【问题标题】:Pandas: Impute a given number of missing values before/after a series of available valuesPandas:在一系列可用值之前/之后估算给定数量的缺失值
【发布时间】:2021-04-05 21:25:20
【问题描述】:

假设我有一个时间序列,其中我通常有某个连续年份的可用数据,但在该跨度之前和之后缺少值,如下所示:

df = pd.DataFrame({'year': ["2000","2001","2002", "2003","2004", "2005","2006", "2007"], 'cakes eaten': [np.nan, np.nan, np.nan, 3, 4, 5, np.nan, np.nan]})
print(df)

   year  cakes eaten
0  2000          NaN
1  2001          NaN
2  2002          NaN
3  2003          3.0
4  2004          4.0
5  2005          5.0
6  2006          NaN
7  2007          NaN

有没有办法根据可用值中看到​​的趋势来填充(给定数量的)缺失值?

假设我想在每个方向上最多填充 2 个值,结果应该是这样的:

   year  cakes eaten
0  2000          NaN
1  2001          1.0
2  2002          2.0
3  2003          3.0
4  2004          4.0
5  2005          5.0
6  2006          6.0
7  2007          7.0

另外: 有没有办法确保只有在有足够的可用值时才执行此插补,例如,如果有,我只想在每个方向上最多填充 2 个值至少有 3 个值可用(或者更笼统地说,只有当 n + m 可用时才填写 n)?

【问题讨论】:

  • 您将如何识别可用值中的趋势?

标签: python pandas imputation


【解决方案1】:

我会使用上面提到的 interpolate()。您可以使用多种方法来产生不同的结果。我使用krogh 方法得到一条线性趋势线。需要limit_direction='both' 来填充两个方向的趋势:

test_dict  = {'col': [np.nan, np.nan,np.nan, np.nan, np.nan, 4, 5, 6 ,np.nan]}
df = pd.DataFrame(test_dict)
df['trend'] = df['col'].interpolate(method='krogh', limit_direction='both')

    col trend
0   NaN -1.0
1   NaN 0.0
2   NaN 1.0
3   NaN 2.0
4   NaN 3.0
5   4.0 4.0
6   5.0 5.0
7   6.0 6.0
8   NaN 7.0

完成后,您可以删除不需要的below 0 趋势值。

【讨论】:

  • 感谢您重新指向 interpolate 函数,它似乎确实能够做我想做的事。 Krogh 在我上面发布的示例中运行良好,但如果趋势不是完全线性的,则会产生一些非常奇怪的值。但是,我发现带有order = 2spline 方法效果更好
【解决方案2】:

感谢@olv1do 让我知道interpolate() 做了我想做的事。

使用 interpolate 和 .first_valid_index.last_valid_index 可以实现所需的行为:

#impute n values in both directions if at least m values are available
def interpolate(data, n, m):
  first_valid = data['cakes eaten'].first_valid_index()
  last_valid = data['cakes eaten'].last_valid_index()

  if(abs(first_valid - last_valid) + 1 >= m):
    data['imputed'] = data['cakes eaten'].interpolate(method='spline',order = 1, limit_direction='both', limit = n)
  return data

对于问题中的示例:

df = pd.DataFrame({'year': ["2000","2001","2002", "2003","2004", "2005","2006", "2007"], 'cakes eaten': [np.nan, np.nan, np.nan, 3, 4, 5, np.nan, np.nan]})
interpolate(df, 2,3)

year    cakes eaten     imputed
0   2000    NaN     NaN
1   2001    NaN     1.0
2   2002    NaN     2.0
3   2003    3.0     3.0
4   2004    4.0     4.0
5   2005    5.0     5.0
6   2006    NaN     6.0
7   2007    NaN     7.0

如果可用的值少于 m,则不执行任何操作:

df = pd.DataFrame({'year': ["2000","2001","2002", "2003","2004", "2005","2006", "2007"], 'cakes eaten': [np.nan, np.nan, np.nan, 3, 4,  np.nan, np.nan, np.nan]})
interpolate(df, 2,3)

    year    cakes eaten
0   2000    NaN
1   2001    NaN
2   2002    NaN
3   2003    3.0
4   2004    4.0
5   2005    NaN
6   2006    NaN
7   2007    NaN

此外,如果值不像我的示例中那样完全线性,spline 方法也可以很好地工作:

df = pd.DataFrame({'year': ["2000","2001","2002", "2003","2004", "2005","2006", "2007"], 'cakes eaten': [np.nan, np.nan, 1, 4, 2,  3, np.nan, np.nan]})
interpolate(df, 1,4)

    year    cakes eaten     imputed
0   2000    NaN     NaN
1   2001    NaN     1.381040
2   2002    1.0     1.000000
3   2003    4.0     4.000000
4   2004    2.0     2.000000
5   2005    3.0     3.000000
6   2006    NaN     3.433167
7   2007    NaN     NaN

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-22
    相关资源
    最近更新 更多