TL; DR:在熊猫中,最好的方法是根据给定的标准将一行拆分为几行,并根据拆分的值进行一些更改?
我有以下数据框:
description value country
0 pen number 29143 for client X 100 France
1 pen num 99523 90 UK
2 pen 58123 and pen 88421 250 Spain
3 pen 10594 for Mr Smith 145 Italy
4 pen number 19534, 94212 and 55645 285 Germany
我知道笔ID是该字段中唯一的5位代码。我想“拆分”具有多个ID的行并平均分配值,同时保持其他字段相同:
id value country
0 29143 100 France
1 99523 90 UK
2 58123 125 Spain
3 88421 125 Spain
4 10594 145 Italy
5 19534 95 Germany
6 94212 95 Germany
7 55645 95 Germany
我对此有一个可行的方法,但是它会创建多个字典,而且看起来并没有做到这一点的最佳,最有效的方法。看起来像这样:
(这使用基本的re来识别字符串中的5位ID)
首先,我创建“ id”列,并填写所有单ID字段。
df['id'] = df['description'].apply(lambda x: re.findall('\d'*5,x)[0] if len(set(re.findall('\d'*5,x))) == 1 else None)
然后我创建一个索引字典:ID列表,用于具有多个ID的描述
multiple_id_dict = {}
for i in df.index:
ids = list(set(re.findall('\d'*5, df.loc[i, 'description'])))
if len(ids) > 1:
multiple_id_dict[i] = ids
此后,对于每个索引,我在数据框中创建该行的字典,然后将每个值自身转换为五倍的列表(保留其他数据)。然后,我为dict分配正确的ID和值,将其转换为数据帧并将其附加到原始帧。最后,我删除了原始行(现在已拆分)。
for i in multiple_id_dict:
id_list = multiple_id_dict[i]
row_dict = df.loc[i].to_dict()
row_dict_sep = {x: [row_dict[x]]*len(id_list) for x in row_dict}
row_dict_sep['id'] = [x for x in id_list]
row_dict_sep['value'] = [row_dict['value']/len(id_list)]*len(id_list)
df = df.append(pd.DataFrame(row_dict_sep), sort=True)
df = df.drop(i)
这似乎很令人费解。是否存在一种更简单或矢量方式的“拆分”行,并带有某种“ agg”来确定对行中每个值的处理方式?
PS:复制/粘贴以获取示例数据框的代码:
df = pd.DataFrame({'description': ['pen number 29143 for client X','pen num 99523','pen 58123 and pen 88421','pen 10594 for Mr Smith','pen number 19534, 94212 and 55645'],'value': [100, 90, 250, 145, 285], 'country':['France','UK','Spain','Italy','Germany']})
答案 0 :(得分:3)
将Series.str.extractall
与正则表达式(\d{5})
一起用于一列DataFrame
,DataFrame.join
的五位数字,并将GroupBy.transform
创建的计数除以相同大小的每组像原始数据一样:
df1 = df.pop('description').str.extractall(r'(\d{5})').reset_index(level=1, drop=True)
print (df1)
0
0 29143
1 99523
2 58123
2 88421
3 10594
4 19534
4 94212
4 55645
df = df1.rename(columns={0:'id'}).join(df)
df['value'] /= df.groupby(level=0)['value'].transform('size')
df = df.reset_index(drop=True)
print (df)
id value country
0 29143 100.0 France
1 99523 90.0 UK
2 58123 125.0 Spain
3 88421 125.0 Spain
4 10594 145.0 Italy
5 19534 95.0 Germany
6 94212 95.0 Germany
7 55645 95.0 Germany