正确分割熊猫行的方法

时间:2019-04-03 13:28:02

标签: python python-3.x pandas

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']})

1 个答案:

答案 0 :(得分:3)

Series.str.extractall与正则表达式(\d{5})一起用于一列DataFrameDataFrame.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