滚动时间值的分组百分位排名 window
Grouped percentile rank of value in rolling time window
在这些示例数据中,用户在随机日期及时下订单某些随机值。
我已经成功地实施了一种方法来计算关于同一用户最近 180 天的订单的每个值的百分位排名。
但是,对于较大的 n
值,最后 groupby
行代码 运行 非常慢(1M 行 运行 大约需要 1 分钟 30 秒)有没有人有关于如何改进计算时间的建议?
import pandas as pd
import numpy as np
from scipy.stats import percentileofscore
#percentile rank function
def rank(x, kind):
return percentileofscore(x, score = x.iloc[-1], kind = kind)
#sample data
n = 10000
orders = pd.DataFrame({
'user':np.random.randint(1, 100, size = n),
'value':np.random.randn(n),
'date':np.random.choice( pd.date_range('1/1/2019', periods=730,
freq='D'), n)
})
orders_sort = orders.sort_values(by = ['user', 'date']).reset_index(drop =True)
#group by time window percentile rank - SLOW!
orders_sort.groupby('user')[['value', 'date']].rolling('180d', on = 'date').apply(lambda x: rank(x, kind = 'mean'))
value date
user
1 0 50.000000 2019-01-03
1 75.000000 2019-01-10
2 83.333333 2019-01-12
3 87.500000 2019-01-17
4 10.000000 2019-01-22
... ... ...
99 9995 19.565217 2020-11-23
9996 64.583333 2020-11-26
9997 39.583333 2020-12-04
9998 54.000000 2020-12-05
9999 6.000000 2020-12-12
[10000 rows x 2 columns]
你可以利用 apply 中的参数 raw=True
来传递一个 numpy 数组而不是 Series。您需要稍微更改函数以使用数组。
def rank_np(x, kind):
return percentileofscore(x, score = x[-1], kind = kind) #no iloc as x is an array
然后就像你用参数 raw 做的那样:
orders_sort.groupby('user')[['value', 'date']]\
.rolling('180d', on = 'date')\
.apply(lambda x: rank_np(x, kind = 'mean'), raw=True) #see here
我在 n=10K 或 50K 时速度提高了 6.5 倍,不确定它在 n=1M 行时的表现如何
在这些示例数据中,用户在随机日期及时下订单某些随机值。 我已经成功地实施了一种方法来计算关于同一用户最近 180 天的订单的每个值的百分位排名。
但是,对于较大的 n
值,最后 groupby
行代码 运行 非常慢(1M 行 运行 大约需要 1 分钟 30 秒)有没有人有关于如何改进计算时间的建议?
import pandas as pd
import numpy as np
from scipy.stats import percentileofscore
#percentile rank function
def rank(x, kind):
return percentileofscore(x, score = x.iloc[-1], kind = kind)
#sample data
n = 10000
orders = pd.DataFrame({
'user':np.random.randint(1, 100, size = n),
'value':np.random.randn(n),
'date':np.random.choice( pd.date_range('1/1/2019', periods=730,
freq='D'), n)
})
orders_sort = orders.sort_values(by = ['user', 'date']).reset_index(drop =True)
#group by time window percentile rank - SLOW!
orders_sort.groupby('user')[['value', 'date']].rolling('180d', on = 'date').apply(lambda x: rank(x, kind = 'mean'))
value date
user
1 0 50.000000 2019-01-03
1 75.000000 2019-01-10
2 83.333333 2019-01-12
3 87.500000 2019-01-17
4 10.000000 2019-01-22
... ... ...
99 9995 19.565217 2020-11-23
9996 64.583333 2020-11-26
9997 39.583333 2020-12-04
9998 54.000000 2020-12-05
9999 6.000000 2020-12-12
[10000 rows x 2 columns]
你可以利用 apply 中的参数 raw=True
来传递一个 numpy 数组而不是 Series。您需要稍微更改函数以使用数组。
def rank_np(x, kind):
return percentileofscore(x, score = x[-1], kind = kind) #no iloc as x is an array
然后就像你用参数 raw 做的那样:
orders_sort.groupby('user')[['value', 'date']]\
.rolling('180d', on = 'date')\
.apply(lambda x: rank_np(x, kind = 'mean'), raw=True) #see here
我在 n=10K 或 50K 时速度提高了 6.5 倍,不确定它在 n=1M 行时的表现如何