【发布时间】:2021-10-16 09:37:26
【问题描述】:
我试图在一个组中的一些变量上在 pandas 中扩展 zscore,我注意到使用 apply 函数作为自定义函数相当慢。
这是我的数据的最小可重复版本,它仍然具有代表性:
import datetime
import pandas as pd
import numpy as np
import timeit
df = pd.DataFrame(
{"date": pd.date_range(start=datetime.datetime(2000,1,1), periods=10000),
"ids" : ["cat"]*5000 + ["dog"]*5000,
"x" : [random.random() for _ in range(10000)],
"y" : [random.random()*100 for _ in range(10000)],
}
)
>>> df.head()
date ids x y
0 2000-01-01 cat 0.947039 76.592064
1 2000-01-02 cat 0.200761 89.646584
2 2000-01-03 cat 0.305686 38.416170
3 2000-01-04 cat 0.080183 84.889605
4 2000-01-05 cat 0.258639 9.046614
在时间方面,这是我使用内置 .sum() 得到的结果
>>> timeit.timeit('df.set_index("date").groupby("ids")[["x","y"]].expanding(5).sum().reset_index()', number=10, globals=globals())
0.12283363699680194
虽然 zscore 函数比 sum 做的工作要多得多,所以我希望它会更慢——这真的很慢:
>>> zscore = lambda x: (x.values[-1] - x.mean())/x.std()
>>> timeit.timeit('df.set_index("date").groupby("ids")[["x","y"]].expanding(5).apply(zscore).reset_index()', number=10, globals=globals())
91.14701056003105
哇!这要慢得多。
所以虽然输出是我正在寻找的:
>>> df.set_index("date").groupby("ids")[["x","y"]].expanding(5).apply(zscore).reset_index()
ids date x y
0 cat 2000-01-01 NaN NaN
1 cat 2000-01-02 NaN NaN
2 cat 2000-01-03 NaN NaN
3 cat 2000-01-04 NaN NaN
4 cat 2000-01-05 -0.293887 -1.457395
... ... ... ... ...
9995 dog 2027-05-14 0.711095 -0.373902
9996 dog 2027-05-15 -0.929957 0.708371
9997 dog 2027-05-16 -1.668474 1.434254
9998 dog 2027-05-17 -0.059490 -1.721237
9999 dog 2027-05-18 -0.551626 1.015764
[10000 rows x 4 columns]
...我确实希望矢量化或潜在的转换比这更快。
但是,我天真地尝试将此代码矢量化:
np.vectorize(zscore)(df.set_index("date").groupby("ids")[["x","y"]].expanding(5))
Fails with:
f"'{type(self).__name__}' object has no attribute '{attr}'"
AttributeError: 'ExpandingGroupby' object has no attribute 'values'
我如何将这个.apply(func) 翻译成矢量化?
【问题讨论】:
-
尽管名称
np.vectorize不是“矢量化”。阅读它的所有文档!
标签: python pandas numpy vectorization