用熊猫计算连胜纪录

min*_*rat 4 python shift dataframe pandas

我以为我知道该怎么做,但我正在把头发拉出来。我正在尝试使用一个函数来创建一个新列。该函数查看当前行中 win 列的值,并需要将其与 win 列中的前一个数字进行比较,如下面的 if 语句所示。win 列永远只会是 0 或 1。

import pandas as pd
data = pd.DataFrame({'win': [0, 0, 1, 1, 1, 0, 1]})
print (data)

   win
0    0
1    0
2    1
3    1
4    1
5    0
6    1

def streak(row):
    win_current_row = row['win']
    win_row_above = row['win'].shift(-1)
    streak_row_above = row['streak'].shift(-1)

    if (win_row_above == 0) & (win_current_row == 0):
        return 0
    elif (win_row_above == 0) & (win_current_row ==1):
        return 1
    elif (win_row_above ==1) & (win_current_row == 1):
        return streak_row_above + 1
    else:
        return 0

data['streak'] = data.apply(streak, axis=1)
Run Code Online (Sandbox Code Playgroud)

所有这一切都以这个错误结束:

AttributeError: ("'numpy.int64' object has no attribute 'shift'", 'occurred at index 0')
Run Code Online (Sandbox Code Playgroud)

在其他示例中,我看到了所指的函数,df['column'].shift(1)所以我很困惑为什么在这种情况下我似乎无法做到这一点。

我也想得到的输出是:

result = pd.DataFrame({'win': [0, 0, 1, 1, 1, 0, 1], 'streak': ['NaN', 0 , 1, 2, 3, 0, 1]})
print(result)

   win streak
0    0    NaN
1    0      0 
2    1      1
3    1      2
4    1      3
5    0      0
6    1      1
Run Code Online (Sandbox Code Playgroud)

谢谢你帮我解脱。

use*_*203 8

使用时一个相当常见的技巧pandas是按连续值分组。这个技巧在这里很好的描述

为了解决您的特定问题,我们想要groupby连续的值,然后使用cumsum,这意味着损失组( 组0)的累积总和为0,而获胜组(或 组1)将跟踪连续获胜。

grouper = (df.win != df.win.shift()).cumsum()
df['streak'] = df.groupby(grouper).cumsum()
Run Code Online (Sandbox Code Playgroud)

   win  streak
0    0       0
1    0       0
2    1       1
3    1       2
4    1       3
5    0       0
6    1       1
Run Code Online (Sandbox Code Playgroud)

为了便于解释,这里是 our grouper Series,它允许我们按1's 和0's 的连续区域进行分组:

print(grouper)
Run Code Online (Sandbox Code Playgroud)

0    1
1    1
2    2
3    2
4    2
5    3
6    4
Name: win, dtype: int64
Run Code Online (Sandbox Code Playgroud)


cs9*_*s95 5

让我们尝试groupby一下cumcount

m = df.win.astype(bool)
df['streak'] = (
    m.groupby([m, (~m).cumsum().where(m)]).cumcount().add(1).mul(m))

df
   win  streak
0    0       0
1    0       0
2    1       1
3    1       2
4    1       3
5    0       0
6    1       1
Run Code Online (Sandbox Code Playgroud)

怎么运行的

使用df.win.astype(bool),转换df['win']为其布尔值(1=True,0=False)。

下一个,

(~m).cumsum().where(m)

0    NaN
1    NaN
2    2.0
3    2.0
4    2.0
5    NaN
6    3.0
Name: win, dtype: float64
Run Code Online (Sandbox Code Playgroud)

用唯一的数字表示所有连续的 1,其中 0 被掩码为 NaN。

现在,使用groupby、 和cumcount为组中的每一行分配一个单调递增的数字。

m.groupby([m, (~m).cumsum().where(m)]).cumcount()

0    0
1    1
2    0
3    1
4    2
5    2
6    0
dtype: int64
Run Code Online (Sandbox Code Playgroud)

这就是我们想要的,但你可以看到它是 1) 从零开始的,2) 也给0(no win) 赋值。我们可以用m它来屏蔽它(x 乘以 1 (=True) 为 x,任何值乘以 0 (=False) 为 0)。

m.groupby([m, (~m).cumsum().where(m)]).cumcount().add(1).mul(m)

0    0
1    0
2    1
3    2
4    3
5    0
6    1
dtype: int64
Run Code Online (Sandbox Code Playgroud)

将其分配回原位。