如何用线性插值填充缺失的字段值?

How to fill missing field values with linear interpolation?

我有一组代表特定日期值的文档。

其中一些日期没有值(该字段可能缺失或设置为 null)。

我想通过对按日期排序的最接近的之前和之后的文档进行线性插值来填充那些缺失的或未定义的值。

这样:

{ date: ISODate("2021-03-07"), value: 10 }
{ date: ISODate("2021-03-08") }
{ date: ISODate("2021-03-09"), value: 15 }
{ date: ISODate("2021-03-10"), value: null }
{ date: ISODate("2021-03-11") }
{ date: ISODate("2021-03-12"), value: 3 }

变成:

{ date: ISODate("2021-03-07"), value: 10   }
{ date: ISODate("2021-03-08"), value: 12.5 } <=
{ date: ISODate("2021-03-09"), value: 15   }
{ date: ISODate("2021-03-10"), value: 11   } <=
{ date: ISODate("2021-03-11"), value: 7    } <=
{ date: ISODate("2021-03-12"), value: 3    }

Mongo 5.3 开始,这是新 $fill 聚合运算符的一个很好的用例:

// { date: ISODate("2021-03-07"), value: 10 }
// { date: ISODate("2021-03-08") }
// { date: ISODate("2021-03-09"), value: 15 }
// { date: ISODate("2021-03-10"), value: null }
// { date: ISODate("2021-03-11") }
// { date: ISODate("2021-03-12"), value: 3 }
db.aggregate(
  { $fill: {
      sortBy: { date: 1 },
      output: { value: { method: "linear" } }
  }}
)
// { date: ISODate("2021-03-07"), value: 10   }
// { date: ISODate("2021-03-08"), value: 12.5 } <=
// { date: ISODate("2021-03-09"), value: 15   }
// { date: ISODate("2021-03-10"), value: 11   } <=
// { date: ISODate("2021-03-11"), value: 7    } <=
// { date: ISODate("2021-03-12"), value: 3    }

文档按 date (sortBy: { date: 1 }) 的时间顺序排列,因此缺少的 value 将使用 linear 插值 (value: { method: "linear" }) 填充之前和之后的值。


请注意,这实际上是基于所选 sortBy 字段的线性插值,这样如果您缺少日期,您将正确获得:

// { date: ISODate("2021-03-07"), value: 10 }
// { date: ISODate("2021-03-08") }
// { date: ISODate("2021-03-09"), value: 15 }
// { date: ISODate("2021-03-10"), value: null }
// { date: ISODate("2021-03-11") }
// => date gap <=
// { date: ISODate("2021-03-13"), value: 3 }
db.aggregate(
  { $fill: {
      sortBy: { date: 1 },
      output: { value: { method: "linear" } }
  }}
)
// { date: ISODate("2021-03-07"), value: 10   }
// { date: ISODate("2021-03-08"), value: 12.5 } <=
// { date: ISODate("2021-03-09"), value: 15   }
// { date: ISODate("2021-03-10"), value: 12   } <=
// { date: ISODate("2021-03-11"), value: 9    } <=
// => date gap <=
// { date: ISODate("2021-03-12"), value: 3    }

另请注意,如果您有上面提到的间隙并且还想插入文档来代替这些间隙,您可以使用 $densify 阶段来获得最终的缺失数据填充!:

// { date: ISODate("2021-03-07"), value: 10 }
// { date: ISODate("2021-03-08") }
// { date: ISODate("2021-03-09"), value: 15 }
// { date: ISODate("2021-03-10"), value: null }
// { date: ISODate("2021-03-11") }
// => date gap <=
// { date: ISODate("2021-03-13"), value: 3 }
db.aggregate(
  { $densify: {
      field: "date",
      range: { step: 1, unit: "day", bounds: "full" }
  }},
  { $fill: {
      sortBy: { date: 1 },
      output: { value: { method: "linear" } }
  }}
)
// { date: ISODate("2021-03-07"), value: 10   }
// { date: ISODate("2021-03-08"), value: 12.5 } <=
// { date: ISODate("2021-03-09"), value: 15   }
// { date: ISODate("2021-03-10"), value: 12   } <=
// { date: ISODate("2021-03-11"), value: 9    } <=
// { date: ISODate("2021-03-12"), value: 6    } <= <=
// { date: ISODate("2021-03-12"), value: 3    }