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

Posted

技术标签:

【中文标题】用滚动平均值或其他插值替换 NaN 或缺失值【英文标题】:Replace NaN or missing values with rolling mean or other interpolation 【发布时间】:2014-10-03 18:43:16 【问题描述】:

我有一个 Pandas 数据框,其中包含我想要计算 12 个月移动平均值的月度数据。但是(NaN)缺少一月份每个月的数据,所以我正在使用

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

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

有没有一种简单的方法可以忽略 NaN 值?我知道在实践中这将成为 11 个月的移动平均线。

数据框还有其他具有 1 月数据的变量,所以我不想只扔掉 1 月的列并做一个 11 个月的移动平均线。

【问题讨论】:

我相信添加 min_periods=11 解决了我的问题。 【参考方案1】:

有几种方法可以解决这个问题,最好的方法取决于 1 月份的数据是否与其他月份存在系统性差异。大多数现实世界的数据可能都有一定的季节性,所以让我们以北半球一个随机城市的平均高温(华氏度)为例。

df=pd.DataFrame( 'month' : [10,11,12,1,2,3],
                  'temp'  : [65,50,45,np.nan,40,43] ).set_index('month')

您可以按照您的建议使用滚动平均值,但问题是您将获得全年的平均温度,这忽略了 1 月是最冷月份这一事实。要纠正这一点,您可以将窗口减小到 3,这会导致 1 月温度是 12 月和 2 月温度的平均值。 (我也在使用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() 方法 (see documentation here)。

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() 默认为简单的线性解释,但您也有其他几个插值选项。有关更多信息,请参阅documentation on pandas interpolate。或者这个 statck 溢出问题: Interpolation on DataFrame in pandas

这是包含所有结果的示例数据:

       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”在所有月份都给出相同的结果。虽然在这里使用哪一种并不重要,但在其他情况下,一种或另一种可能会更好。

【讨论】:

【参考方案2】:

真正的关键是拥有min_periods=1。此外,从版本 18 开始,正确的调用是使用 Rolling object。因此,您的代码应该是

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

【讨论】:

我遇到了类似的问题,min_periods=1 为我解决了这个问题。 +1 建议滚动对象 @user394430 -- 仅供参考,我大大改进了我的答案,包括您对 min_periods 的使用以及比较不同的执行方式。在我的回答中,标有“rollmean12”的列应该与您的答案相对应。

以上是关于用滚动平均值或其他插值替换 NaN 或缺失值的主要内容,如果未能解决你的问题,请参考以下文章

pandas dataframe缺失值(np.nan)处理:识别缺失情况删除0值填补均值填补中位数填补加缺失标签插值填充详解及实例

Sklearn 或 Pandas,用简单的线性回归估算缺失值

数据分析缺失值处理(Missing Values)——删除法填充法插值法

Pandas:用前一个和下一个非缺失值的平均值动态替换 NaN 值

pandas groupby 滚动均值/中值删除缺失值

Python:替换数组中的 NaN 或 MEAN 而不是 -999 值[重复]