“名称”列在一行中包含一个人员名称,后跟他们需要执行的编号任务(带有简短描述),所有任务都与该人员名称相关联,直到出现另一个人员名称为止(因此,汤姆拥有以下所有任务他的名字与Tom关联,直到Jim出现为止,然后Jim与他名字之后的所有任务(直到下一个名字……等等)关联。所以这是我拥有的数据的示例:
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)。试图说出这样的话:在真值之间(可能是人的名字),通过对“三位数任务”进行分组来求和“天数”
最佳答案
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)
说明
使用
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
使用
cumsum
为Name
之后的每个连续行创建唯一编号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
创建熊猫
groupby
对象grps = df.groupby(grp_keys)
使用
agg
和pd.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)