2017-09-03 105 views
1

我有一个大熊猫数据框,其中有多个多值列。这些列的名称中包含“/”,这些列中的值也由“/”分隔。以下是这种数据框的一个最基本的代表性示例。熊猫:基于分隔符名称的拆分多值列

 Name North/South East/West No1/No2/No3 
0  ABC   0/1   0/0  10/3/6 
1  XYZ   1/0   0/1   4/5/6 
2  PQR   1/0   0/1   3/6/6 

我想分割列。直接的方法是创建一个新列,然后沿索引的长度迭代,并沿每个元素填充分割的字符串。但是我必须对所有多值列进行硬编码。

有没有更一般的方法来做到这一点?也许扫描df.columns,然后如果一个元素包含“/”,运行另一个函数来分解该列?对于上面的数据帧,所需的输出如下。

 Name North South East West No1 No2 No3 
0  ABC  0  1  0  0 10 3 6 
1  XYZ  1  0  0  1 4 5 6 
2  PQR  1  0  0  1 3 6 6 

回答

0
#get columns not contains/and set index 
cols = df.columns[~df.columns.str.contains('/')].tolist() 
df = df.set_index(cols) 
print (df) 
    North/South East/West No1/No2/No3 
Name           
ABC   0/1  0/0  10/3/6 
XYZ   1/0  0/1  4/5/6 
PQR   1/0  0/1  3/6/6 

#create new columns names 
c = df.columns.to_series().str.split('/', expand=True).stack().values.tolist() 
print (c) 
['North', 'South', 'East', 'West', 'No1', 'No2', 'No3'] 

#list comprehension with split to df and concat output 
df = pd.concat([df[x].str.split('/', expand=True) for x in df], axis=1) 
print (df) 
     0 1 0 1 0 1 2 
Name      
ABC 0 1 0 0 10 3 6 
XYZ 1 0 0 1 4 5 6 
PQR 1 0 0 1 3 6 6 

#assign new columns names 
df.columns = c 
df = df.reset_index() 
print (df) 
    Name North South East West No1 No2 No3 
0 ABC  0  1 0 0 10 3 6 
1 XYZ  1  0 0 1 4 5 6 
2 PQR  1  0 0 1 3 6 6 

时序

df = pd.concat([df]*1000).reset_index(drop=True) 
print (df) 

def f(df): 
    return pd.concat([s.str.split('/').apply(pd.Series, index=c.split('/')) for c, s in df.set_index('Name').iteritems()], axis=1).reset_index() 
print (f(df)) 

def f1(df): 
    cols = df.columns[~df.columns.str.contains('/')].tolist() 
    df = df.set_index(cols) 
    c = df.columns.to_series().str.split('/', expand=True).stack().values.tolist() 
    df = pd.concat([df[x].str.split('/', expand=True) for x in df], axis=1) 
    df.columns = c 
    return df.reset_index() 
print (f1(df)) 

In [142]: %timeit (f(df)) 
1 loop, best of 3: 2.6 s per loop 

In [143]: %timeit (f1(df)) 
10 loops, best of 3: 27.5 ms per loop 
+0

感谢您的解决方案。我遇到了一些问题。我想用df = df.set_index(cols)你已经改变了df。因此,当我运行c = df.columns.to_series()。str.split('/',expand = True).stack()。值时,它会引发错误。你能再次检查解决方案吗? – Spinor8

+0

什么样的错误? – jezrael

+0

没关系。我的错误。再次感谢。 – Spinor8

1

这里有一个方法

In [1417]: pd.concat([s.str.split('/').apply(pd.Series, index=c.split('/')) 
        for c, s in df.set_index('Name').iteritems()], 
        axis=1).reset_index() 
Out[1417]: 
    Name North South East West No1 No2 No3 
0 ABC  0  1 0 0 10 3 6 
1 XYZ  1  0 0 1 4 5 6 
2 PQR  1  0 0 1 3 6 6 
+0

感谢您的解决方案。它确实适用于玩具的例子,但Jezrael的更普遍。 – Spinor8