使用相邻日期的平均数据填充数据缺口

时间:2014-09-18 09:35:12

标签: python pandas time-series

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

我不知道该怎么做。现在,我可能会遍历数据框中的每一行和一行,并在np.nanmean的行中编写一个非常糟糕的黑客,但我觉得必须有更多的pythonic / pandas-y方式?

样本数据集:

np.mean(df.ix[[i-48, i, i+48], "A"])

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

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

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]

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

  1. 如果在任何地方丢失或重复了一行,则会失败。在最后一行,我想减去"有一天"所有的时间,无论是47,48或49行。此外,我可以扩展范围(例如-3天到+3天)而无需手动编写索引列表。
  2. 我想摆脱循环,如果可能的话。

1 个答案:

答案 0 :(得分:3)

这应该是一种更快,更简洁的方法。主要是使用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')

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

或者,您可以使用groupby执行某些操作。我的groupby-fu很弱但是给你的味道,比如:

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

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