Как рассчитать средневзвешенные значения в Google Sheets?


36

У меня есть Google Sheets, где продукты перечислены в виде строк, а атрибуты - в виде столбцов. Атрибут каждого продукта оценивается по шкале от 1 до 10. Мой последний столбец является средним из этих значений (то есть =Average(B2:D2)). Это прекрасно работает, если каждый атрибут имеет одинаковый вес.

+--------+-------+-------+-------+---------+
|        | Attr1 | Attr2 | Attr3 | Overall |
+--------+-------+-------+-------+---------+
| Prod 1 | 10    | 8     | 9     | 9       |
| Prod 2 | 2     | 10    | 7     | 6.33    |
| Prod 3 | 4     | 6     | 6     | 5.33    |
+--------+-------+-------+-------+---------+

Проблема в том, что я хочу, чтобы каждый атрибут имел разный вес. Например, Attr1 может не иметь значения и должен стоить только 50%, в то время как Attr3 очень важен и должен стоить 300%.

+--------+-------------+-------+--------------+---------+
|        | Attr1 (50%) | Attr2 | Attr3 (300%) | Overall |
+--------+-------------+-------+--------------+---------+
| Prod 1 | 10          | 8     | 9            | 8.89    |
| Prod 2 | 2           | 10    | 7            | 7.11    |
| Prod 3 | 4           | 6     | 6            | 5.78    |
+--------+-------------+-------+--------------+---------+

Значение для первой строки будет:

(10*0.5 + 8*1 + 9*3) / (0.5+1+3) = 8.89

который можно рассчитать с помощью:

(
  B2*(IFERROR(REGEXEXTRACT(B1, "\d+"), 100)/100) 
  + C2*(IFERROR(REGEXEXTRACT(C1, "\d+"), 100)/100)
  + D2*(IFERROR(REGEXEXTRACT(D1, "\d+"), 100)/100) 
) / (
  IFERROR(REGEXEXTRACT(B1, "\d+"), 100)/100
  + IFERROR(REGEXEXTRACT(C1, "\d+"), 100)/100
  + IFERROR(REGEXEXTRACT(D1, "\d+"), 100)/100
)

которым, как вы можете видеть, может стать очень сложно управлять по мере добавления новых атрибутов. В идеале я ищу решение, которое не требует создания временных ячеек, чтобы помочь с расчетами.

Существует ли какая-либо встроенная функция или общее соглашение, которое может помочь мне рассчитать эти средневзвешенные значения?

Ответы:


8

Нет встроенной функции для вычисления средневзвешенного значения, поэтому вам нужно написать пользовательскую функцию, если вы хотите избежать использования слишком большого количества временных ячеек. Итак, вот как вы можете достичь своей цели.

Перейдите в Инструменты > Сценарии > Редактор сценариев ... , Скопируйте / Вставьте приведенный ниже код и сохраните его:

function weightedAverage(v, w) {
  var sum_v = 0;
  var sum_w = 0;

  if (v[0].length != w[0].length) {
    return "#ERROR: Incorrect number of values and weights";  
  }

  for (var c = 0; c < v[0].length; ++c) {
    sum_v += v[0][c] * w[0][c]; 
    sum_w += w[0][c]; 
  }

  return sum_v/sum_w;
}​

Используйте это как:

=weightedAverage(B3:D3,$B$2:$D$2) 

Где B3:D3ваши ценности и $B$2:$D$2вес? Это не доказательство ошибок (единственная проверка - убедиться, что оба массива имеют одинаковую длину), но это поможет.

В приведенном выше примере я не пытаюсь извлечь веса из заголовка атрибута, но я читаю их из второй строки ( B2:D2), чтобы сделать нашу жизнь проще и понятнее. Это $не меняет результат формулы. Это влияет только на то, что происходит, когда вы копируете формулу в другую ячейку. Часть ссылки на ячейку, следующая за $, не изменится ( ссылка для более подробной информации). Запишите формулу один раз в ячейку E3и скопируйте ее в остальные строки, чтобы увидеть ее в действии.


Что $означают знаки?
Чувствительный

@Senseful Я обновил свой ответ, и вы можете Google в целом, потому что dollar sign in excelэто то же самое, так как вы найдете больше документации для него.
Липис

1
Ваша функция не работает. Но это работает для меня: gist.github.com/totty90/b58f47dbc430a53d2e5b
Totty.js

1
На этой странице есть еще один ответ с более высоким рейтингом, который работает и использует встроенную функциюsumproduct
Брэд Паркс

58

Если ваши веса находятся в строке 2 от B до L, а данные, которые вы хотите усреднить, находятся в строках 3 и выше, скажем, тогда вы можете использовать sumproduct следующим образом:

=sumproduct(B$2:L$2, C3:L3)/sum(B$2:L$2)

7
+1 этот ответ прост, работает и намного лучше принятого.
Afr


2

Код Липиса у меня не работал, так что вот обновление. Этот код:

  • работает с текущей версией таблиц Google, правильно обращаясь к элементам массива

  • проверяет, являются ли значения числами

  • имеет переключатель, чтобы рассмотреть нулевые значения или нет

Код:

/**
  v - Values range
  w - Weights range
  z - count zero values?
*/

function weightedAverage(v, w, z) {
  var sum_v = 0;
  var sum_w = 0;

  if (v.length != w.length) {
    return "#ERROR: Incorrect number of values and weights";  
  }

  for (var c = 0; c < v.length; ++c) {
    if (!z && Number(v[c][0])!=0) {
      sum_v += Number(v[c][0]) * Number(w[c][0]); 
      sum_w += Number(w[c][0]); 
    }
  }

  return sum_v/sum_w;
}

0

Исправление кода Lipis для работы с текущей версией таблиц Google:

function weightedAverage(v, w) {
  var sum_v = 0;
  var sum_w = 0;

  if (v.length != w.length) {
    return "#ERROR: Incorrect number of values and weights";  
  }

  for (var c = 0; c < v.length; ++c) {
    sum_v += v[c] * w[c]; 
    sum_w += w[c] * 1; 
  }

  return sum_v/sum_w;
}​

-1; Я проверил ваш код в новых Google Sheets, и он не работал, он дал #NUM!в результате. Код, созданный Lipis, все еще работает. Вы игнорируете только 2d-массив, который возвращается.
Джейкоб Ян Туинстра

0

ARRAYFORMULA () может вычислить средневзвешенное значение в таблицах Google (и не только).

Хранение весов отдельно в B2: D2 упрощает чтение формулы. Вычисление средневзвешенного значения для E3 выглядит аналогично SUMPRODUCT () выше (копирование / вставка для E4 и E5):

=ARRAYFORMULA(sum(B3:D3 * $B$2:$D$2)/sum($B$2:$D$2))

+--------+-------------+-------+-------------+---------+
|        | AttrA (50%) | AttrB | AttrC (300%)| Overall |
| Weight:|        50%  |  100% |        300% |         |
+--------+-------------+-------+-------------+---------+
| Prod 1 |       10    |  8    |       9     | 8.8889  |
| Prod 2 |        2    | 10    |       7     | 7.1111  |
| Prod 3 |        4    |  6    |       6     | 5.7778  |
+--------+-------------+-------+-------------+---------+

Использование RegExExtract () для получения весов от $ B $ 1: $ D $ 1 - это простое изменение в ARRAYFORMULA (). Замените простой диапазон более сложным выражением " iferror(regexextract($B$1:$D$1,"\d+"),100)/100", и формула для E3 становится (копировать / вставить для E4 и E5):

=ARRAYFORMULA(sum(B3:D3 * iferror(regexextract($B$1:$D$1,"\d+"),100)/100)/sum(iferror(regexextract($B$1:$D$1,"\d+"),100)/100))

NB. Это регулярное выражение требует имен атрибутов без номеров; поэтому используйте AttrA, AttrB и AttrC вместо Attr1, Attr2 & Attr3.


0

Внимательно прочитав ваш вопрос,

В идеале я ищу решение, которое не требует создания временных ячеек, чтобы помочь с расчетами.

Я придумал это решение, которое не использует временных ячеек.

формула

weights = ARRAYFORMULA(IFERROR(VALUE(REGEXEXTRACT($B$1:$D$1,"\((\d+)")),100))

=SUMPRODUCT(B3:D3, weights) / SUM(weights)

copy / paste
=SUMPRODUCT(B2:D2, ARRAYFORMULA(IFERROR(VALUE(REGEXEXTRACT($B$1:$D$1,"\((\d+)")),100)))/SUM(ARRAYFORMULA(IFERROR(VALUE(REGEXEXTRACT($B$1:$D$1,"\((\d+)")),100)))

Скриншот

введите описание изображения здесь

Разъяснения

REGEXEXTRACTИзвлечет значение в заголовке после первой прямой скобки и VALUEпреобразует его в число. Значение IFERRORбудет установлено равным, 100если ничего не найдено, и ARRAYFORMULAпозволит выбрать диапазон, а не отдельные ячейки.

пример

Я создал для вас файл примера: Как рассчитать средневзвешенные значения в таблицах Google?


0

Поскольку принятый ответ использует скрипт Google Apps, я также создал небольшой фрагмент кода.

Код

function weightedAverage(v, w) {
  var weights = [], sumWeights = 0;
  for(var k = 0, kLen = w[0].length; k < kLen; k++) {
    var m = w[0][k].match(/\((\d+)/), value;
    if(!m) {
      value = 100;
    } else {
      value = Number(m[1]);
    }
    weights.push(value);
    sumWeights += value;
  }

  var output = [];
  for(var i = 0, iLen = v.length; i < iLen; i++) {
    var sumProduct = 0;
    for(var j = 0, jLen = v[0].length; j < jLen; j++) {
      sumProduct += v[i][j] * weights[j]; 
    }
    output.push(sumProduct / sumWeights);
  } 
  return output;
}

Скриншот

введите описание изображения здесь

Заметка

Сценарий будет следовать той же логике, что и в этом посте. Основным преимуществом является то, что он будет рассчитывать общие значения сразу.

пример

Я создал для вас файл примера: Как рассчитать средневзвешенные значения в таблицах Google?


0

Для простых средневзвешенных значений вы можете просто добавить значение ячейки несколько раз. Например, если вы хотите, чтобы А1 составлял 75%, а В1 - 25%, вы можете вставить =AVERAGE (A1,A1,A1,B1). Так что специально для вас это будет =AVERAGE (B2,C2,C2,D1,D2,D2,D2,D2,D2,D2), который будет весить В2 как половину от С2 (50%) и D2 как 3х С2 (300%).

Более сложные вещи выше моей зарплаты. :)


0

На самом деле обе версии Average.weighted и sumproduct дают одинаковый результат:

AVERAGE.WEIGHTED("Values","Weight")

SUMPRODUCT("Numbers","Weight")/sum("Weight")

Поэтому я предпочитаю использовать первый, так как с ним гораздо проще справиться, однако я не знаю, как добавить другие веса к этой формуле.

Это подсказка, но не знаю, как добавить только веса, а не дополнительные значения

AVERAGE.WEIGHTED(values, weights, [additional_values, ...], [additional_weights, ...])

Это немного расплывчато. Вы пытаетесь задать новый вопрос или это ответ?
Йонска

-2

Существует довольно простой способ использования только данных функций.

=(sumproduct(E5:E9;G5:G9)/sum(E5:E9))   

где E content - количество баллов, а G - важность этих баллов.



@JacobJanTuinstra Почему этот ответ появляется первым, если его рейтинг намного ниже, чем тот, на который вы ссылаетесь? webapps stackexchange работает загадочным образом ...
e18r
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.