用滚动平均或其他插值方法替换NaN或缺失值

19

我有一个带有每月数据的pandas数据框,我想计算12个月的移动平均值。然而,每年1月份的数据都缺失(NaN),因此我正在使用

pd.rolling_mean(data["variable"]), 12, center=True)

但是它只给了我所有的NaN值。

有没有简单的方法可以忽略NaN值?我知道实际上这将变成一个11个月的移动平均。

数据框中有其他具有1月数据的变量,因此我不想仅丢弃1月列并进行11个月的移动平均。


我相信添加 min_periods=11 解决了我的问题。 - Alexis Eggermont
2个回答

28

有几种方法可以处理这个问题,最好的方法取决于1月份的数据是否与其他月份有系统性的不同。大多数真实世界中的数据很可能具有某种季节性,因此让我们以北半球一个随机城市的平均高温(华氏度)为例。

有几种方法可以处理这个问题,最好的方法取决于1月份的数据是否与其他月份有系统性的不同。大多数真实世界中的数据很可能具有某种季节性,因此让我们以北半球一个随机城市的平均高温(华氏度)为例。
df=pd.DataFrame({ 'month' : [10,11,12,1,2,3],
                  'temp'  : [65,50,45,np.nan,40,43] }).set_index('month')
你可以像你所建议的那样使用滚动平均值,但问题在于你会得到整个年度的平均温度,这忽略了一月份是最冷的事实。为了纠正这个问题,你可以将窗口减小到3,这将导致一月份的温度是十二月和二月温度的平均值。(我还使用了min_periods=1,就像@user394430的回答中建议的一样。)
df['rollmean12'] = df['temp'].rolling(12,center=True,min_periods=1).mean()
df['rollmean3']  = df['temp'].rolling( 3,center=True,min_periods=1).mean()

这些是改进,但仍存在通过滚动平均覆盖现有值的问题。为了避免这种情况,您可以与update()方法结合使用(请参见此处的文档)。

df['update'] = df['rollmean3']
df['update'].update( df['temp'] )  # note: this is an inplace operation

甚至还有更简单的方法,它可以保留现有值,同时将缺失的一月温度填充为上个月、下个月或前后两个月平均值。

df['ffill']   = df['temp'].ffill()         # previous month 
df['bfill']   = df['temp'].bfill()         # next month
df['interp']  = df['temp'].interpolate()   # mean of prev/next
在这种情况下,interpolate() 默认使用简单线性插值,但你还可以选择多种其他的插值选项。请参阅 pandas interpolate 文档 获取更多信息。或者查看这个 stack overflow 问题:在 pandas 中对 DataFrame 进行插值 以下是带有所有结果的示例数据:
       temp  rollmean12  rollmean3  update  ffill  bfill  interp
month                                                           
10     65.0        48.6  57.500000    65.0   65.0   65.0    65.0
11     50.0        48.6  53.333333    50.0   50.0   50.0    50.0
12     45.0        48.6  47.500000    45.0   45.0   45.0    45.0
1       NaN        48.6  42.500000    42.5   45.0   40.0    42.5
2      40.0        48.6  41.500000    40.0   40.0   40.0    40.0
3      43.0        48.6  41.500000    43.0   43.0   43.0    43.0

特别注意,"update"和"interp"在所有月份中都会产生相同的结果。虽然在这里使用哪一个都无所谓,但在其他情况下,一种方法可能比另一种更好。


16

关键在于设置 min_periods=1。从18版本开始,正确的调用方法是使用Rolling对象。 因此,您的代码应该是

data["variable"].rolling(min_periods=1, center=True, window=12).mean()


1
我曾经遇到过类似的问题,而 min_periods=1 是解决问题的关键。感谢你提供了滚动对象的建议。 - MyCarta
@user394430 -- 我的回答有了大幅改进,包括您使用min_periods以及比较不同的方法。在我的答案中,“rollmean12”列应该对应于您的答案。 - JohnE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接