在多索引数据框中创建不存在的列

Creating non-exist columns in multiindex dataframe

假设我们有这样的数据框

df = pd.DataFrame({ 
                "metric": ["1","2","1" ,"1","2"],
                "group1":["o", "x", "x" , "o", "x"],
                "group2":['a', 'b', 'a', 'a', 'b'] ,
                "value": range(5),
                "value2": np.array(range(5))* 2})

df

    metric  group1  group2  value   value2
0   1         o      a         0    0
1   2         x      b         1    2
2   1         x      a         2    4
3   1         o      a         3    6
4   2         x      b         4    8

然后我想要数据透视格式

df['g'] = df.groupby(['group1','group2'])['group2'].cumcount()
df1 = df.pivot(index=['g','metric'], columns=['group1','group2'], values=['value','value2']).sort_index(axis=1).rename_axis(columns={'g':None})


            value       value2
   group1   o   x       o   x
   group2   a   a   b   a   a   b
g  metric                       
0   1       0.0 2.0 NaN 0.0 4.0 NaN
    2       NaN NaN 1.0 NaN NaN 2.0
1   1       3.0 NaN NaN 6.0 NaN NaN
    2       NaN NaN 4.0 NaN NaN 8.0

从这里我们可以看到("value","o","b")("value2","o","b")在制作pivot

后不存在

但我需要这些列的值为 NA 所以我尝试了;

cols = [('value','x','a'), ('value','o','a'),('value','o','b')]

df1.assign(**{col : "NA" for col in np.setdiff1d(cols, df1.columns.values)})

这给出了

预期输出

            value           value2
   group1   o       x       o       x
   group2   a   b   a   b   a   b   a   b
g  metric                       
0   1       0.0 NaN 2.0 NaN 0.0 NaN 4.0 NaN
    2       NaN NaN NaN 1.0 NaN NaN NaN 2.0
1   1       3.0 NaN NaN NaN 6.0 NaN NaN NaN
    2       NaN NaN NaN 4.0 NaN NaN NaN 8.0

一个极端情况是,如果 b 不存在,如何创建该列?

           value     value2
   group1   o   x    o  x
   group2   a   a    a  a   
g  metric                       
0   1       0.0 2.0  0.0 4.0    
    2       NaN NaN  NaN NaN    
1   1       3.0 NaN  6.0 NaN    
    2       NaN NaN  NaN NaN    

使用DataFrame.stack with DataFrame.unstack:

df1 = df1.stack([1,2],dropna=False).unstack([2,3])
print (df1)
         value               value2              
group1       o        x           o        x     
group2       a   b    a    b      a   b    a    b
g metric                                         
0 1        0.0 NaN  2.0  NaN    0.0 NaN  4.0  NaN
  2        NaN NaN  NaN  1.0    NaN NaN  NaN  2.0
1 1        3.0 NaN  NaN  NaN    6.0 NaN  NaN  NaN
  2        NaN NaN  NaN  4.0    NaN NaN  NaN  8.0

或者选择上一关和上一关:

df1 = df1.stack([-2,-1],dropna=False).unstack([-2,-1])

另一个想法:

df1 = df1.reindex(pd.MultiIndex.from_product(df1.columns.levels), axis=1)
print (df1)
         value               value2              
group1       o        x           o        x     
group2       a   b    a    b      a   b    a    b
g metric                                         
0 1        0.0 NaN  2.0  NaN    0.0 NaN  4.0  NaN
  2        NaN NaN  NaN  1.0    NaN NaN  NaN  2.0
1 1        3.0 NaN  NaN  NaN    6.0 NaN  NaN  NaN
  2        NaN NaN  NaN  4.0    NaN NaN  NaN  8.0

编辑:

如果需要通过元组列表设置新列:

cols = [('value','x','a'), ('value','o','a'),('value','o','b')]

df = df1.reindex(pd.MultiIndex.from_tuples(cols).union(df1.columns), axis=1)
print (df)
         value               value2          
             o        x           o    x     
             a   b    a    b      a    a    b
g metric                                     
0 1        0.0 NaN  2.0  NaN    0.0  4.0  NaN
  2        NaN NaN  NaN  1.0    NaN  NaN  2.0
1 1        3.0 NaN  NaN  NaN    6.0  NaN  NaN
  2        NaN NaN  NaN  4.0    NaN  NaN  8.0