熊猫:基于分隔符名称的拆分多值列
问题描述:
我有一个大熊猫数据框,其中有多个多值列。这些列的名称中包含“/”,这些列中的值也由“/”分隔。以下是这种数据框的一个最基本的代表性示例。熊猫:基于分隔符名称的拆分多值列
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
答
#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
答
这里有一个方法
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
感谢您的解决方案。我遇到了一些问题。我想用df = df.set_index(cols)你已经改变了df。因此,当我运行c = df.columns.to_series()。str.split('/',expand = True).stack()。值时,它会引发错误。你能再次检查解决方案吗? – Spinor8
什么样的错误? – jezrael
没关系。我的错误。再次感谢。 – Spinor8