在pandas DataFram中将列表分割为多列

2024-06-11 18:50:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个提供如下数据的源系统:

Name    |Hobbies
----------------------------------
"Han"   |"Art;Soccer;Writing"
"Leia"  |"Art;Baking;Golf;Singing"
"Luke"  |"Baking;Writing"

每个爱好列表都用分号分隔。我想把它变成一个类似表格的结构,每个爱好都有一个列,并有一个标志来指示是否有人选择了这个爱好:

^{pr2}$

下面是在pandas数据帧中生成示例数据的代码:

>>> import pandas as pd
>>> df = pd.DataFrame(
...     [
...         {'name': 'Han',   'hobbies': 'Art;Soccer;Writing'},
...         {'name': 'Leia',  'hobbies': 'Art;Baking;Golf;Singing'},
...         {'name': 'Luke',  'hobbies': 'Baking;Writing'},
...     ]
... )
>>> df
                   hobbies  name
0       Art;Soccer;Writing   Han
1  Art;Baking;Golf;Singing  Leia
2           Baking;Writing  Luke

现在,我使用下面的代码将数据放入具有我想要的结构的datatrame中,但它的速度非常慢(我的实际数据集大约有150万行):

>>> df2 = pd.DataFrame(columns=['name', 'hobby'])
>>>
>>> for index, row in df.iterrows():
...     for value in str(row['hobbies']).split(';'):
...         d = {'name':row['name'], 'value':value}
...         df2 = df2.append(d, ignore_index=True)
...
>>> df2 = df2.groupby('name')['value'].value_counts()
>>> df2 = df2.unstack(level=-1).fillna(0)
>>>
>>> df2
value  Art  Baking  Golf  Singing  Soccer  Writing
name
Han    1.0     0.0   0.0      0.0     1.0      1.0
Leia   1.0     1.0   1.0      1.0     0.0      0.0
Luke   0.0     1.0   0.0      0.0     0.0      1.0

有没有更有效的方法?在


Tags: 数据namevaluepddf2lukeartwriting
3条回答

为什么不直接改变数据帧呢?在

for idx, row in df.iterrows():
    for hobby in row.hobbies.split(";"):
        df.loc[idx, hobby] = True

df.fillna(False, inplace=True)

实际上,使用^{}和{a2}应该比使用iterrows循环要快得多。在

  1. 拆分为多个列:

    >>> df = pd.DataFrame([{'name': 'Han', 'hobbies': 'Art;Soccer;Writing'}, 
                           {'name': 'Leia', 'hobbies': 'Art;Baking;Golf;Singing'},
                           {'name': 'Luke', 'hobbies': 'Baking;Writing'}])
    >>> hobbies = df['hobbies'].str.split(';', expand=True)
    >>> hobbies
        0          1       2       3
    0 Art     Soccer Writing    None
    1 Art     Baking    Golf Singing
    2 Baking Writing    None    None 
    
  2. 按名字取消兴趣爱好:

    >>> df = df.drop('hobbies', axis=1)
    >>> df = df.join(hobbies)
    >>> stacked = df.melt('name', value_name='hobby').drop('variable', axis=1)
    >>> stacked
       name   hobby
     0  Han     Art
     1 Leia     Art
     2 Luke  Baking
     3  Han  Soccer
     4 Leia  Baking
     5 Luke Writing
     6  Han Writing
     7 Leia    Golf
     8 Luke    None
     9  Han    None
    10 Leia Singing
    11 Luke    None
    
  3. 计算数值:

    >>> counts = stacked.groupby('name')['hobby'].value_counts()
    >>> result = counts.unstack(level=-1).fillna(0).astype(int)
    >>> result
    hobby Art Baking Golf Singing Soccer Writing
    name                        
     Han    1      0    0       0      1       1
    Leia    1      1    1       1      0       0
    Luke    0      1    0       0      0       1
    

第2步和第3步还有其他选择,比如使用^{}^{},正如这里讨论的:Pandas get_dummies on multiple columns,但是第一步会占用你的内存,第二步要慢得多。在


参考文献:
Pandas split column into multiple columns by comma
Pandas DataFrame stack multiple column values into single column

您可以做的不是在每次迭代中追加列,而是在运行循环后追加所有列:

df3 = pd.DataFrame(columns=['name', 'hobby'])
d_list = []

for index, row in df.iterrows():
    for value in str(row['hobbies']).split(';'):
        d_list.append({'name':row['name'], 
                       'value':value})
df3 = df3.append(d_list, ignore_index=True)
df3 = df3.groupby('name')['value'].value_counts()
df3 = df3.unstack(level=-1).fillna(0)
df3

我检查了这个示例dataframe需要多少时间。经过改进,我建议它快50倍左右。在

相关问题 更多 >