我正在尝试计算一个滚动统计量,该统计量需要一个窗口中来自两个输入列的所有变量。
我唯一的解决方案涉及for循环。有没有更有效的方法,也许使用了Pandas的滚动和应用功能?
import pandas as pd
from statsmodels.tsa.stattools import coint
def f(x):
return coint(x['a'], x['b'])[1]
df = pd.DataFrame(data={'a': [1, 2, 3, 4], 'b': [5, 6, 7, 8]})
df2 = df.rolling(2).apply(lambda x: f(x), raw=False) # KeyError: 'a'
我得到KeyError:'a',因为df一次传递给一个系列(列)的f()。指定axis = 1会将一行和所有列发送到f(),但是两种方法都不能提供所需的一组观察值。
答案 0 :(得分:2)
您可以尝试滚动,平均和求和:
df['result'] = df.rolling(2).mean().sum(axis=1)
a b result
0 1 5 0.0
1 2 6 7.0
2 3 7 9.0
3 4 8 11.0
编辑
根据OP中问题中的新信息添加不同的答案。
设置功能。
import pandas as pd
from statsmodels.tsa.stattools import coint
def f(x):
return coint(x['a'], x['b'])
创建数据和数据框:
a_data = [1,2,3,4]
b_data = [5,6,7,8]
df = pd.DataFrame(data={'a': a_data, 'b': b_data})
a b
0 1 5
1 2 6
2 3 7
3 4 8
在研究了硬币之后,我收集到您试图将两个滚动数组传递给f ['a']和f ['b']。下面将创建数组和数据框。
n=2
arr_a = [df['a'].shift(x).values[::-1][:n] for x in range(len(df['a']))[::-1]]
arr_b = [df['b'].shift(x).values[::-1][:n] for x in range(len(df['b']))[::-1]]
df1 = pd.DataFrame(data={'a': arr_a, 'b': arr_b})
n是滚动窗口的大小。
df1
a b
0 [1.0, nan] [5.0, nan]
1 [2.0, 1.0] [6.0, 5.0]
2 [3.0, 2.0] [7.0, 6.0]
3 [4, 3] [8, 7]
然后您可以使用apply。(f)发送数组中的行。
df1.iloc[(n-1):,].apply(f, axis=1)
您的输出如下:
1 (-inf, 0.0, [-48.37534, -16.26923, -10.00565])
2 (-inf, 0.0, [-48.37534, -16.26923, -10.00565])
3 (-inf, 0.0, [-48.37534, -16.26923, -10.00565])
dtype: object
运行此命令时,对于完全共线性的数据确实会出现错误,但我怀疑该错误会随着实际数据消失。
此外,我知道纯粹的矢量化解决方案可能会更快。我想知道如果您要寻找的是什么表现?
向真正为this problem here解决方案的@Zero致意。
答案 1 :(得分:0)
我尝试将总和放在滚动前:
import pandas as pd
import time
df = pd.DataFrame(data={'a': [1, 2, 3, 4], 'b': [5, 6, 7, 8]})
df2 = df.copy()
s = time.time()
df2.loc[:, 'mean1'] = df.sum(axis = 1).rolling(2).mean()
print(time.time() - s)
s = time.time()
df2.loc[:, 'mean2'] = df.rolling(2).mean().sum(axis=1)
print(time.time() - s)
df2
0.003737926483154297
0.005460023880004883
a b mean1 mean2
0 1 5 NaN 0.0
1 2 6 7.0 7.0
2 3 7 9.0 9.0
3 4 8 11.0 11.0
它比以前的答案要快一些,但效果相同,并且在大型数据集中差异可能很大。
您可以修改它以仅选择感兴趣的列:
s = time.time()
print(df[['a', 'b']].sum(axis = 1).rolling(2).mean())
print(time.time() - s)
0 NaN
1 7.0
2 9.0
3 11.0
dtype: float64
0.0033559799194335938