首页 > 解决方案 > Pandas 将非数字分类虚拟列转换为单个分类列

问题描述

我有如下数据

test=pd.DataFrame( {'group':['v','w','x','y','z'],
                       'cat1':['a',np.nan,np.nan,'c',np.nan],
                       'cat2':[np.nan,'b','a',np.nan,np.nan],
                       'cat3':[np.nan,np.nan,np.nan,np.nan,'a'],
                      })

我想做如下

| group | cat1 | cat2 | cat3 |
|-------|------|------|------|
|   v   |  a   | NaN  | NaN  |
|   w   | NaN  |  b   | NaN  |
|   x   | NaN  |  a   | NaN  |
|   y   |  c   | NaN  | NaN  |
|   z   | NaN  | NaN  |  a   |

| group | category | values |
|-------|----------|--------|
|   v   |   cat1   |   a    |
|   w   |   cat2   |   b    |
|   x   |   cat2   |   a    |
|   y   |   cat1   |   c    |
|   z   |   cat3   |   a    |

我尝试idxmax在stackoverflow中使用另一个问题,但这并没有奏效。

标签: pythonpandasdataframe

解决方案


您可以set_index将“组”转换为索引,然后stack删除 NaN,然后​​您就完成了:

test.set_index('group').stack()

group      
v      cat1    a
w      cat2    b
x      cat2    a
y      cat1    c
z      cat3    a
dtype: object

(test.set_index('group')
     .stack()
     .reset_index(name='values')
     .rename(columns={'level_1': 'categories'}))

  group categories values
0     v       cat1      a
1     w       cat2      b
2     x       cat2      a
3     y       cat1      c
4     z       cat3      a

注意:不对行进行排序


另一种选择是使用pd.wide_to_long,产生类似的输出:

(pd.wide_to_long(test, ['cat'], i=['group'], j='category')
   .dropna()
   .reset_index()
   .rename(columns={'cat': 'values'}))

  group  category values
0     v         1      a
1     y         1      c
2     w         2      b
3     x         2      a
4     z         3      a

注意:行将按“类别”排序


推荐阅读