【问题标题】:Fill missing data by interpolation in Google Spreadsheet在 Google 电子表格中通过插值填充缺失的数据
【发布时间】:2015-12-08 07:31:26
【问题描述】:

我有包含以下数据的 Google 电子表格

   A           B       D
1  Date        Weight  Computation
2  2015/12/09          =B2*2
3  2015/12/10  65      =B3*2
4  2015/12/11          =B4*2
5  2015/12/12          =B5*2
6  2015/12/14  62      =B6*2
7  2015/12/15          =B7*2
8  2015/12/16  61      =B8*2
9  2015/12/17          =B9*2

我想绘制重量 w.r.t.日期,和/或将其与计算重量的其他数量的其他列一起使用。但是,您会注意到缺少一些条目。我想要的是另一列,该列的数据基于权重列,其中插入并填充了缺失值。例如:

   A           B       C       D
1  Date        Weight  WeightI Computation
2  2015/12/09          65      =C2*2          # use first known value
3  2015/12/10  65      65      =C3*2
4  2015/12/11          64      =C4*2          # =(62-65)/3*(1)+65
5  2015/12/12          63      =C5*2          # =(62-65)/3*(2)+65
6  2015/12/14  62      62      =C6*2
7  2015/12/15          61.5    =C7*2          # =(61-62)/2*(1)+62
8  2015/12/16  61      61      =C8*2
9  2015/12/17          61      =C9*2          # use the last known value

当我必须在两个已知点之间查找缺失数据时,C 列中的值是使用线性插值填充的。

我相信这是一个非常简单且常见的用例,所以我确信这是一件微不足道的事情,但我无法找到使用内置函数的解决方案。我对电子表格也没有太多经验。我花了几个小时试验 =INDEX、=MATCH、=VLOOKUP、=LINEST、=TREND 等,但我无法从示例中得出一些结论。我可以使用的唯一解决方案是使用 Google Apps 脚本创建自定义函数。虽然我的解决方案有效,但它似乎执行得非常缓慢。我的电子表格也很大。

任何指针,解决方案?

【问题讨论】:

  • 您最好采用为自定义函数编写的代码,并将其修改为从onEdit() 触发器或类似的东西运行。每次发生更改时,函数可能都会重新计算整个电子表格。 onEdit() 触发器可以运行脚本,该脚本只会更改脚本中指定的单元格中的值。您可能想查看Link to Google Sheets Events 文档。

标签: google-sheets


【解决方案1】:

您可能想要使用forecast,首先将您有读数的日期与没有读数的日期分开(稍后重新排列)可能更方便。因此,只需三个读数即可:

       A        B
1 10/12/2015    65
2 14/12/2015    62
3 16/12/2015    61

以及需要值的日期在左下方:

 6 09/12/2015   65.6
 7 11/12/2015   64.3
 8 12/12/2015   63.6
 9 15/12/2015   61.5
10 17/12/2015   60.2

在 B6 中产生65.6 的公式(并从那里复制到适合)是:

=forecast(A6,$B$1:$B$3,$A$1:$A$3)  

这与您显示的方式不同,但可能被认为稍微更准确,特别是通过推断缺失的最终值,而不是仅仅重复它们最接近的可用值。

计算完值后,您可能希望按日期顺序重新组合数据。所以我建议复制 B6:B10 和编辑,粘贴特殊,粘贴 values 只在顶部,然后排序以适应。

下面的图表将上面的结果(蓝色)与您的 OP(绿色)中的结果进行了比较,并标记了给定的数据点:

【讨论】:

  • 我可以看到forcast() 的值,但是,在我的实验中,我发现它在整个数据范围内插入为一条直线。所以它不会追踪数据已经可用的点。理想情况下,如果我可以使用样条拟合而不是直线插值,我会很高兴。
【解决方案2】:

使用以下方法找到了满足我大部分要求的解决方案:

  1. 使用=FILTER() 首先删除数据不可用的空白行(感谢“pnuts”的提示)。

  2. =MATCH() 从过滤表中查找两个连续的行。在我的情况下,我能够使用此功能,因为列 A 已排序并且没有重复。

  3. 然后用线公式插值。

所以输出变成:

   A            B       C           D       E
 1 Date         Weight  FDdate      FWeight IWeight
 2 2015/05/09           2015/05/10  65.00   #N/A
 3 2015/05/10   65.00   2015/05/13  62.00   65.00
 4 2015/05/11           2015/05/15  61.00   64.00
 5 2015/05/12                               63.00
 6 2015/05/13   62.00                       62.00
 7 2015/05/14                               61.50
 8 2015/05/15   61.00                       61.00
 9 2015/05/16                               61.00
10 2015/05/17                               61.00

单元格C2D2 具有以下范围公式(小提示:如果列AB 相邻,则当然可以组合以下公式):

C2 =FILTER($A$2:$A$10, NOT(ISBLANK($B$2:$B$10)))
D2 =FILTER($B$2:$B$10, NOT(ISBLANK($B$2:$B$10)))

单元格E2E10 包含以下行插值公式:[y = y1 + (y2 - y1) / (x2 - x1) * (x - x1)]:

E2 =(INDEX($D:$D, MATCH($A2, $C:$C, 1),     1))
   +(INDEX($D:$D, MATCH($A2, $C:$C, 1) + 1, 1)
   - INDEX($D:$D, MATCH($A2, $C:$C, 1),     1))
   /(INDEX($C:$C, MATCH($A2, $C:$C, 1) + 1, 1)
   - INDEX($C:$C, MATCH($A2, $C:$C, 1),     1))
   *(INDEX($C:$C, MATCH($A2, $C:$C, 1),     1) - $A2) * -1

此解决方案不适用于当第一个单元格 B2 没有值时,公式会导致 #N/A。如果我们在 google 电子表格中有 =INTERPOLATE_LINE( A2, $A$2:$A$10, $B$2:$B$10 ) 之类的东西,所有这一切都会更有效率,但不幸的是,这不存在。如果我在阅读谷歌电子表格中的supported functions 时遗漏了它,请纠正我。

【讨论】:

    【解决方案3】:

    我找到了一个完全满足要求的解决方案。我使用了一张单独的表格,这样我就可以将计算分成几部分。

    创建一个新工作表。在单元格 A2-F2 中输入以下公式,然后将它们复制到页面下方。

    1. 单元格 A2: 将您的体重数据复制到第一列。 (在本例中,工作表名称为 Daily Record,重量记录在 D 列中。)

      'Daily Record'!D2

    2. 单元格 B2: 查找最近记录的体重。

      =INDEX(FILTER(A$2:A2,A$2:A2 <> ""),COUNT(FILTER(A$2:A2,A$2:A2 <> "")),1)

    3. 单元格 C2:计算自最近一次称重以来的天数。

      =IF(A2<>"",0,IF(ROW(C2)<3,0,C1+1))

    4. 单元格 D2: 查找下一个记录的重量(从当前日期或以后)。

      =IFERROR(INDEX(FILTER(A2:A,A2:A <> ""),1,1),"")

    5. 单元格 E2: 计算距离下一次称重的天数。

      =IF(A2<>"",0,IF(E3="","",E3+1))

    6. 单元格 F2: 计算插值权重。

      =IF(A2 <> "", A2, IF(D2 = "", "", B2 + (D2-B2)*C2/(C2+E2)))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-20
      • 2018-12-17
      • 2020-02-06
      相关资源
      最近更新 更多