熊猫:条件滚动计数

jus*_*vol 35 python pandas

我有一个看起来如下的系列:

   col
0  B
1  B
2  A
3  A
4  A
5  B
Run Code Online (Sandbox Code Playgroud)

这是一个时间序列,因此索引按时间排序.

对于每一行,我想计算该值连续出现的次数,即:

输出:

   col count
0  B   1
1  B   2
2  A   1 # Value does not match previous row => reset counter to 1
3  A   2
4  A   3
5  B   1 # Value does not match previous row => reset counter to 1
Run Code Online (Sandbox Code Playgroud)

我找到了2个相关问题,但我无法弄清楚如何将这些信息"写"为DataFrame中的新列,每行(如上所述).使用rolling_apply效果不佳.

有关:

按索引计算pandas数据帧上的连续事件

在pandas数据框中查找连续的段

P.T*_*ann 39

我觉得这是对@chrisb和@CodeShaman的解决方案相结合的好办法(正如有人指出CodeShamans解决方案总计算,而不是连续值).

  df['count'] = df.groupby((df['col'] != df['col'].shift(1)).cumsum()).cumcount()+1

  col  count
0   B      1
1   B      2
2   A      1
3   A      2
4   A      3
5   B      1
Run Code Online (Sandbox Code Playgroud)

  • @P.Tillmann 如果您需要按多列进行分组怎么办? (3认同)

Cod*_*man 20

一内胆:

df['count'] = df.groupby('col').cumcount()
Run Code Online (Sandbox Code Playgroud)

要么

df['count'] = df.groupby('col').cumcount() + 1
Run Code Online (Sandbox Code Playgroud)

如果你想让计数从1开始.

  • 这不是问题的答案.这不计算连续值,它计算总值. (26认同)
  • 如果你想开始计数器更容易使用: df['count'] = df.groupby('col').cumcount() + 1 (2认同)

chr*_*isb 14

根据您链接的第二个答案,假设s是您的系列.

df = pd.DataFrame(s)
df['block'] = (df['col'] != df['col'].shift(1)).astype(int).cumsum()
df['count'] = df.groupby('block').transform(lambda x: range(1, len(x) + 1))


In [88]: df
Out[88]: 
  col  block  count
0   B      1      1
1   B      1      2
2   A      2      1
3   A      2      2
4   A      2      3
5   B      3      1
Run Code Online (Sandbox Code Playgroud)

  • 真的很喜欢你的方法。但是,如果对多列进行分组怎么办? (2认同)

ZJS*_*ZJS 9

我喜欢@chrisb的答案,但想分享我自己的解决方案,因为有些人可能会发现它更易读,更容易使用类似的问题....

1)创建一个使用静态变量的函数

def rolling_count(val):
    if val == rolling_count.previous:
        rolling_count.count +=1
    else:
        rolling_count.previous = val
        rolling_count.count = 1
    return rolling_count.count
rolling_count.count = 0 #static variable
rolling_count.previous = None #static variable
Run Code Online (Sandbox Code Playgroud)

2)转换为数据帧后将其应用于您的系列

df  = pd.DataFrame(s)
df['count'] = df['col'].apply(rolling_count) #new column in dataframe
Run Code Online (Sandbox Code Playgroud)

df的输出

  col  count
0   B      1
1   B      2
2   A      1
3   A      2
4   A      3
5   B      1
Run Code Online (Sandbox Code Playgroud)