根据条件Python对多行进行分组

时间:2016-12-12 17:10:21

标签: python function pandas group-by

“名称”列包含一行中的人名,后面是他们需要执行的编号任务(带有小描述),所有任务都与该人名相关联,直到出现另一个人名(所以汤姆全部他的名字下面的任务与汤姆相关,直到吉姆出现,然后吉姆与他的名字之后的所有任务相关联,直到下一个名字......等等)。以下是我的数据示例:

Name                       Three Digit Task    Number of Days

Tom                        BLANK               0.00
1.1.6.1 Task Description   1.1.6               9.00
1.1.6.2 Task Description   1.1.6               8.25
1.1.1.4 Task Description   1.1.1               13.25
Jim                        BLANK               0.00
1.1.3.1 Task Description   1.1.3               8.75
1.2.1.1 Task Description   1.2.1               6.00
1.2.1.2 Task Description   1.2.1               12.75

所以我想得到每个人的天数总和,按三位数任务分组。希望它看起来像这样:

Tom      1.1.1     13.25
Tom      1.1.6     17.25
Jim      1.1.3     8.75
Jim      1.2.1     18.75

所以我尝试过使用:

import string
ALPHA = string.ascii_letters
df['Name'].str.startswith(tuple(ALPHA))

如果“名称”列以字母开头,则返回true / false(字母为True,否则为false)。试图说出这样的话:在真实(这将是人民的名字)之间通过分组'三位数任务'来总结'天数'

1 个答案:

答案 0 :(得分:1)

<强> TL;博士

name_bool = df.Name.str.match('^[a-zA-Z]')
grp_keys = name_bool.cumsum()
grps = df.groupby(grp_keys)
tdt = 'Three Digit Task'
nod = 'Number of Days'

funcs = {'Name': 'first', nod: 'sum'}
dicts = {g.iloc[0, 0]: g.tail(-1).groupby(tdt).agg(funcs) for _, g in grps}
pd.concat(dicts)

enter image description here

<强> 解释
使用regex查找哪些行的Name列以字母开头。

name_bool = df.Name.str.match('^[a-zA-Z]')
name_bool  

0     True
1    False
2    False
3    False
4     True
5    False
6    False
7    False
Name: Name, dtype: bool

使用cumsumName

之后的每个连续行集创建唯一编号
grp_keys = name_bool.cumsum()
grp_keys

0    1
1    1
2    1
3    1
4    2
5    2
6    2
7    2
Name: Name, dtype: int64

创建pandas groupby对象
grps = df.groupby(grp_keys)

使用aggpd.concat创建最终pd.DataFrame

funcs = {'Name': 'first', nod: 'sum'}
dicts = {g.iloc[0, 0]: g.tail(-1).groupby(tdt).agg(funcs) for _, g in grps}
pd.concat(dicts)

enter image description here