![](/img/trans.png)
[英]Efficiently finding consecutive streaks in a pandas DataFrame column?
[英]finding streaks in pandas dataframe
我有一個pandas數據幀如下:
time winner loser stat
1 A B 0
2 C B 0
3 D B 1
4 E B 0
5 F A 0
6 G A 0
7 H A 0
8 I A 1
每一行都是匹配結果。 第一列是匹配的時間,第二列和第三列包含贏家/輸家,第四列是匹配的一個統計。
我想檢測每個輸家的統計數據為零。
預期結果應如下所示:
time winner loser stat streak
1 A B 0 1
2 C B 0 2
3 D B 1 0
4 E B 0 1
5 F A 0 1
6 G A 0 2
7 H A 0 3
8 I A 1 0
在偽代碼中,算法應該像這樣工作:
.groupby
loser
專欄。 loser
組的每一行 stat
列:如果它包含0
,則將前一行的streak
值增加0
。 如果它不是0
,則開始一個新的streak
,即將0
放入streak
列。 所以.groupby
很清楚。 但是我需要某種.apply
,我可以看看前一行? 這是我被困的地方。
您可以apply
自定義函數f
,然后應用cumsum
, cumcount
和astype
:
def f(x):
x['streak'] = x.groupby( (x['stat'] != 0).cumsum()).cumcount() +
( (x['stat'] != 0).cumsum() == 0).astype(int)
return x
df = df.groupby('loser', sort=False).apply(f)
print df
time winner loser stat streak
0 1 A B 0 1
1 2 C B 0 2
2 3 D B 1 0
3 4 E B 0 1
4 5 F A 0 1
5 6 G A 0 2
6 7 H A 0 3
7 8 I A 1 0
為了更好的未成年:
def f(x):
x['c'] = (x['stat'] != 0).cumsum()
x['a'] = (x['c'] == 0).astype(int)
x['b'] = x.groupby( 'c' ).cumcount()
x['streak'] = x.groupby( 'c' ).cumcount() + x['a']
return x
df = df.groupby('loser', sort=False).apply(f)
print df
time winner loser stat c a b streak
0 1 A B 0 0 1 0 1
1 2 C B 0 0 1 1 2
2 3 D B 1 1 0 0 0
3 4 E B 0 1 0 1 1
4 5 F A 0 0 1 0 1
5 6 G A 0 0 1 1 2
6 7 H A 0 0 1 2 3
7 8 I A 1 1 0 0 0
不像jezrael的答案那么優雅,但對我來說更容易理解......
首先,定義一個與單個輸家一起使用的函數:
def f(df):
df['streak2'] = (df['stat'] == 0).cumsum()
df['cumsum'] = np.nan
df.loc[df['stat'] == 1, 'cumsum'] = df['streak2']
df['cumsum'] = df['cumsum'].fillna(method='ffill')
df['cumsum'] = df['cumsum'].fillna(0)
df['streak'] = df['streak2'] - df['cumsum']
df.drop(['streak2', 'cumsum'], axis=1, inplace=True)
return df
條紋基本上是一個cumsum
,但我們需要在每次stat
為1時重置它。因此我們減去stat
為1的cumsum
的值,結轉到下一個1。
然后groupby
並通過輸家apply
:
df.groupby('loser').apply(f)
結果如預期。
您可以使用iterrows
訪問上一行:
df['streak'] = 0
for i, row in df.iterrows():
if i != 0:
if row['stat'] == 0:
if row['loser'] == df.ix[i-1, 'loser']:
df.ix[i, 'streak'] = df.ix[i-1, 'streak'] + 1
else:
df.ix[i, 'streak'] = 1
else:
if row['stat'] == 0:
df.ix[i, 'streak'] = 1
這使:
In [210]: df
Out[210]:
time winner loser stat streak
0 1 A B 0 1
1 2 C B 0 2
2 3 D B 1 0
3 4 E B 0 1
4 5 F A 0 1
5 6 G A 0 2
6 7 H A 0 3
7 8 I A 1 0
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.