Pandas 滑动窗口

4
我有一个用日期时间索引的pandas DataFrame如下所示:
                             VAL
           DATETIME    
2012-01-02 02:00:00    3.375000
2012-01-02 02:01:00    3.281667
2012-01-02 02:02:00    3.426667
2012-01-02 02:03:00    3.378333
2012-01-02 02:04:00    3.381667
2012-01-02 02:05:00    3.831667
....

我需要将DataFrame转换为以下格式:
                            VAL        VAL1        VAL2
           DATETIME    
2012-01-02 02:00:00    3.375000    3.281667    3.426667
2012-01-02 02:01:00    3.281667    3.426667    3.378333
2012-01-02 02:02:00    3.426667    3.378333    3.381667
2012-01-02 02:03:00    3.378333    3.381667    3.831667
...

有没有内置函数或者高效的方法可以实现这个功能?
2个回答

4

使用 Series.shift 和循环来分配多个新列:

for x in range(1, 3):
    df['VAL{}'.format(x)] = df['VAL'].shift(-x)

如果需要将时间调整一分钟:

for x in range(1, 3):
    df['VAL{}'.format(x)] = df['VAL'].shift(-x, freq='T')

print (df)
                          VAL      VAL1      VAL2
DATETIME                                         
2012-01-02 02:00:00  3.375000  3.281667  3.426667
2012-01-02 02:01:00  3.281667  3.426667  3.378333
2012-01-02 02:02:00  3.426667  3.378333  3.381667
2012-01-02 02:03:00  3.378333  3.381667  3.831667
2012-01-02 02:04:00  3.381667  3.831667       NaN
2012-01-02 02:05:00  3.831667       NaN       NaN

最后,如有必要,请删除具有 NaN 的最后行:

#N > 1
N = 3
for x in range(1, N):
    df['VAL{}'.format(x)] = df['VAL'].shift(-x, freq='T')

df = df.iloc[:-N + 1]
print (df)
                          VAL      VAL1      VAL2
DATETIME                                         
2012-01-02 02:00:00  3.375000  3.281667  3.426667
2012-01-02 02:01:00  3.281667  3.426667  3.378333
2012-01-02 02:02:00  3.426667  3.378333  3.381667
2012-01-02 02:03:00  3.378333  3.381667  3.831667

2
你可以使用NumPy的stride_tricks函数:
import numpy as np
import numpy.lib.stride_tricks as stride
import pandas as pd
df = pd.DataFrame({'DATETIME': ['2012-01-02 02:00:00', '2012-01-02 02:01:00', '2012-01-02 02:02:00', '2012-01-02 02:03:00', '2012-01-02 02:04:00', '2012-01-02 02:05:00'], 'VAL': [3.375, 3.2816669999999997, 3.4266669999999997, 3.378333, 3.3816669999999998, 3.831667]})
df['DATETIME']  = pd.to_datetime(df['DATETIME'])
df = df.set_index('DATETIME')


stride = df['VAL'].values.strides[0]
ncols = 3
nrows = len(df)-ncols+1
arr = stride.as_strided(df['VAL'], shape=(nrows, ncols), strides=(stride, stride))

result = pd.DataFrame(arr.copy(), columns=['VAL{}'.format(i) for i in range(1, ncols+1)],
                      index=df.index[:nrows])

产出率
                         VAL1      VAL2      VAL3
DATETIME                                         
2012-01-02 02:00:00  3.375000  3.281667  3.426667
2012-01-02 02:01:00  3.281667  3.426667  3.378333
2012-01-02 02:02:00  3.426667  3.378333  3.381667
2012-01-02 02:03:00  3.378333  3.381667  3.831667

strides=(stride,stride)是制作滑动窗口的关键。它告诉stride.as_stridedresult中的每个位置,下一个值(即下一列)在stride个字节之后,而每个向下的值(即下一行)也只有stride个字节之后。定义result中的值的字节来自基础数组arr.copy()


虽然stride_tricks可以非常快速地生成所需的数组,但与其使用相关的注意事项也有缺陷。请参见下文和文档页面上的注释。这些注意事项完全可以通过复制数组来解决,即使用arr.copy()而不是arr本身。另一方面,复制数组,特别是如果它很大,将降低性能。


请注意,如果您使用pd.DataFrame(arr)而不是pd.DataFrame(arr.copy()),则DataFrame中的值是df['VAL']的视图。虽然这样做可以节省内存,但这也意味着修改result中的一个值可能会更改多个位置上的值。例如,

result = pd.DataFrame(arr, columns=['VAL{}'.format(i) for i in range(1, ncols+1)],
                      index=df.index[:nrows])

In [30]: result.iloc[1,1] = 100
In [27]: result
Out[27]: 
                           VAL1        VAL2        VAL3
DATETIME                                               
2012-01-02 02:00:00    3.375000    3.281667  100.000000
2012-01-02 02:01:00    3.281667  100.000000    3.378333
2012-01-02 02:02:00  100.000000    3.378333    3.381667
2012-01-02 02:03:00    3.378333    3.381667    3.831667

如果您希望每个值都是独立的,请使用 arr.copy()

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