python - 用相邻天的数据平均值填补数据缺口

标签 python pandas time-series

想象一个数据框,其中包含每 30 分钟测量一次的多个变量。此数据框中的每个时间序列在可能不同的位置都有间隙。这些差距将被某种运行平均值所取代,比方说 +/- 2 天。例如,如果在第 4 天 07:30 缺少数据,我想用第 2、3、5 和 6 天 07:30 的测量平均值替换 NaN 条目。 注意也有可能,例如,第 5 天的 07:30 也是 NaN - 在这种情况下,这应该从要替换第 4 天丢失的测量值的平均值中排除(应该可以使用 np.nanmean 吗?)

我不知道该怎么做。现在,我可能会遍历数据框中的每一行和每一列,并按照 np.mean(df.ix[[i-48, i, i+48], "A"]),但我觉得一定有更 pythonic/pandas-y 的方式?

示例数据集:

import numpy as np
import pandas as pd

# generate a 1-week time series
dates = pd.date_range(start="2014-01-01 00:00", end="2014-01-07 00:00", freq="30min")
df = pd.DataFrame(np.random.randn(len(dates),3), index=dates, columns=("A", "B", "C"))

# generate some artificial gaps
df.ix["2014-01-04 10:00":"2014-01-04 11:00", "A"] = np.nan
df.ix["2014-01-04 12:30":"2014-01-04 14:00", "B"] = np.nan
df.ix["2014-01-04 09:30":"2014-01-04 15:00", "C"] = np.nan

print df["2014-01-04 08:00":"2014-01-04 16:00"]

                            A         B         C
2014-01-04 08:00:00  0.675720  2.186484 -0.033969
2014-01-04 08:30:00 -0.897217  1.332437 -2.618197
2014-01-04 09:00:00  0.299395  0.837023  1.346117
2014-01-04 09:30:00  0.223051  0.913047       NaN
2014-01-04 10:00:00       NaN  1.395480       NaN
2014-01-04 10:30:00       NaN -0.800921       NaN
2014-01-04 11:00:00       NaN -0.932760       NaN
2014-01-04 11:30:00  0.057219 -0.071280       NaN
2014-01-04 12:00:00  0.215810 -1.099531       NaN
2014-01-04 12:30:00 -0.532563       NaN       NaN
2014-01-04 13:00:00 -0.697872       NaN       NaN
2014-01-04 13:30:00 -0.028541       NaN       NaN
2014-01-04 14:00:00 -0.073426       NaN       NaN
2014-01-04 14:30:00 -1.187419  0.221636       NaN
2014-01-04 15:00:00  1.802449  0.144715       NaN
2014-01-04 15:30:00  0.446615  1.013915 -1.813272
2014-01-04 16:00:00 -0.410670  1.265309 -0.198607

[17 rows x 3 columns]

(一个更复杂的工具也会从平均过程中排除测量结果,这些测量结果本身是通过平均创建的,但这不一定必须包含在答案中,因为我认为这可能会使事情现在变得太复杂。 )

/edit:一个我不太满意的示例解决方案:

# specify the columns of df where gaps should be filled
cols = ["A", "B", "C"]
for col in cols:
    for idx, rows in df.iterrows():
        if np.isnan(df.ix[idx, col]):
            # replace with mean of adjacent days
            df.ix[idx, col] = np.nanmean(df.ix[[idx-48, idx+48], col]) 

这个解决方案有两点我不喜欢:

  1. 如果任何地方有一行缺失或重复,则失败。在最后一行,我想一直减去“一天”,不管那是 47、48 还是 49 行。另外,如果我可以扩展范围(例如 -3 天到 +3 天),而无需手动编写索引列表,那将是一件好事。
  2. 如果可能的话,我想摆脱循环。

最佳答案

这应该是一种更快、更简洁的方法。主要是使用 shift() 函数而不是循环。简单的版本是这样的:

df[ df.isnull() ] = np.nanmean( [ df.shift(-48), df.shift(48) ] )

事实证明很难概括这一点,但这似乎可行:

df[ df.isnull() ] = np.nanmean( [ df.shift(x).values for x in 
                                     range(-48*window,48*(window+1),48) ], axis=0 )

我不确定,但怀疑 nanmean 可能存在错误,这也是您自己缺失值的相同原因。在我看来,如果你给它一个数据框,nanmean 就无法处理 nans。但是,如果我转换为一个数组(带有 .values)并使用 axis=0 那么它似乎可以工作。

检查 window=1 的结果:

print df.ix["2014-01-04 12:30":"2014-01-04 14:00", "B"]
print df.ix["2014-01-03 12:30":"2014-01-03 14:00", "B"]
print df.ix["2014-01-05 12:30":"2014-01-05 14:00", "B"]    

2014-01-04 12:30:00    0.940193     # was nan, now filled
2014-01-04 13:00:00    0.078160
2014-01-04 13:30:00   -0.662918
2014-01-04 14:00:00   -0.967121

2014-01-03 12:30:00    0.947915     # day before
2014-01-03 13:00:00    0.167218
2014-01-03 13:30:00   -0.391444
2014-01-03 14:00:00   -1.157040

2014-01-05 12:30:00    0.932471     # day after
2014-01-05 13:00:00   -0.010899
2014-01-05 13:30:00   -0.934391
2014-01-05 14:00:00   -0.777203

关于问题#2,这将取决于您的数据,但如果您在上述问题之前加上

df = df.resample('30min')

这将为所有缺失的行提供一行 nan,然后您可以像所有其他 nan 一样填充它们。如果可行的话,这可能是最简单、最快的方法。

或者,您可以使用 groupby 做一些事情。我的 groupby-fu 很弱,但为了给你它的味道,像这样:

df.groupby( df.index.hour ).fillna(method='pad')

会正确处理缺失行的问题,但不会处理其他问题。

关于python - 用相邻天的数据平均值填补数据缺口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25909115/

相关文章:

python - 使 Seaborn 热图之间的单元格大小相同

python - 如何加速 SQLAlchemy 查询?

python - Django 在 url 查询中需要参数

python - 如何在循环中从字典填充数据框

在 R 中使用 MSwM 包复制 Hamilton 的 Markov Switching Model 示例

python - Matplotlib 删除缺失数据的插值

python - 如何通过 stripe python api 创建定期费用?

python - 如何删除已存在列平均值的列

Python - 使用数据库中的图表创建 pdf 报告的过程是什么?

python - 在 Pandas 中获取平均年份(多年平均天数)