计算与熊猫的连胜纪录

时间:2018-10-24 19:10:24

标签: python pandas dataframe shift

我以为我知道该怎么做,但是我正在把头发拔出来。我正在尝试使用一个函数来创建新列。该函数查看当前行中win列的值,并需要将其与win列中的前一个数字进行比较,如下面的if语句所示。获胜栏将永远只有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)

所有这些都以以下错误结束:

AttributeError: ("'numpy.int64' object has no attribute 'shift'", 'occurred at index 0')

在其他示例中,我看到了引用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

感谢您帮助我摆脱困境。

3 个答案:

答案 0 :(得分:3)

让我们尝试groupbycumcount

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

工作方式

使用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

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

现在,使用groupbycumcount为组中的每一行分配单调递增的数字。

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

0    0
1    1
2    0
3    1
4    2
5    2
6    0
dtype: int64

这是我们想要的,但是您可以看到它是1)从零开始,以及2)还向0分配值(无获胜)。我们可以使用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

将此内容分配回原位。

答案 1 :(得分:2)

使用pandas时,一个相当普遍的技巧是按连续值分组。这个诀窍是well-described here

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

grouper = (df.win != df.win.shift()).cumsum()
df['streak'] = df.groupby(grouper).cumsum()

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

为便于说明,这是我们的grouper Series,它使我们可以按10的连续区域进行分组:

print(grouper)

0    1
1    1
2    2
3    2
4    2
5    3
6    4
Name: win, dtype: int64

答案 2 :(得分:1)

出现该错误的原因是因为shift()是熊猫方法。您的代码尝试执行的操作是在numpy.int64的行(row ['win'])中获取值。因此,您尝试在numpy.int64上执行shift()的位置。 df ['column']。shift(1)要做的是获取一个也是数据帧的dateframe列,并将该列移动1。

要自己测试一下,请尝试 打印(类型(数据['win'])) 和 print(type(row ['win'])) 和 打印(类型(行))

这将告诉您数据类型。

当您进入时也会出现错误
streak_row_above = row ['streak']。shift(-1)

因为您在创建row ['streak']之前就对其进行了引用。