加快 Pandas 中的分组差分
Speeding up group-wise differencing in Pandas
考虑以下 solution 来计算 Pandas 中的组内差异:
df = df.set_index(['ticker', 'date']).sort_index()[['value']]
df['diff'] = np.nan
idx = pd.IndexSlice
for ix in df.index.levels[0]:
df.loc[ idx[ix,:], 'diff'] = df.loc[idx[ix,:], 'value' ].diff()
对于:
> df
date ticker value
0 63 C 1.65
1 88 C -1.93
2 22 C -1.29
3 76 A -0.79
4 72 B -1.24
5 34 A -0.23
6 92 B 2.43
7 22 A 0.55
8 32 A -2.50
9 59 B -1.01
它returns:
> df
value diff
ticker date
A 22 0.55 NaN
32 -2.50 -3.05
34 -0.23 2.27
76 -0.79 -0.56
B 59 -1.01 NaN
72 -1.24 -0.23
92 2.43 3.67
C 22 -1.29 NaN
63 1.65 2.94
88 -1.93 -3.58
该解决方案不适用于大型数据帧。形状为 (405344,2)
的数据框需要几分钟时间。大概是这种情况,因为我正在遍历主循环中第一级的每个值。
有什么方法可以在 Pandas 中加快速度吗?遍历索引值是解决这个问题的好方法吗? numba
可以用于此吗?
作为替代方案,您可以在每个组内进行排序和索引。虽然还没有经过时间考验:
In [11]: def value_and_diff(subdf):
subdf = subdf.set_index('date').sort_index()
return pd.DataFrame({'value': subdf['value'],
'diff': subdf['value'].diff()})
In [12]: df.groupby('ticker').apply(value_and_diff)
Out[12]:
diff value
ticker date
A 22 NaN 0.55
32 -3.05 -2.50
34 2.27 -0.23
76 -0.56 -0.79
B 59 NaN -1.01
72 -0.23 -1.24
92 3.67 2.43
C 22 NaN -1.29
63 2.94 1.65
88 -3.58 -1.93
这是另一种方式,应该会快很多。
首先,根据代码和日期排序:
In [11]: df = df.set_index(['ticker', 'date']).sort_index()
In [12]: df
Out[12]:
value
ticker date
A 22 0.55
32 -2.50
34 -0.23
76 -0.79
B 59 -1.01
72 -1.24
92 2.43
C 22 -1.29
63 1.65
88 -1.93
添加差异列:
In [13]: df['diff'] = df['value'].diff()
要填写NaN,我们可以找到第一行如下(可能有更好的方法):
In [14]: s = pd.Series(df.index.labels[0])
In [15]: s != s.shift()
Out[15]:
0 True
1 False
2 False
3 False
4 True
5 False
6 False
7 True
8 False
9 False
dtype: bool
In [16]: df.loc[(s != s.shift()).values 'diff'] = np.nan
In [17]: df
Out[17]:
value diff
ticker date
A 22 0.55 NaN
32 -2.50 -3.05
34 -0.23 2.27
76 -0.79 -0.56
B 59 -1.01 NaN
72 -1.24 -0.23
92 2.43 3.67
C 22 -1.29 NaN
63 1.65 2.94
88 -1.93 -3.58
使用groupby/apply简单优雅,但在Pandas中可能会很慢。 Bodo JIT编译器(基于Numba)在很多情况下可以让它变得很快:
pip install bodo
import pandas as pd
import numpy as np
import bodo
def value_and_diff(subdf):
subdf = subdf.set_index('date').sort_index()
return pd.DataFrame({'value': subdf['value'],
'diff': subdf['value'].diff()})
@bodo.jit(distributed=False)
def f(df):
df2 = df.groupby('ticker').apply(value_and_diff)
return df2
np.random.seed(0)
df = pd.DataFrame({'ticker': ["A", "B", "C", "D"] * 25_000,
'date': pd.date_range('1/1/2000', periods=100_000, freq='T'),
'value': np.random.randn(100_000)})
print(f(df))
考虑以下 solution 来计算 Pandas 中的组内差异:
df = df.set_index(['ticker', 'date']).sort_index()[['value']]
df['diff'] = np.nan
idx = pd.IndexSlice
for ix in df.index.levels[0]:
df.loc[ idx[ix,:], 'diff'] = df.loc[idx[ix,:], 'value' ].diff()
对于:
> df
date ticker value
0 63 C 1.65
1 88 C -1.93
2 22 C -1.29
3 76 A -0.79
4 72 B -1.24
5 34 A -0.23
6 92 B 2.43
7 22 A 0.55
8 32 A -2.50
9 59 B -1.01
它returns:
> df
value diff
ticker date
A 22 0.55 NaN
32 -2.50 -3.05
34 -0.23 2.27
76 -0.79 -0.56
B 59 -1.01 NaN
72 -1.24 -0.23
92 2.43 3.67
C 22 -1.29 NaN
63 1.65 2.94
88 -1.93 -3.58
该解决方案不适用于大型数据帧。形状为 (405344,2)
的数据框需要几分钟时间。大概是这种情况,因为我正在遍历主循环中第一级的每个值。
有什么方法可以在 Pandas 中加快速度吗?遍历索引值是解决这个问题的好方法吗? numba
可以用于此吗?
作为替代方案,您可以在每个组内进行排序和索引。虽然还没有经过时间考验:
In [11]: def value_and_diff(subdf):
subdf = subdf.set_index('date').sort_index()
return pd.DataFrame({'value': subdf['value'],
'diff': subdf['value'].diff()})
In [12]: df.groupby('ticker').apply(value_and_diff)
Out[12]:
diff value
ticker date
A 22 NaN 0.55
32 -3.05 -2.50
34 2.27 -0.23
76 -0.56 -0.79
B 59 NaN -1.01
72 -0.23 -1.24
92 3.67 2.43
C 22 NaN -1.29
63 2.94 1.65
88 -3.58 -1.93
这是另一种方式,应该会快很多。
首先,根据代码和日期排序:
In [11]: df = df.set_index(['ticker', 'date']).sort_index()
In [12]: df
Out[12]:
value
ticker date
A 22 0.55
32 -2.50
34 -0.23
76 -0.79
B 59 -1.01
72 -1.24
92 2.43
C 22 -1.29
63 1.65
88 -1.93
添加差异列:
In [13]: df['diff'] = df['value'].diff()
要填写NaN,我们可以找到第一行如下(可能有更好的方法):
In [14]: s = pd.Series(df.index.labels[0])
In [15]: s != s.shift()
Out[15]:
0 True
1 False
2 False
3 False
4 True
5 False
6 False
7 True
8 False
9 False
dtype: bool
In [16]: df.loc[(s != s.shift()).values 'diff'] = np.nan
In [17]: df
Out[17]:
value diff
ticker date
A 22 0.55 NaN
32 -2.50 -3.05
34 -0.23 2.27
76 -0.79 -0.56
B 59 -1.01 NaN
72 -1.24 -0.23
92 2.43 3.67
C 22 -1.29 NaN
63 1.65 2.94
88 -1.93 -3.58
使用groupby/apply简单优雅,但在Pandas中可能会很慢。 Bodo JIT编译器(基于Numba)在很多情况下可以让它变得很快:
pip install bodo
import pandas as pd
import numpy as np
import bodo
def value_and_diff(subdf):
subdf = subdf.set_index('date').sort_index()
return pd.DataFrame({'value': subdf['value'],
'diff': subdf['value'].diff()})
@bodo.jit(distributed=False)
def f(df):
df2 = df.groupby('ticker').apply(value_and_diff)
return df2
np.random.seed(0)
df = pd.DataFrame({'ticker': ["A", "B", "C", "D"] * 25_000,
'date': pd.date_range('1/1/2000', periods=100_000, freq='T'),
'value': np.random.randn(100_000)})
print(f(df))