Pandas执行unstack操作去除NaN值合并为单行的方法
问题描述
给定如下测试数据:
import pandas as pd import io data = pd.read_csv( io.StringIO( ",x,t,t_cls,level\n0,70.0,4.472156319636573,med,level_0\n1,30.0,6.4012513032334235,med,level_1\n" ) ).drop("Unnamed: 0", axis=1)
执行如下unstack操作:
data.set_index("level", append=True).unstack(level=1)
返回结果中分布大量NaN值,数据分散在两行:
| ('x', 'level_0') | ('x', 'level_1') | ('t', 'level_0') | ('t', 'level_1') | ('t_cls', 'level_0') | ('t_cls', 'level_1') | |
|---|---|---|---|---|---|---|
| 0 | 70 | NaN | 4.47216 | NaN | med | NaN |
| 1 | NaN | 30 | NaN | 6.40125 | NaN | med |
需求是将unstack后的结果合并为无NaN值的单行,保留多级列名结构以便后续自行扁平化,目标效果参考:
现有待优化实现
目前可实现需求的写法如下,但逻辑冗余、性能较差,不够优雅:
import numpy as np ( data.set_index("level", append=True) .unstack(level=1) .apply(lambda x: sorted(x.astype(str)), axis=0) .replace({"nan": np.nan}) .dropna(how="all") )
该代码运行后可得到符合预期的结果:
| ('x', 'level_0') | ('x', 'level_1') | ('t', 'level_0') | ('t', 'level_1') | ('t_cls', 'level_0') | ('t_cls', 'level_1') | |
|---|---|---|---|---|---|---|
| 0 | 70 | 30 | 4.47216 | 6.40125 | med | med |
最优实现方案
该场景下unstack输出的每一列仅存在1个有效值,其余位置全为NaN,不需要做字符串转换、排序这类多余操作,直接向下填充后取首行即可,代码简洁且运行效率更高:
( data.set_index("level", append=True) .unstack(level=1) .bfill() # 用下方行的非空值填充当前行的NaN .iloc[[0]] # 取填充完成的第一行,即为所有有效值组成的单行结果 )
如果不需要保留原默认整数行索引,也可以直接用pivot配合列级非空筛选实现:
data.pivot(columns="level", values=["x", "t", "t_cls"]).apply(pd.Series.dropna)
两种写法输出的多级列名结构和预期完全一致,没有多余NaN值,可直接进行后续列名扁平化处理。
内容的提问来源于stack exchange,提问作者baxx
相关产品推荐
相关产品推荐

