You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Pandas中将每行仅含单值的多类别列合并为一列

问题描述

现有如下代码:

import pandas as pd
import numpy as np
df = pd.DataFrame({"x": ["red", "blue", np.nan, np.nan, np.nan, np.nan, np.nan, ],
                   "y": [np.nan, np.nan, np.nan, 'cold', 'warm', np.nan, np.nan, ],
                   "z": [np.nan, np.nan,  np.nan, np.nan, np.nan, 'charm', 'strange'],
                  }).astype("category")

运行后得到DataFrame:

x     y        z
0   red   NaN      NaN
1  blue   NaN      NaN
2   NaN   NaN      NaN
3   NaN  cold      NaN
4   NaN  warm      NaN
5   NaN   NaN    charm
6   NaN   NaN  strange

需求:新增一个无序类别列,包含值red、blue、cold、warm、charm、strange,并按对应行填充(每行仅保留非空的那个值)。实际场景中这类列数量较多,不止三列。

已尝试但失败的方法:

  • 使用astype(str)拼接后重新创建类别
  • 使用union_categoricals创建新类别类型,转换各列后依次fillna()

备注:定义df时用.astype(pd.CategoricalDtype(ordered=True))替代.astype("category"),后续解决方案依然适用。

解决方案

方法1:统一类别后提取每行非空值

先合并所有列的类别,创建统一的CategoricalDtype,再转换所有列并提取每行第一个非空值:

from pandas.api.types import union_categoricals

# 合并所有列的类别集合
all_categories = union_categoricals([df[col] for col in df.columns])
# 创建统一的类别类型(无序,需有序则设置ordered=True)
unified_cat_type = pd.CategoricalDtype(categories=all_categories.categories, ordered=False)

# 将所有列转换为统一类别
df_unified = df.astype(unified_cat_type)
# 新增目标列,取每行第一个非空值
df['new_col'] = df_unified.bfill(axis=1).iloc[:, 0]

方法2:利用stack()高效聚合(适合大量列场景)

无需逐列转换类别,通过堆叠操作直接提取每行非空值:

# 堆叠所有列,提取非空值并匹配原行索引
stacked_data = df.stack().reset_index(level=1, drop=True)
# 将结果合并到原DataFrame,空行自动填充NaN
df['new_col'] = stacked_data
# 转换为包含所有目标值的类别列
df['new_col'] = df['new_col'].astype(
    pd.CategoricalDtype(categories=stacked_data.unique(), ordered=False)
)

两种方法均兼容有序类别场景,只需在创建CategoricalDtype时将ordered参数设为True即可。

内容的提问来源于stack exchange,提问作者CPBL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 13:40:26