计算连胜 pandas
Compute winning streak with pandas
我以为我知道该怎么做,但我正在努力解决这个问题。我正在尝试使用一个函数来创建一个新列。该函数查看当前行中 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
感谢您帮助我摆脱困境。
让我们试试 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
工作原理
使用 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。
现在,使用 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
这就是我们想要的,但您可以看到它 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
原地分配。
使用 pandas
时一个相当常见的技巧是按连续值分组。这一招就是.
为了解决你的特定问题,我们想要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
,它允许我们按 1
和 0
的连续区域进行分组:
print(grouper)
0 1
1 1
2 2
3 2
4 2
5 3
6 4
Name: win, dtype: int64
您收到该错误的原因是因为 shift() 是 pandas 方法。您的代码试图做的是获取 numpy.int64 行 (row['win']) 中的值。所以你试图在 numpy.int64 上执行 shift()。这个 df['column'].shift(1) 所做的是获取一个日期框列,该列也是一个数据框,并将该列移动 1。
要亲自测试一下,请尝试
打印(类型(数据['win']))
和
打印(类型(行['win']))
和
打印(类型(行))
那会告诉你数据类型。
当你到达
时你也会得到一个错误
streak_row_above = 行['streak'].shift(-1)
因为您在创建之前引用了行['streak']。
我以为我知道该怎么做,但我正在努力解决这个问题。我正在尝试使用一个函数来创建一个新列。该函数查看当前行中 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
感谢您帮助我摆脱困境。
让我们试试 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
工作原理
使用 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。
现在,使用 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
这就是我们想要的,但您可以看到它 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
原地分配。
使用 pandas
时一个相当常见的技巧是按连续值分组。这一招就是
为了解决你的特定问题,我们想要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
,它允许我们按 1
和 0
的连续区域进行分组:
print(grouper)
0 1
1 1
2 2
3 2
4 2
5 3
6 4
Name: win, dtype: int64
您收到该错误的原因是因为 shift() 是 pandas 方法。您的代码试图做的是获取 numpy.int64 行 (row['win']) 中的值。所以你试图在 numpy.int64 上执行 shift()。这个 df['column'].shift(1) 所做的是获取一个日期框列,该列也是一个数据框,并将该列移动 1。
要亲自测试一下,请尝试 打印(类型(数据['win'])) 和 打印(类型(行['win'])) 和 打印(类型(行))
那会告诉你数据类型。
当你到达
时你也会得到一个错误
streak_row_above = 行['streak'].shift(-1)
因为您在创建之前引用了行['streak']。