使用pandas将单元格内容扩展为列名的最快方法是什么?

时间:2017-10-01 11:18:04

标签: python pandas dataframe

我的数据采用以下格式:

index                 keys    
1                    key 1
2      key 1\nkey 2\nkey 3
3      key 2\nkey 4\nkey 5
5      key 2\nkey 3\nkey 5

我感兴趣的关键字位于键列中,以\n分隔。我想将每个密钥转换为列名称,并使用True1标记来自其所在位置的行,如下所示:

index                   key 1   key 2   key 3   key 4   key 5
1                       1       0       0       0       0
2                       1       1       1       0       0
3                       0       1       0       1       1
5                       0       1       1       0       1

现在,我做的是迭代索引,将每行的键列表保存到字典中,然后使用pandas.DataFrame.from_dict转换重新导入它,如下所示:

 l=[]
 for i in df.index:
     d={j:True for j in df["keys"][i].split("\n")}    
     l.append(d)
 new_df=pandas.DataFrame(l)

它非常快,但由于有很多NaN,因此在将数据帧转换为int64类型之前,数据帧的内存消耗量非常大。然而,我有几十万行。有没有人知道一种更有效的方法,如果可能的话,可以避免自己迭代行?

2 个答案:

答案 0 :(得分:3)

这是理解的一种方式

In [5442]: pd.DataFrame([{k:1 for k in x.split('\\n')} for x in df['keys']]).fillna(0)
Out[5442]:
   key 1  key 2  key 3  key 4  key 5
0    1.0    0.0    0.0    0.0    0.0
1    1.0    1.0    1.0    0.0    0.0
2    0.0    1.0    0.0    1.0    1.0
3    0.0    1.0    1.0    0.0    1.0

使用apply的另一种方式,在较大的数据上会慢一些

In [5429]: df['keys'].apply(lambda x: pd.Series({k:1 for k in x.split('\\n')})
                           ).fillna(0).astype(int)
Out[5429]:
   key 1  key 2  key 3  key 4  key 5
0      1      0      0      0      0
1      1      1      1      0      0
2      0      1      0      1      1
3      0      1      1      0      1

计时

In [5447]: dff.shape
Out[5447]: (20000, 2)

In [5444]: %timeit pd.DataFrame([{k: 1for k in x.split('\\n')} for x in dff['keys']]).fillna(0)
10 loops, best of 3: 59.6 ms per loop

In [5445]: %timeit dff['keys'].str.split(r'\\n', expand=True).stack().str.get_dummies().groupby(level=0).sum()
1 loop, best of 3: 399 ms per loop

In [5446]: %%timeit
      ...: d = pd.get_dummies(dff['keys'].str.split(r'\\n', expand=True))
      ...: d.groupby(d.columns.str.split('_').str[1], axis=1).sum()
1 loop, best of 3: 62.0 ms per loop

答案 1 :(得分:2)

选项1
str.split + stack + str.get_dummies + groupby + sum

df    
                      keys
index                     
1                    key 1
2      key 1\nkey 2\nkey 3
3      key 2\nkey 4\nkey 5
5      key 2\nkey 3\nkey 5

df['keys'].str.split('\n', expand=True).stack()\
                 .str.get_dummies().groupby(level=0).sum()

       key 1  key 2  key 3  key 4  key 5
index                                   
1          1      0      0      0      0
2          1      1      1      0      0
3          0      1      0      1      1
5          0      1      1      0      1

选项2
使用pd.get_dummies,绕过stack

d = pd.get_dummies(df['keys'].str.split('\n', expand=True))
d.groupby(d.columns.str.split('_').str[1], axis=1).sum()

       key 1  key 2  key 3  key 4  key 5
index                                   
1          1      0      0      0      0
2          1      1      1      0      0
3          0      1      0      1      1
5          0      1      1      0      1

选项3
使用stack + value_counts + unstack

df['keys'].str.split('\n', expand=True).stack()\
       .groupby(level=0).value_counts().unstack().fillna(0)

       key 1  key 2  key 3  key 4  key 5
index                                   
1        1.0    0.0    0.0    0.0    0.0
2        1.0    1.0    1.0    0.0    0.0
3        0.0    1.0    0.0    1.0    1.0
5        0.0    1.0    1.0    0.0    1.0