旋转两列数据框

时间:2019-01-23 08:11:53

标签: python pandas

问题

我有一个数据框untidy

  attribute value
0       age    49
1       sex     M
2    height   176
3       age    27
4       sex     F
5    height   172

'attribute'列中的值定期重复。所需的输出是tidy

  age sex height
0  49   M    176
1  27   F    172

(行列顺序或其他标签无关紧要,我可以自己清理。)

实例化代码:

untidy = pd.DataFrame([['age', 49],['sex', 'M'],['height', 176],['age', 27],['sex', 'F'],['height', 172]], columns=['attribute', 'value'])
tidy = pd.DataFrame([[49, 'M', 176], [27, 'F', 172]], columns=['age', 'sex', 'height']) 

尝试

这看起来像是简单的枢轴操作,但是我的初始方法引入了NaN值:

>>> untidy.pivot(columns='attribute', values='value')                                                                                                       
attribute  age height  sex
0           49    NaN  NaN
1          NaN    NaN    M
2          NaN    176  NaN
3           27    NaN  NaN
4          NaN    NaN    F
5          NaN    172  NaN

一些麻烦的解决方法:

>>> untidy.pivot(columns='attribute', values='value').apply(lambda c: c.dropna().reset_index(drop=True))
attribute age height sex
0          49    176   M
1          27    172   F


>>> untidy.set_index([untidy.index//untidy['attribute'].nunique(), 'attribute']).unstack('attribute')
          value           
attribute   age height sex
0            49    176   M
1            27    172   F

惯用的方法是什么?

3 个答案:

答案 0 :(得分:3)

pandas.pivotGroupBy.cumcount一起使用来获取新的索引值,并使用rename_axis来删除列名称:

df = pd.pivot(index=untidy.groupby('attribute').cumcount(),
              columns=untidy['attribute'], 
              values=untidy['value']).rename_axis(None, axis=1) 
print (df)
  age height sex
0  49    176   M
1  27    172   F

另一种解决方案:

df = (untidy.set_index([untidy.groupby('attribute').cumcount(), 'attribute'])['value']
            .unstack()
            .rename_axis(None, axis=1))

答案 1 :(得分:1)

另一种方法是首先使用累积年龄计数来引入新列:

untidy["index"] = (untidy["attribute"] == "age").cumsum() - 1

现在看起来不整洁

      attribute value  index
0       age    49      0
1       sex     M      0
2    height   176      0
3       age    27      1
4       sex     F      1
5    height   172      1

这样,您可以像这样基于属性和索引创建多索引数据框

tidy = untidy.set_index(["index", "attribute"]).unstack()

这会导致以下格式

              value           
attribute   age height sex
index                     
0            49    176   M
1            27    172   F

仍然存在的唯一问题是,列现在是一个多索引,级别太多了。您可以摆脱它,但是首先将列作为索引转置,降低索引的级别并将其转回

tidy = tidy.T.reset_index(level=0).drop("level_0", axis=1).T

最终结果是您的数据框整齐

    attribute age height sex
index                   
0          49    176   M
1          27    172   F

您当然可以将第二步和第三步结合在一起。我不确定这是否更惯用,但对我来说至少是更直观的。

答案 2 :(得分:1)

pivot应该可以正常工作,但是如果您确定标签每隔第三行重复一次,则可以将pd.concat与生成器表达式一起使用:

gen = (df.iloc[3*i:3*(i+1)].set_index('attribute').T for i in range(df.shape[0] // 3))
df = pd.concat(gen, ignore_index=True)

print(df)

attribute age sex height
0          49   M    176
1          27   F    172