在实际数据收集过程中,经常会遇到将同一个人的多个学位信息存储在同一行宽表的情况,比如一行数据同时包含本科院校、硕士院校、博士院校等多个字段,这种结构不符合数据规范化的要求,不利于后续做学位相关的统计分析。通过Pandas的相关方法,可以快速将这类宽表转换为长表,把多学位字段展开为多条独立的记录。

多学位宽表的典型结构
我们先看一个常见的多学位宽表示例,这类表通常把不同层级的学位信息作为不同的列存储,结构如下:
| 姓名 | 本科院校 | 本科专业 | 硕士院校 | 硕士专业 | 博士院校 | 博士专业 |
|---|---|---|---|---|---|---|
| 张三 | 北京大学 | 计算机科学 | 清华大学 | 软件工程 | 浙江大学 | 人工智能 |
| 李四 | 复旦大学 | 数学 | 上海交通大学 | 应用数学 |
核心处理思路
宽表转长表的核心是把不同学位对应的列拆分为独立的行,同时保留公共的基础信息列。处理步骤可以分为三步:
- 确定需要保留的固定列,也就是不随学位变化的基础信息,比如姓名
- 识别多学位相关的列,按照学位层级和属性进行分组
- 使用Pandas的
melt函数或者wide_to_long函数完成转换
使用melt函数分步处理
melt函数是Pandas中用于宽表转长表的基础函数,我们可以先把院校列和专业列分别展开,再进行合并。
第一步:展开院校列
先把不同学位的院校列转换为长表结构:
import pandas as pd
import numpy as np
# 构造示例宽表数据
data = {
"姓名": ["张三", "李四"],
"本科院校": ["北京大学", "复旦大学"],
"本科专业": ["计算机科学", "数学"],
"硕士院校": ["清华大学", "上海交通大学"],
"硕士专业": ["软件工程", "应用数学"],
"博士院校": ["浙江大学", np.nan],
"博士专业": ["人工智能", np.nan]
}
df = pd.DataFrame(data)
# 展开院校列,保留姓名作为固定列
school_long = pd.melt(
df,
id_vars=["姓名"],
value_vars=["本科院校", "硕士院校", "博士院校"],
var_name="学位层级",
value_name="院校名称"
)
# 清洗学位层级列,去掉后缀
school_long["学位层级"] = school_long["学位层级"].str.replace("院校", "")
print(school_long)
第二步:展开专业列
同样的方式展开专业列:
# 展开专业列
major_long = pd.melt(
df,
id_vars=["姓名"],
value_vars=["本科专业", "硕士专业", "博士专业"],
var_name="学位层级",
value_name="专业名称"
)
major_long["学位层级"] = major_long["学位层级"].str.replace("专业", "")
print(major_long)
第三步:合并两个长表
按照姓名和学位层级合并两个长表,得到完整的长表结构:
# 合并院校和专业长表 result = pd.merge(school_long, major_long, on=["姓名", "学位层级"], how="left") # 过滤掉院校名称为空的记录 result = result.dropna(subset=["院校名称"]) print(result)
使用wide_to_long函数一步处理
如果多学位列的命名有统一的规则,比如都是“学位+属性”的格式,可以使用wide_to_long函数一步完成转换,效率更高。
# 使用wide_to_long一步转换
result2 = pd.wide_to_long(
df,
stubnames=["院校", "专业"],
i="姓名",
j="学位层级",
sep="",
suffix="(本科|硕士|博士)"
)
# 重置索引,调整列顺序
result2 = result2.reset_index()
# 过滤空值
result2 = result2.dropna(subset=["院校"])
print(result2)
处理后的长表优势
转换后的长表结构符合数据规范化要求,每行记录对应一个学位信息,后续可以很方便地做各类统计,比如统计不同院校的毕业人数、不同专业的分布情况等,也更适合导入到数据库中进行存储和查询。
注意:如果多学位列的数量不固定,比如部分人员有博士后经历,部分没有,处理前可以先动态识别所有包含院校、专业关键字的列,避免手动列举列名出现遗漏。