首页 > 解决方案 > 在 Pandas 中透视包含重复条目的表

问题描述

有没有办法将带有熊猫的用户角色身高和体重表 (A) 旋转到 (B)?我曾尝试使用 unstack,但它似乎不起作用。

(A) 用户角色身高体重表

+---------------------------------------------+
|     USER_ID    Category    Height    Weight |
+---------------------------------------------+
|     USER 1      Green       172cm      69kg |
|     USER 2      Blue        169cm      61kg |
|     USER 1      Red         153cm      41kg |
|     USER 3      Green       172cm      59kg |
+---------------------------------------------+

(乙)

+--------------------------------------------------------------------------------------------------+
| USER_ID Green Height_Green Weight_Green Blue Height_Blue Weight_Blue Red  Height_Red  Weight_Red |
+--------------------------------------------------------------------------------------------------+
| USER 1    1      172.0        69.0        0       0.0       0.0       1      153.0        41.0   |
| USER 2    0        0.0         0.0        1     169.0      61.0       0        0.0         0.0   |            
| USER 3    1      172.0        59.0        0       0.0       0.0       0        0.0         0.0   |
+--------------------------------------------------------------------------------------------------+

我曾尝试使用 unstack,但它似乎不起作用。因为有多个相同的用户 id,pivot_table 会给我一个 ValueError,说索引包含重复的条目,不能重塑。有解决此问题的方法吗?

df.groupby('USER_ID')['Category','Height', 'Weight'] \
      .apply(lambda x: pd.DataFrame(x.values.tolist(),
             columns=['Category','Height', 'Weight'])) \
      .unstack(fill_value=0)

标签: pythonpandaspivot-table

解决方案


我会尝试拆分问题:

  • 首先将高度和重量列转换为浮点值
  • 通过使用辅助列旋转数据框来生成绿色、蓝色和红色列
  • 产生 type_color 列unstack
  • 连接上面的列并重新索引以生成最终的数据帧

代码可以是:

# convert the values to float
for col in ['Height', 'Weight']:
    df[col] = df[col].str.slice(stop=-2).astype('float')

# First columns
tmp1 = df[['USER_ID', 'Category']].assign(val=1).pivot(
    'USER_ID', 'Category', 'val').fillna(0).astype(int)

# Other columns
tmp2 = df.set_index(['USER_ID', 'Category']).unstack().fillna(0)
tmp2.columns = ['_'.join(i) for i in tmp2.columns]

# compute the expected column names
final_cols = [i for j in [[i] + ['_'.join((j,i)) for j in ('Height', 'Weight')]
              for i in ['Green', 'Blue', 'Red']] for i in j]

# finaly produce the result dataframe
resul = pd.concat([tmp1, tmp2], axis=1).reindex(columns=final_cols
                                                ).reset_index()

使用您的初始数据,它提供:

  USER_ID  Green  Height_Green  Weight_Green  Blue  Height_Blue  Weight_Blue  Red  Height_Red  Weight_Red
0  USER 1      1         172.0          69.0     0          0.0          0.0    1       153.0        41.0
1  USER 2      0           0.0           0.0     1        169.0         61.0    0         0.0         0.0
2  USER 3      1         172.0          59.0     0          0.0          0.0    0         0.0         0.0

推荐阅读