[英]Rolling m out of n most recent occurences of condition in pandas
我對符合條件的最后'n'事件中的'm'次數感興趣,按人或用戶分組 。 具體來說,我感興趣的是玩家是否習慣於在給定的班級或“類別”中玩游戲,這取決於他們最后幾場比賽(而不是任何比賽)中有多少比賽是在指定等級或高於指定等級。
我盡職盡責地打破了一個玩具數據集中的一個小組,然后讓我的代碼在下面工作。 但是,當我嘗試在SeriesGroupBy
對象上隨意使用相同的方法鏈時,事情會發生故障。
首先,最簡單的例子。 當玩家3的前3個匹配中的2個屬於類別3時,列hc
(高等級)為1
否則,它為0.(我手動生成此並使用0 | 1,而不是True | False。):
import pandas as pd
pd.__version__
# '0.23.4'
match = ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c',
'c', 'c', 'd', 'd', 'd', 'e', 'e', 'e', 'e']
category = [3, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2]
player = ['bar', 'baz', 'chaz', 'baz', 'choo', 'chaz', 'chaz', 'foo',
'baz', 'choo', 'foo', 'char', 'baz', 'choo', 'foo', 'chaz', 'baz']
hc = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1]
games = pd.DataFrame({'match': match, 'category': category, 'player': player, 'hc': hc})
games
# match category player hc
# 0 a 3 bar 0
# 1 a 3 baz 0
# 2 a 3 chaz 0
# 3 b 2 baz 0
# 4 b 2 choo 0
# 5 b 2 chaz 0
# 6 c 3 chaz 0
# 7 c 3 foo 0
# 8 c 3 baz 0
# 9 c 3 choo 0
# 10 d 3 foo 0
# 11 d 3 char 0
# 12 d 3 baz 1
# 13 e 2 choo 0
# 14 e 2 foo 1
# 15 e 2 chaz 1
# 16 e 2 baz 1
由於我之前的漫長努力而充分受阻,我采用了(顯然是天真的)策略來打破一個有趣的玩家並讓計算在拆分組上工作:
baz = games.groupby('player').get_group('baz')
baz
# match category player hc
# 1 a 3 baz 0
# 3 b 2 baz 0
# 8 c 3 baz 0
# 12 d 3 baz 1
# 16 e 2 baz 1
result = baz.category.gt(2).rolling(3).sum().shift().gt(1)
result
# 1 False
# 3 False
# 8 False
# 12 True
# 16 True
# Name: category, dtype: bool
成功! 我是熊貓黑客! 我已經升天了,現在可以用Pandoric Way來輔導別人了! 在我購買長袍並在修道院收到我分配的嬰兒床之前,先讓我快速檢查一下:
games.groupby('player').category.gt(2).rolling(3).sum().shift().gt(1)
回溯(最近一次調用最后一次):文件“”,第1行,在文件“(枯燥的路徑東西)/lib/python3.6/site-packages/pandas/core/groupby/groupby.py”,第762行,在getattr中 return self._make_wrapper(attr)文件“(枯燥的路徑東西)/lib/python3.6/site-packages/pandas/core/groupby/groupby.py”,第799行,在_make_wrapper中引發AttributeError(msg)AttributeError:無法訪問'SeriesGroupBy'對象的可調用屬性'gt',嘗試使用'apply'方法
啊。 我是暴徒。
這樣做有什么好處? 還有,我做錯了什么? 在元級別,為什么我的策略在單個組上運行然后推廣不起作用? 我確實嘗試了apply()
方式。 它輸出廢話。
編輯: apply()
可能答案:
games['actual_hc'] =
games.groupby('player').category.apply(lambda x: x.shift().gt(2).rolling(3).sum().fillna(0, downcast='infer').astype(int).gt(1))
games
# match category player hc actual_hc
# 0 a 3 bar 0 False
# 1 a 3 baz 0 False
# 2 a 3 chaz 0 False
# 3 b 2 baz 0 False
# 4 b 2 choo 0 False
# 5 b 2 chaz 0 False
# 6 c 3 chaz 0 False
# 7 c 3 foo 0 False
# 8 c 3 baz 0 False
# 9 c 3 choo 0 False
# 10 d 3 foo 0 False
# 11 d 3 char 0 False
# 12 d 3 baz 1 True
# 13 e 2 choo 0 False
# 14 e 2 foo 1 True
# 15 e 2 chaz 1 True
# 16 e 2 baz 1 True
這在我的實際250k行DataFrame上大約需要12秒。 我仍然喜歡更快的東西,只要知道“正確的方式”,如果有的話。
使用申請:
games.groupby('player').apply(
lambda group: group.category.gt(2).rolling(3).sum().shift().gt(1)
)
這輸出:
player
bar 0 False
baz 1 False
3 False
8 False
12 True
16 True
char 11 False
chaz 2 False
5 False
6 False
15 True
choo 4 False
9 False
13 False
foo 7 False
10 False
14 False
Name: category, dtype: bool
這似乎是你想要的。
我不知道這是否是性能最好的,但由於錯誤建議使用apply,我猜猜大熊貓的開發人員認為這是一個好主意。
我最近重新審視了這個問題並發現了答案, transform()
。 出於某種原因,pj.dewitte的apply()
的回答對rolling()
的min_periods參數不敏感,無論我在鍵入min_periods=2
時按下鍵有多難。
完整答案:
games['actual_hc'] = \
games.groupby('player').category.transform(
lambda g:
g.gt(2).rolling(3, min_periods=2).sum().shift().gt(1)).astype(int)
# match category player hc actual_hc
# 0 a 3 bar 0 0
# 1 a 3 baz 0 0
# 2 a 3 chaz 0 0
# 3 b 2 baz 0 0
# 4 b 2 choo 0 0
# 5 b 2 chaz 0 0
# 6 c 3 chaz 0 0
# 7 c 3 foo 0 0
# 8 c 3 baz 0 0
# 9 c 3 choo 0 0
# 10 d 3 foo 0 0
# 11 d 3 char 0 0
# 12 d 3 baz 1 1
# 13 e 2 choo 0 0
# 14 e 2 foo 1 1
# 15 e 2 chaz 1 1
# 16 e 2 baz 1 1
請注意,即使foo
在她的最后一場比賽之前只有兩場比賽,他們都是三級,並且她被正確地報告為games.iloc[14]
的高級球員。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.