如何在熊猫中拆分多列

时间:2019-12-08 10:52:07

标签: python pandas

我有一个如下数据框:

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.meltstr.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)从宽格式转换为长格式(从dfdf_long)然后再返回(从df_longdf3)似乎效率很低,我希望通过寻找解决方案来提高性能

那么从dfdf2的最佳转换方法是什么,以便我们可以在需要时轻松获得df3

3 个答案:

答案 0 :(得分:1)

您可以将stackstr.split()expand=Trueunstack()结合使用来实现此目的:

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,其中:

  • 第一级是 ind1
  • 第二层是 x1 x2 等(字符串列表)。

要定义的第二个函数是重新格式化的函数:

def refRow(row):
    return pd.concat([ refCell(val, idx) for idx, val in row.iteritems() ])

然后,要获取结果,请将此函数(应用于每一行):

df.apply(refRow, axis=1)