本文介绍如何使用 pandas 对按样本分组的单列数据(如 subject)进行结构化重分布,将其依次填充至 person、place、thing 等语义明确的目标列中,适用于清洗“堆叠式”非规范表格。
本文介绍如何使用 pandas 对按样本分组的单列数据(如 subject)进行结构化重分布,将其依次填充至 person、place、thing 等语义明确的目标列中,适用于清洗“堆叠式”非规范表格。
在实际数据清洗中,常遇到“纵向堆叠”的半结构化表格:同一 Sample 下的多个语义类型(人名、地名、物品名)被统一存入 Subject 列,而其他列为空。目标是将每组内有序的三个值(Person → Place → Thing)分别映射到对应列,形成宽表结构。
核心思路是:按 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": ["", "", "", "", "", ""],
"Place": ["", "", "", "", "", ""],
"Thing": ["", "", "", "", "", ""]
})
# 关键操作:分组 + 序列展开 + 列对齐
out = (
df.groupby("Sample")["Subject"]
.apply(lambda x: pd.Series(x.tolist(), index=["Person", "Place", "Thing"]))
.unstack(level=1) # 将列索引(Person/Place/Thing)转为列
.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
✅ 注意事项:
- 此方法假设每组 Sample 下 Subject 值严格按 Person → Place → Thing 顺序排列,且数量恒为 3;若顺序不固定或数量不一致,需先排序或补充逻辑校验(如 x.iloc[0], x.iloc[1] 显式索引)。
- pd.Series([...], index=[...]) 是关键——它将列表值与语义列名精准绑定,避免依赖位置的歧义。
- .unstack(level=1) 将分组后产生的多级列(Sample 为 level-0,Person/Place/Thing 为 level-1)展平为标准列,是实现“行→列”映射的核心步骤。
该方案简洁、可读性强,无需 pivot 或 melt 等复杂操作,直击“语义化列分配”这一典型清洗需求。










