Pandas DataFrame自定义滚动函数,可以看到索引

时间:2018-03-05 16:04:09

标签: python pandas dataframe aggregation rolling-computation

我想在带有日期索引的DataFrame上应用偏移滚动窗口函数。这是一个例子:

rng = pd.date_range('2017-01-03', periods=20, freq='W')
df = pd.DataFrame(np.random.randn(20), rng, columns=['Val'])
df.index.name = 'Date'
r = df.rolling('15D')

这会生成一个DataFrame df,如:

                 Val
Date                
2017-01-08  0.592210
2017-01-15 -1.243938
2017-01-22 -0.713988
2017-01-29  1.554777
...

但我无法弄清楚如何在我应用于Rolling窗口的任何函数中看到与每个Val关联的日期。例如,以下内容:

def f(data=None): # I really want to reference the Date associated with each Val in here!
    print('f(%s) data=%s' % (str(type(data)), data))        
    return 1
r.apply(lambda x: f(x))

显示我看到的每个电话都是ndarray

f(<class 'numpy.ndarray'>) data=[0.59220959]
f(<class 'numpy.ndarray'>) data=[ 0.59220959 -1.24393841]
f(<class 'numpy.ndarray'>) data=[ 0.59220959 -1.24393841 -0.71398767]
f(<class 'numpy.ndarray'>) data=[-1.24393841 -0.71398767  1.55477737]
...

有没有办法在DataFrame上调用时间偏移滚动窗口,使聚合函数看到与窗口中每个值关联的索引?

,例如,我可以应用一个看起来像这样的函数:

f(<class 'DataFrame'>) data=[{2017-01-08, 0.59221}]
f(<class 'DataFrame'>) data=[{2017-01-08, 0.59221}, {2017-01-15, -1.243938}]
...

2 个答案:

答案 0 :(得分:1)

我认为只有pd.rolling才有办法解决这个问题。这是一个受a recent SO question启发的解决方法:

s = pd.Series([df.loc[d - pd.offsets.DateOffset(days=15):d, 'Val'] for d in df.index])

这将构建一系列系列,其中每个子系列包含您希望功能看到的日期和Val。即,使用您的示例函数s.apply(f)生成:

f(<class 'pandas.core.series.Series'>) data=Date
2017-01-08   -1.662699
Freq: W-SUN, Name: Val, dtype: float64
f(<class 'pandas.core.series.Series'>) data=Date
2017-01-08   -1.662699
2017-01-15    0.478471
Freq: W-SUN, Name: Val, dtype: float64
f(<class 'pandas.core.series.Series'>) data=Date
2017-01-08   -1.662699
2017-01-15    0.478471
2017-01-22   -0.552616
Freq: W-SUN, Name: Val, dtype: float64
f(<class 'pandas.core.series.Series'>) data=Date
2017-01-15    0.478471
2017-01-22   -0.552616
2017-01-29   -2.190669
...

答案 1 :(得分:1)

在最新版本的.apply(..., raw=False)中可以实现

诀窍是定义一个可以访问整个数据框的函数。然后,在任何列上滚动,并调用传递该函数的apply()。该函数将有权访问窗口数据,该数据是dataframe列的子集。从该子集中,您可以提取应该查看的索引。 (这假设您的索引严格增加。因此,通常的整数索引以及大多数时间序列都可以使用。)您可以使用索引来访问所有列的整个数据框。

def dataframe_roll(df):
    def my_fn(window_series):
        # Note: you can do any kind of offset here
        window_df = df[(df.index >= window_series.index[0]) & (df.index <= window_series.index[-1])]
        return window_df["col1"] + window_df["col2"]
    return my_fn

df["result"] = df["any_col"].rolling(24).apply(dataframe_roll(df), raw=False)