pd.get_dummies() 是 Pandas 中处理分类变量的核心函数,能一键将字符串/离散数值类型的分类特征转换为「哑变量/虚拟变量」(0-1 编码,独热编码)------ 这是解决机器学习模型无法直接处理非数值特征的关键步骤。
简单来说:一个包含 N 个不同分类值的列,会被转换成 N 个新的 0-1 (独热)列 (除非设置 drop_first=True),新列名的生成有明确规则。
二、新列名的生成规则(核心重点)
新列名的命名遵循「前缀 + 分隔符 + 分类值」的逻辑,默认规则和自定义规则如下:
1. 默认规则(最常用)
- 前缀 = 原分类列的列名
- 分隔符 = 下划线
_ - 最终列名 =
原列名_分类值
2. 特殊场景的列名规则
| 场景 | 示例(原数据) | 生成的新列名 |
|---|---|---|
| 字符串分类值 | 列名性别,值为男/女 |
性别_男、性别_女 |
| 数值型分类值 | 列名学历,值为1/2/3 |
学历_1、学历_2、学历_3 |
| 多列同时转换 | 列性别(男/女)+ 列城市(北京/上海) |
性别_男、性别_女、城市_北京、城市_上海 |
| 自定义分隔符 | 设置prefix_sep='-',列性别(男/女) |
性别-男、性别-女 |
| 自定义前缀 | 设置prefix='sex',列性别(男/女) |
sex_男、sex_女 |
| 剔除首列(去重共线) | 设置drop_first=True,列性别(男/女) |
仅生成性别_女(删除第一个分类的列) |
三、代码示例(直观理解列名生成)
下面的代码可以直接复制运行,覆盖核心场景:
python
import pandas as pd
# 1. 创建测试数据(包含字符串、数值分类列)
df = pd.DataFrame({
"性别": ["男", "女", "男", "女"],
"学历": [1, 2, 3, 2],
"城市": ["北京", "上海", "北京", "广州"]
})
print("原始数据:")
print(df)
print("-" * 50)
# 2. 基础用法:转换所有分类列(默认规则)
dummies_default = pd.get_dummies(df)
print("默认规则生成的哑变量(列名=原列名_分类值):")
print(dummies_default.columns.tolist()) # 打印所有新列名
print(dummies_default)
print("-" * 50)
# 3. 自定义分隔符
dummies_sep = pd.get_dummies(df, prefix_sep='-')
print("自定义分隔符(-)的列名:")
print(dummies_sep.columns.tolist())
print("-" * 50)
# 4. 剔除首列(避免多重共线性)
dummies_drop = pd.get_dummies(df, drop_first=True)
print("drop_first=True 后生成的列(删除每个分类的第一个列):")
print(dummies_drop.columns.tolist())
输出结果说明
- 基础用法输出列名:
['性别_女', '性别_男', '学历_1', '学历_2', '学历_3', '城市_上海', '城市_北京', '城市_广州'] - 自定义分隔符输出列名:
['性别-女', '性别-男', '学历-1', '学历-2', '学历-3', '城市-上海', '城市-北京', '城市-广州'] - drop_first=True 输出列名:
['性别_男', '学历_2', '学历_3', '城市_上海', '城市_广州'](删除了每个分类的第一个列)
四、补充事项
1. 空值处理:如果原列有 NaN,pd.get_dummies() 会自动忽略该值,生成的哑变量列中对应行全为 0(也可通过 dummy_na=True 单独生成 原列名_nan 列)。
2. 指定转换列:可用 columns 参数指定只转换某几列,比如 pd.get_dummies(df, columns=['性别', '城市']) 仅转换性别和城市列。
3. 剔除首列(避免多重共线性)
1. 先理解:为什么分类变量的哑变量会产生共线性?
哑变量的本质是「互斥且穷尽」的------对于一个有 N 个分类的变量,生成的 N 个哑变量之间存在完全的线性依赖关系 (可以互相推导),没有独立的信息增量。从数学角度上讲,只有N-1 个自由变量,即:N-1 个哑变量就能完全表达原分类变量的所有信息。
举个最直观的例子:
假设你有一个「性别」列(只有「男」「女」两个分类),用默认方式生成哑变量会得到两列:
性别_男:1=男,0=女性别_女:1=女,0=男
这两列满足:性别_女 = 1 - 性别_男。也就是说,知道其中一列的值,就能100%推出另一列的值------这就是完全多重共线性。
再举多分类例子(城市:北京/上海/广州):
生成3列哑变量后,城市_北京 = 1 - 城市_上海 - 城市_广州,依然是完全线性相关的。
2. 为什么共线性对建模有害?
多重共线性主要影响基于线性假设的模型(如线性回归、逻辑回归、岭回归等),核心问题有3个:
- 模型系数(权重)的估计不稳定:微小的数据变化会导致系数大幅波动,无法反映变量的真实影响;
- 系数的解释性失效:比如线性回归中,系数代表「其他变量不变时,该变量对目标的影响」,但共线性下「其他变量不变」的前提不成立;
- 冗余计算:多余的列不会增加任何信息,只会增加模型的计算量,对建模毫无帮助。
3. 为什么删除第一列不会丢失信息?
删除第一个哑变量列后,剩余的列依然能完整表达原分类变量的所有信息,只是把「第一个分类」作为「基准类别」。
还是用「性别」举例:
- 删除
性别_女(第一个列),只剩性别_男:性别_男=1→ 男性别_男=0→ 女(基准类别)
信息完全没丢。
用「城市(北京/上海/广州)」举例:
- 删除
城市_北京(第一个列),剩城市_上海、城市_广州:0,0→ 北京(基准类别)1,0→ 上海0,1→ 广州
所有城市信息依然完整。
说明
- 不是所有模型都需要drop_first:比如决策树、随机森林、XGBoost等树模型对共线性不敏感(因为树模型是基于特征分裂,而非线性组合),删不删影响很小;但线性回归、逻辑回归、线性SVM等必须处理,否则会影响模型效果。
- 基准类别的选择 :
drop_first=True删的是「按字母/数值排序的第一个分类」,如果想自定义基准类别(比如把「北京」设为基准),可以手动删除对应列,效果一致。 - 适用场景:对线性假设的模型(如线性回归、逻辑回归)必须用;树模型等对共线性不敏感的模型,可删可不删(删了能减少特征数量,提升效率)。
记住
pd.get_dummies()核心作用是将分类变量转为 0-1 哑变量,解决非数值特征建模问题。- 新列名默认规则为
原列名_分类值,可通过prefix(自定义前缀)、prefix_sep(自定义分隔符)调整。 drop_first=True会删除每个分类变量的第一个哑变量列,是机器学习中避免多重共线性的常用操作。