熊猫:重塑数据框

时间:2020-04-01 10:34:58

标签: python pandas dataframe

我有一个与熊猫有关的问题。我的数据框看起来像这样:

  id val1 val2
0  1     0    1
1  1     1    0
2  1     0    0
3  2     1    1
4  2     1    1
5  2     1    0
6  3     0    0
7  3     0    1
8  3     1    1
9  4     1    0
10 4     0    1
11 4     0    0

我想将其转换为类似的内容:

             a         b        c
   id     a0   a1   b0   b1   c0   c1
    1     0    1    1    0    0    0
    2     1    1    1    1    1    0
    3     0    0    1    1    1    1
    4     1    0    0    1    0    0

我想到了类似添加一个由a,b和c循环枚举的sub_id列的操作,然后对框架进行拆栈。有没有更简单/更智能的解决方案?

非常感谢!

蒂姆

2 个答案:

答案 0 :(得分:2)

如果可能的数字不是abc,而是使用GroupBy.cumcount作为计数器,则通过DataFrame.set_index创建MultiIndex并通过DataFrame.unstack进行整形,最后用{{ 3}}:

g = df.groupby('id').cumcount()

df = df.set_index(['id', g]).unstack().sort_index(axis=1, level=1).swaplevel(0,1,axis=1)
print (df)
      0         1         2     
   val1 val2 val1 val2 val1 val2
id                              
1     0    1    1    0    0    0
2     1    1    1    1    1    0
3     0    0    0    1    1    1
4     1    0    0    1    0    0

如果可能需要a,b,c值,请从string.ascii_lowercaserename列生成字典:

import string

d = dict(enumerate(string.ascii_lowercase))
df = df.rename(columns=d)
print (df)
      a         b         c     
   val1 val2 val1 val2 val1 val2
id                              
1     0    1    1    0    0    0
2     1    1    1    1    1    0
3     0    0    0    1    1    1
4     1    0    0    1    0    0

重命名两个级别的解决方案是先在set_index之后按范围创建默认列名称:

g = df.groupby('id').cumcount()
df = df.set_index(['id', g])
df.columns = range(len(df.columns))
df = df.unstack().sort_index(axis=1, level=1).swaplevel(0,1,axis=1)
print (df)
    0     1     2   
    0  1  0  1  0  1
id                  
1   0  1  1  0  0  0
2   1  1  1  1  1  0
3   0  0  0  1  1  1
4   1  0  0  1  0  0

列表理解中的最后一个设置新值:

import string

d = dict(enumerate(string.ascii_lowercase))
df.columns = pd.MultiIndex.from_tuples([(d[a], f'{d[a]}{b}') for a, b in df.columns])
print (df)
    a     b     c   
   a0 a1 b0 b1 c0 c1
id                  
1   0  1  1  0  0  0
2   1  1  1  1  1  0
3   0  0  0  1  1  1
4   1  0  0  1  0  0

答案 1 :(得分:0)

可能的解决方案之一:

从将每个 id 的值重新格式化为一行:

res = df.set_index('id').groupby('id').apply(
    lambda grp: pd.Series(grp.values.flatten()))

目前的结果是:

    0  1  2  3  4  5
id                  
1   0  1  1  0  0  0
2   1  1  1  1  1  0
3   0  0  0  1  1  1
4   1  0  0  1  0  0

然后设置适当的列名称:

res.columns = pd.MultiIndex.from_tuples(
    [(x, x + y) for x in list('abc') for y in list('01')])

结局结果是:

    a     b     c   
   a0 a1 b0 b1 c0 c1
id                  
1   0  1  1  0  0  0
2   1  1  1  1  1  0
3   0  0  0  1  1  1
4   1  0  0  1  0  0