首页 > 解决方案 > 根据列名压缩宽数据

问题描述

有没有一种优雅的方式来做我想要在 Pandas 中做的事情?我的数据看起来像:

df = pd.DataFrame({
    'alpha': [1, np.nan, np.nan, np.nan],
    'bravo': [np.nan, np.nan, np.nan, -1],
    'charlie': [np.nan, np.nan, np.nan, np.nan],
    'delta': [np.nan, 1, np.nan, np.nan],
})

print(df)

   alpha  bravo  charlie  delta
0    1.0    NaN      NaN    NaN
1    NaN    NaN      NaN    1.0
2    NaN    NaN      NaN    NaN
3    NaN   -1.0      NaN    NaN

我想把它变成类似的东西:

  position  value
0    alpha      1
1    delta      1
2      NaN    NaN
3    bravo     -1

因此,对于原始数据中的每一行,我想找到非 NaN 值并检索找到它的列的名称。然后我将列和值存储在名为“位置”和“值”的新列中。

我可以保证原始数据中的每一行都包含零个或一个非 NaN 值。

我唯一的想法是遍历每一行,但我知道这个想法很糟糕,必须有一种更平易近人的方式来做到这一点。我不完全确定如何表达我的问题,所以我在谷歌上搜索想法时遇到了麻烦。感谢您的任何建议!

标签: pandas

解决方案


我们可以使用DataFrame.meltunpivot 您的数据,然后使用sort_valuesand drop_duplicates

df = (
    df.melt(var_name='position')
    .sort_values('value')
    .drop_duplicates('position', ignore_index=True)
)
  position  value
0    bravo   -1.0
1    alpha    1.0
2    delta    1.0
3  charlie    NaN

另一种选择是DataFrame.bfill在列轴上使用。既然你注意到:

可以保证原始数据中的每一行都恰好包含零个或一个非NaN值

values = df.bfill(axis=1).iloc[:, 0]
dfn = pd.DataFrame({'positions': df.columns, 'values': values})
  positions  values
0     alpha     1.0
1     bravo     1.0
2   charlie     NaN
3     delta    -1.0

推荐阅读