在熊猫数据框中找到条纹

bet*_*eta 10 python dataframe pandas

我有一个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
Run Code Online (Sandbox Code Playgroud)

每一行都是匹配结果.第一列是匹配的时间,第二列和第三列包含赢家/输家,第四列是匹配的一个统计.

我想检测每个输家的统计数据为零.

预期结果应如下所示:

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
Run Code Online (Sandbox Code Playgroud)

在伪代码中,算法应该像这样工作:

  • .groupby loser 柱.
  • 然后遍历每个loser组的每一行
  • 在每一行中,查看stat列:如果包含0,streak则从上一行增加值0.如果不是0,然后开始一个新的streak,那就是,把0streak列.

所以.groupby很清楚.但那时我需要某种.apply我可以看到前一行的地方?这是我被困的地方.

jez*_*ael 13

你可以apply自定义函数f,然后cumsum,cumcountastype:

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
Run Code Online (Sandbox Code Playgroud)

为了更好的未成年:

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
Run Code Online (Sandbox Code Playgroud)


Ian*_*anS 5

不像 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
Run Code Online (Sandbox Code Playgroud)

连胜本质上是 a cumsum,但我们每次需要将其重置stat为 1。 因此我们减去cumsumwhere的值stat是 1,结转直到下一个 1。

然后groupbyapply失败者:

df.groupby('loser').apply(f)
Run Code Online (Sandbox Code Playgroud)

结果如预期。