【问题标题】:Fill in NaN in Pandas Dataframe using trend of previous valid values使用先前有效值的趋势在 Pandas Dataframe 中填写 NaN
【发布时间】:2021-01-01 23:57:13
【问题描述】:

我试图通过分组来填补数据中的空白,然后使用之前数据点的趋势来预测缺失值是什么。

df

Group  Week  Value
B      1     5
B      2     6
B      3     NaN
B      4     NaN
B      5     NaN
B      6     8
B      7     8
B      8     7
B      9     6
B      10    NaN

图形如下所示: Initial df plot

一旦所需功能发生,数据框将如下所示:

Group  Week  Value
B      1     5
B      2     6
B      3     7
B      4     8
B      5     9
B      6     8
B      7     8
B      8     7
B      9     6
B      10    5.5

找到这些 NaN 值的先前点的趋势在此处以图形方式显示: NaN values calculated

这个例子中的前三个 NaN 值是通过简单地绘制值 5 和 6 找到的,找到线性方程 (y = mx + c) 并将 x 作为周来计算 y。对所有 NaN 值都将执行相同的过程

我尝试过插值 (df = df.groupby('Group').apply(lambda group: group.interpolate(method='index')) 但这显然会查看下一个有效数据点并将其包含在计算中,我试图避免这种情况

可能值得注意的是,我使用的数据框有 200,000 行和 4,000 个组!

【问题讨论】:

  • @lrobertd 你为什么不根据你的要求对数据点进行分组。
  • 欢迎来到 StackOverflow!如果我已经解决了您的问题,请确保通过单击我的答案旁边的复选标记接受作为解决方案。谢谢!请参阅以下链接以获取有关如何执行此操作的帮助:meta.stackexchange.com/questions/5234/…
  • 错误是什么?始终在评论中包含错误消息或添加到您的问题并在评论中引用它。谢谢!
  • @DavidErickson spline 出错,因为某些组仅包含 1 个值 - 我知道 spline 无法对其进行操作。有没有我可以按照以下 sudo 代码实现的东西: if group size = 1 then 'linear' else 'spline'
  • 嗨@lrobertd 查看我的更新答案。请通过单击答案旁边的复选标记来接受解决原始问题的解决方案。如果您需要更多帮助并参考 ois 问题,您可以随时打开一个新的 StackOverflow 问题。

标签: python pandas dataframe interpolation extrapolation


【解决方案1】:

您可以创建子组系列g 并将method="spline" 和order=1 传递给interpolate:

g = df['Value'].mask(df['Value'].notnull(), df['Value'].isnull().cumsum()).ffill()
df['Value'] = (df.groupby(['Group', g])['Value']
                 .apply(lambda x: x.interpolate(method="spline", order=1)))
df
Out[1]: 
  Group  Week  Value
0     B     1    5.0
1     B     2    6.0
2     B     3    7.0
3     B     4    8.0
4     B     5    9.0
5     B     6    8.0
6     B     7    8.0
7     B     8    7.0
8     B     9    6.0
9     B    10    5.5

获取g 的中间步骤如下所示。

g = df['Value'].mask(df['Value'].notnull(), df['Value'].isnull().cumsum()).ffill()
g
Out[1]: 
0    0.0
1    0.0
2    0.0
3    0.0
4    0.0
5    3.0
6    3.0
7    3.0
8    3.0
9    3.0

这些数字基本上只是创建子组。我的方法是实现这一目标的一种方法。


根据您的评论,我创建了一个 mask m 来计算大小为 1 的组。然后,我使用 fillna() 组合单独的方法:

df = pd.DataFrame({'Group': {0: 'A',
  1: 'B',
  2: 'B',
  3: 'B',
  4: 'B',
  5: 'B',
  6: 'B',
  7: 'B',
  8: 'B',
  9: 'B'},
 'Week': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10},
 'Value': {0: 5.0,
  1: 6.0,
  2: np.nan,
  3: np.nan,
  4: np.nan,
  5: 8.0,
  6: 8.0,
  7: 7.0,
  8: 6.0,
  9: np.nan}})
g = df['Value'].iloc[1:].mask(df['Value'].notnull(), df['Value'].isnull().cumsum()).ffill()
m = df.groupby(['Group', g])['Value'].transform('count') > 1
v1 = (df[m].groupby(['Group', g])['Value']
                     .apply(lambda x: x.interpolate(method="spline", order=1)))
v2 = (df.groupby(['Group', g])['Value']
                     .apply(lambda x: x.interpolate(method="index")))
df['Value'] = df['Value'].fillna(v1).fillna(v2)
df

【讨论】:

  • 这很有帮助-谢谢一个问题-为什么在这里使用'spline'方法而不是'index'? x.interpolate(method="spline", order=1) 我必须使用 'index' 否则代码会抛出错误。
  • 这很有帮助 - 谢谢 一个问题 - 我无法使用“样条”方法 - 我必须使用“索引”,否则代码会出错。 @daviderickson
猜你喜欢
  • 1970-01-01
  • 2020-10-19
  • 2015-02-14
  • 2014-07-22
  • 1970-01-01
  • 2018-12-05
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
相关资源
最近更新 更多