我有一个如下数据框:
df = pd.DataFrame({'var1': ['0,3788,99,20.88', '3,99022,08,91.995'],
'var2': ['0,929,92,299.90', '1,38333,9,993.11'],
'var3': ['8,9332,99,29.10', '7,922111,07,45.443']})
Out[248]:
var1 var2 var3
0 0,3788,99,20.88 0,929,92,299.90 8,9332,99,29.10
1 3,99022,08,91.995 1,38333,9,993.11 7,922111,07,45.443
我想用逗号分割每一列,并将新的一组列彼此相邻。因此,结果数据框应如下所示:
df2 = pd.DataFrame({('var1', 'x1'): [0, 3], ('var1', 'x2'): [3788, 99022], ('var1', 'x3'): [99, '08'], ('var1', 'x4'): [20.88, 91.995],
('var2', 'x1'): [0, 1], ('var2', 'x2'): [929, 38333], ('var2', 'x3'): [92, 9], ('var2', 'x4'): [299.90, 993.11],
('var3', 'x1'): [8, 7], ('var3', 'x2'): [9332, 922111], ('var3', 'x3'): [99, '07'], ('var3', 'x4'): [29.10, 45.443]})
Out[249]:
var1 var2 var3
x1 x2 x3 x4 x1 x2 x3 x4 x1 x2 x3 x4
0 0 3788 99 20.880 0 929 92 299.90 8 9332 99 29.100
1 3 99022 08 91.995 1 38333 9 993.11 7 922111 07 45.443
MultiIndex
不是强制性的,但是我想有机会轻松地收集数据并在需要时获取df3:
var x1 x2 x3 x4
0 var1 0 3788 99 20.880
1 var1 3 99022 08 91.995
0 var2 0 929 92 299.900
1 var2 1 38333 9 993.110
0 var3 8 9332 99 29.100
1 var3 7 922111 07 45.443
我的努力包括pd.melt
和str.split
:
df_long = pd.melt(df.reset_index(drop = False), id_vars = 'index', var_name = 'var', value_name = 'values') \
.sort_values(['index', 'var']) \
.set_index('index')
df_long = df_long['values'].str.split(',', expand = True)
df_long.columns = ['x' + str(i) for i in range(df_long.shape[1])]
但是:
1)我不知道该如何分散彼此相邻的var1, var2, var3...
的数据
2)从宽格式转换为长格式(从df
到df_long
)然后再返回(从df_long
到df3
)似乎效率很低,我希望通过寻找解决方案来提高性能
那么从df
到df2
的最佳转换方法是什么,以便我们可以在需要时轻松获得df3
?
答案 0 :(得分:1)
您可以将stack
,str.split()
与expand=True
和unstack()
结合使用来实现此目的:
final=(df.stack().str.split(',',expand=True).unstack().swaplevel(axis=1)
.sort_index(level=0,axis=1))
print(final)
var1 var2 var3
0 1 2 3 0 1 2 3 0 1 2 3
0 0 3788 99 20.88 0 929 92 299.90 8 9332 99 29.10
1 3 99022 08 91.995 1 38333 9 993.11 7 922111 07 45.443
要重命名列的第0级,请使用;
final.columns=pd.MultiIndex.from_tuples([(a,f'x{b}') for a,b in final.columns])
var1 var2 var3
x0 x1 x2 x3 x0 x1 x2 x3 x0 x1 x2 x3
0 0 3788 99 20.88 0 929 92 299.90 8 9332 99 29.10
1 3 99022 08 91.995 1 38333 9 993.11 7 922111 07 45.443
您也可以将以下内容用于问题中显示的第二个输出:
df.stack().str.split(',',expand=True).add_prefix('x').reset_index(1).reset_index(drop=True)
level_1 x0 x1 x2 x3
0 var1 0 3788 99 20.88
1 var2 0 929 92 299.90
2 var3 8 9332 99 29.10
3 var1 3 99022 08 91.995
4 var2 1 38333 9 993.11
5 var3 7 922111 07 45.443
答案 1 :(得分:1)
以下是首先获取df3的方法:
df3 = pd.concat([df[s].str.split(',', expand=True).add_prefix("x").assign(var=s) for s in df])
print(df3)
x0 x1 x2 x3 var
0 0 3788 99 20.88 var1
1 3 99022 08 91.995 var1
0 0 929 92 299.90 var2
1 1 38333 9 993.11 var2
0 8 9332 99 29.10 var3
1 7 922111 07 45.443 var3
然后:
df2 = df3.set_index("var", append=True).unstack().swaplevel(axis=1).sort_index(axis=1)
print(df2)
var var1 var2 var3
x0 x1 x2 x3 x0 x1 x2 x3 x0 x1 x2 x3
0 0 3788 99 20.88 0 929 92 299.90 8 9332 99 29.10
1 3 99022 08 91.995 1 38333 9 993.11 7 922111 07 45.443
答案 2 :(得分:0)
定义用于重新格式化单个单元格的功能的起始表格:
def refCell(cell, ind1):
tbl = cell.split(',')
ind2 = [ 'x' + str(i) for i in range(1, len(tbl) + 1) ]
ind = pd.MultiIndex.from_product([[ind1], ind2])
return pd.Series(tbl, index=ind)
它会创建一个系列,其值是通过拆分单元格得到的, 带有MultiIndex,其中:
要定义的第二个函数是重新格式化行的函数:
def refRow(row):
return pd.concat([ refCell(val, idx) for idx, val in row.iteritems() ])
然后,要获取结果,请将此函数(应用于每一行):
df.apply(refRow, axis=1)