如何计算Google表格中的加权平均值?


36

我有一个Google表格,其中产品列为行,属性列为列。每个产品的属性等级为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
)

如您所见,随着添加更多属性,这变得非常难以管理。理想情况下,我正在寻找不需要创建临时单元来帮助进行计算的解决方案。

是否有任何内置函数或通用约定可以帮助我计算这些加权平均值?

Answers:


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我更新了我的答案,dollar sign in excel由于您会找到更多有关此文档的信息,因此您通常可以使用Google 。
Lipis 2010年

1
您的功能不起作用。但这对我有用
Totty.js

1
此页面上还有另一个评分更高的答案,该答案可以使用并使用内置功能sumproduct
布拉德·帕克斯

58

例如,如果权重在从B到L的第2行中,并且想要平均的数据在第3行或更高行中,则可以使用sumproduct,如下所示:

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

7
+1这个答案很简单,有效,并且比公认的答案好得多。
2013年


2

Lipis的代码不适用于我,因此这里有一个更新。这段代码:

  • 与当前版本的Google Spreadsheets一起正确处理数组元素

  • 检查值是否为数字

  • 可以选择是否考虑零值

码:

/**
  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 Spreadsheets:

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表格中测试了您的代码,#NUM!结果无法正常工作。Lipis制作的代码仍然有效。您只是忽略了要返回的2D数组。
Jacob Jan Tuinstra 2014年

0

ARRAYFORMULA()可以计算Google Spreadsheets(甚至更多)中的加权平均值

将权重分别存储在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))

注意:正则表达式要求属性名称不带数字。因此,请使用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 Spreadsheets中的加权平均值?


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 Spreadsheets中的加权平均值?


0

对于简单的加权平均值,您可以多次添加像元值。例如,如果您希望A1为75%,B1为25%,则可以输入=AVERAGE (A1,A1,A1,B1)。因此,特别适合您的是=AVERAGE (B2,C2,C2,D1,D2,D2,D2,D2,D2,D2),它将B2的重量占C2的一半(50%),而D2的重量称为C2的3倍(300%)。

更复杂的东西高于我的薪水等级。:)


0

实际上,两个版本的Average.weighted和sumproduct给出相同的结果:

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

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

所以我宁愿使用第一个,因为它处理起来更简单,但是我不知道如何在此公式中增加其他权重。

这是工具提示,但不知道如何仅添加权重而不添加其他值

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

这有点含糊。您是要提出一个新问题还是这是一个答案?
jonsca

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.