本文介绍如何使用 Pandas 将同一分组下分散在单一列(如 Subject)中的多个值,按顺序(如第1个为 Person、第2个为 Place、第3个为 Thing)精准分配至对应的目标列,实现结构化重组。
本文介绍如何使用 pandas 将同一分组下分散在单一列(如 `subject`)中的多个值,按顺序(如第1个为 person、第2个为 place、第3个为 thing)精准分配至对应的目标列,实现结构化重组。
在实际数据清洗中,常遇到“宽表逻辑、窄表存储”的情况:原始数据将不同语义的值(如人名、地名、物品)统一存于一列,仅靠分组标识(如 Sample)隐含顺序关系。此时需将其“解压”为规范宽表——即每个语义字段独占一列。Pandas 提供了简洁高效的向量化方案,无需循环或手动索引。
核心思路是:按 Sample 分组 → 提取每组 Subject 列的值序列 → 将该序列按预设顺序映射到目标列名 → 重塑为宽表。具体实现如下:
import pandas as pd
# 构造示例数据
df = pd.DataFrame({
"Sample": ["1-1", "1-1", "1-1", "1-2", "1-2", "1-2"],
"Subject": ["Janet", "Boston", "Hat", "Chris", "Austin", "Scarf"],
"Person": [""] * 6,
"Place": [""] * 6,
"Thing": [""] * 6
})
# 关键步骤:分组 + 序列映射 + 展开
out = (
df.groupby("Sample")["Subject"]
.apply(lambda x: pd.Series(x.tolist(), index=["Person", "Place", "Thing"]))
.unstack(level=1)
.reset_index()
)
# 若需保留原始 Subject 列(通常等于 Person),可显式添加
out["Subject"] = out["Person"]
print(out)输出结果:
Sample Person Place Thing Subject 0 1-1 Janet Boston Hat Janet 1 1-2 Chris Austin Scarf Chris
✅ 关键说明:
- groupby("Sample")["Subject"] 确保按样本聚合;
- apply(...) 中 pd.Series(..., index=[...]) 将每组的值列表(如 ["Janet", "Boston", "Hat"])严格按索引顺序绑定到 ["Person", "Place", "Thing"],自动对齐列名;
- unstack(level=1) 将列索引(即 "Person"/"Place"/"Thing")提升为列,完成宽表转换;
- .reset_index() 恢复 Sample 为普通列。
⚠️ 注意事项:
- 此方法严格依赖每组内 Subject 值的出现顺序(第1行→Person,第2行→Place,第3行→Thing)。请确保原始数据顺序稳定且符合业务逻辑;
- 若某组值数量不足3个,缺失位置将自动填充 NaN;若超过3个,仅取前3个(可通过 x.iloc[:3] 显式截断);
- 如需动态适配不同数量的类别,可预先定义映射字典并用 map() 或 pivot() 替代硬编码索引。
该方案兼具可读性与性能,是处理此类“顺序语义列展开”问题的推荐实践。

















