将组上的顺序计数器列添加到 pandas 数据帧

Add a sequential counter column on groups to a pandas dataframe

提问人:Owen 提问时间:5/3/2014 最后编辑:cottontailOwen 更新时间:8/10/2023 访问量:48627

问:

我觉得有比这更好的方法:

import pandas as pd
df = pd.DataFrame(
    columns="   index    c1    c2    v1 ".split(),
    data= [
            [       0,  "A",  "X",    3, ],
            [       1,  "A",  "X",    5, ],
            [       2,  "A",  "Y",    7, ],
            [       3,  "A",  "Y",    1, ],
            [       4,  "B",  "X",    3, ],
            [       5,  "B",  "X",    1, ],
            [       6,  "B",  "X",    3, ],
            [       7,  "B",  "Y",    1, ],
            [       8,  "C",  "X",    7, ],
            [       9,  "C",  "Y",    4, ],
            [      10,  "C",  "Y",    1, ],
            [      11,  "C",  "Y",    6, ],]).set_index("index", drop=True)
def callback(x):
    x['seq'] = range(1, x.shape[0] + 1)
    return x
df = df.groupby(['c1', 'c2']).apply(callback)
print df

为此,请执行以下操作:

   c1 c2  v1  seq
0   A  X   3    1
1   A  X   5    2
2   A  Y   7    1
3   A  Y   1    2
4   B  X   3    1
5   B  X   1    2
6   B  X   3    3
7   B  Y   1    1
8   C  X   7    1
9   C  Y   4    1
10  C  Y   1    2
11  C  Y   6    3

有没有办法避免回调?

熊猫 数据帧 分组依据 运行计数

评论


答:

125赞 Jeff 5/3/2014 #1

使用,请参阅此处的文档cumcount()

In [4]: df.groupby(['c1', 'c2']).cumcount()
Out[4]: 
0     0
1     1
2     0
3     1
4     0
5     1
6     2
7     0
8     0
9     0
10    1
11    2
dtype: int64

如果您希望从 1 开始订购

In [5]: df.groupby(['c1', 'c2']).cumcount()+1
Out[5]: 
0     1
1     2
2     1
3     2
4     1
5     2
6     3
7     1
8     1
9     1
10    2
11    3
dtype: int64
2赞 Shaina Raza 5/12/2020 #2

这可能很有用

df = df.sort_values(['userID', 'date'])
grp = df.groupby('userID')['ItemID'].aggregate(lambda x: '->'.join(tuple(x))).reset_index()
print(grp)

它将创建这样的序列enter image description here

2赞 cottontail 9/13/2022 #3

如果您有一个类似于下面的数据帧,并且您想通过从 or 构建它来添加列,即在其他列中保留类似值的运行计数(或直到出现标志),请继续阅读。seqc1c2

df = pd.DataFrame(
    columns="  c1      c2    seq".split(),
    data= [
            [ "A",      1,    1 ],
            [ "A1",     0,    2 ],
            [ "A11",    0,    3 ],
            [ "A111",   0,    4 ],
            [ "B",      1,    1 ],
            [ "B1",     0,    2 ],
            [ "B111",   0,    3 ],
            [ "C",      1,    1 ],
            [ "C11",    0,    2 ] ])

然后首先找到组起始器,(下面使用(和)但可以使用任何创建布尔级数的方法,例如 、 等)并调用它来创建一个级数,其中每个组都有一个唯一的标识值。然后将其用作操作中的石斑鱼。str.contains()eq()lt()ne()isna()cumsum()groupby().cumsum()

总之,请使用类似于以下代码的代码。

# build a grouper Series for similar values
groups = df['c1'].str.contains("A$|B$|C$").cumsum()

# or build a grouper Series from flags (1s)
groups = df['c2'].eq(1).cumsum()

# groupby using the above grouper
df['seq'] = df.groupby(groups).cumcount().add(1)
0赞 CreekGeek 1/21/2023 #4

Jeff 的回答很简洁,但我更喜欢明确地排序......尽管通常不会覆盖这些类型的用例的 DF(例如 Shaina Raza 的答案)。

因此,要在每个(“c1”、“c2”)组中创建一个按“v1”排序的新列:

df["seq"] = df.sort_values(by=['c1','c2','v1']).groupby(['c1','c2']).cumcount()

您可以通过以下方式查看:

df.sort_values(by=['c1','c2','seq'])

或者,如果要覆盖 DF,则:

df = df.sort_values(by=['c1','c2','seq']).reset_index()
0赞 Siddhant Raj Mishra 8/7/2023 #5

您可以使用 groupby 和 cumcount 函数来实现所需的结果。

import pandas as pd

data = {'col': ['A', 'B', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'A']}
df = pd.DataFrame(data)

df['counts'] = df.groupby('col').cumcount() + 1

df