Python 如何基于一组行在DataFrame中创建新列

Python 如何基于一组行在DataFrame中创建新列,python,pandas,dataframe,pandas-groupby,Python,Pandas,Dataframe,Pandas Groupby,我有以下数据框: import pandas as pd cols = 'id,seq,msg'.split(',') data = [ ['001',1,'abc aaa'], ['001',2,'bcd bbb'], ['001',3,'cde ccc'], ['001',1,'def ddd'], ['001',2,'efg eee'], ['001',3,'fgh fff'],

我有以下数据框:

import pandas as pd
cols = 'id,seq,msg'.split(',')

data = [
        ['001',1,'abc aaa'],
        ['001',2,'bcd bbb'],
        ['001',3,'cde ccc'],
        ['001',1,'def ddd'],
        ['001',2,'efg eee'],
        ['001',3,'fgh fff'],
        ['001',4,'ghi ggg'],
        ['002',1,'hij hhh'],
        ['002',2,'ijk iii'],
        ['002',3,'jkl jjj']
]
df = pd.DataFrame(data,columns=cols)
print(df)
输出:

    id  seq      msg
0  001    1  abc aaa
1  001    2  bcd bbb
2  001    3  cde ccc
3  001    1  def ddd
4  001    2  efg eee
5  001    3  fgh fff
6  001    4  ghi ggg
7  002    1  hij hhh
8  002    2  ijk iii
9  002    3  jkl jjj
如何获得如下输出:

    id  seq      msg msg_num
0  001    1  abc aaa     1
1  001    2  bcd bbb     1
2  001    3  cde ccc     1
3  001    1  def ddd     2
4  001    2  efg eee     2
5  001    3  fgh fff     2
6  001    4  ghi ggg     2
7  002    1  hij hhh     3
8  002    2  ijk iii     3
9  002    3  jkl jjj     3

在上述数据框中,id 001下有两条消息,id 002下有一条消息。seq字段在id字段之后排序。多行消息字段创建一条消息。每当一条新消息启动时,seq会发生变化。

IIUC,每次df.seq重新启动时,您都会计算一条新消息,因此您可以执行以下操作:

df['msg_num'] = df.groupby([e - i for i, e in enumerate(df.seq)], sort=False).ngroup() + 1
print(df)
输出

这里的关键思想是:

[e - i for i, e in enumerate(df.seq)]
帮助您识别连续的递增运行。作为替代方案,您可以:

df['msg_num'] = df.groupby(df.seq - df.seq.index, sort=False).ngroup() + 1

IIUC,每次df.seq重新启动时,您都会计算一条新消息,因此您可以执行以下操作:

df['msg_num'] = df.groupby([e - i for i, e in enumerate(df.seq)], sort=False).ngroup() + 1
print(df)
输出

这里的关键思想是:

[e - i for i, e in enumerate(df.seq)]
帮助您识别连续的递增运行。作为替代方案,您可以:

df['msg_num'] = df.groupby(df.seq - df.seq.index, sort=False).ngroup() + 1
IIUC

IIUC

使用:

如果不总是以1开头:

#import numpy as np
df['msg_num']=(df.seq<df.seq.shift(fill_value=np.inf)).cumsum()
print(df)

   id  seq      msg  msg_num
0   1    1  abc aaa        1
1   1    2  bcd bbb        1
2   1    3  cde ccc        1
3   1    1  def ddd        2
4   1    2  efg eee        2
5   1    3  fgh fff        2
6   1    4  ghi ggg        2
7   2    1  hij hhh        3
8   2    2  ijk iii        3
9   2    3  jkl jjj        3
使用:

如果不总是以1开头:

#import numpy as np
df['msg_num']=(df.seq<df.seq.shift(fill_value=np.inf)).cumsum()
print(df)

   id  seq      msg  msg_num
0   1    1  abc aaa        1
1   1    2  bcd bbb        1
2   1    3  cde ccc        1
3   1    1  def ddd        2
4   1    2  efg eee        2
5   1    3  fgh fff        2
6   1    4  ghi ggg        2
7   2    1  hij hhh        3
8   2    2  ijk iii        3
9   2    3  jkl jjj        3

我很困惑我们应该如何理解创建msg_num列背后的逻辑。当seq字段值更改为1时,意味着新消息已经开始。这就是我获取数据的方式,我需要为每条消息分配一个号码,以便进一步处理。感谢大家回答这个问题。在几个答案中,我不得不选择一个。我对我掌握的数据进行了一些测试。我无法复制粘贴测试和结果,因为它们是在受限制的计算机上完成的。因此,我只是在这里键入结果,以便对其他行有用:在116700行上,df['msg_num']=df.seq.diff.ne1.cumsum和df['msg_num']=df.seq.diff.lt0.cumsum.add1花费了零秒,df['msg_num']=1.cumsum花费了0.016秒,df['msg_num']=df']=df.groupby[e-I代表枚举df.seq中的I,e],sort=False.ngroup+1花费了0.14秒。我很困惑我们应该如何理解创建msg_num列背后的逻辑。当seq字段值更改为1时,意味着新消息已经开始。这就是我获取数据的方式,我需要为每条消息分配一个号码,以便进一步处理。感谢大家回答这个问题。在几个答案中,我不得不选择一个。我对我掌握的数据进行了一些测试。我无法复制粘贴测试和结果,因为它们是在受限制的计算机上完成的。因此,我只是在这里键入结果,以便对其他行有用:在116700行上,df['msg_num']=df.seq.diff.ne1.cumsum和df['msg_num']=df.seq.diff.lt0.cumsum.add1花费了零秒,df['msg_num']=1.cumsum花费了0.016秒,df['msg_num']=df']=df.groupby[e-I代表枚举df.seq中的I,e],sort=False.n组+1花费了0.14秒。哈哈!我的只是和你的稍有不同,而且晚了一分钟。我删除了我的,向上投你的:df.seq.diff.ne1.cumsumhah!我的只是和你的稍有不同,而且晚了一分钟。我删除了我的,向上投你的:df.seq.diff.ne1.cumsumYes,你的理解是正确的。我相信,当数据帧将有数百万行时,您的替代解决方案将比使用for循环的解决方案花费更少的时间来计算。是的,@Daniel,好主意。我将在真实数据上测试所有解决方案。我只是有一个示例DF在运行,但没有帮助。是的,您的理解是正确的。我相信,当数据帧将有数百万行时,您的替代解决方案将比使用for循环的解决方案花费更少的时间来计算。是的,@Daniel,好主意。我将在真实数据上测试所有解决方案。我只是有一个样本DF上运行,没有帮助。