5.3 类别特征编码
Scikit-learn类别特征编码完整指南:LabelEncoder、OneHotEncoder与OrdinalEncoder详解
本教程为Scikit-learn新手详细讲解类别特征编码方法,包括LabelEncoder目标变量编码、OneHotEncoder特征变量编码和OrdinalEncoder有序编码,并介绍如何使用drop='first'避免多重共线性问题。
类别特征编码:Scikit-learn中的核心预处理技术
简介
在机器学习中,数据通常包含类别特征(Categorical Features),如性别(男/女)、颜色(红/绿/蓝)或产品类型(A/B/C)。这些特征不能直接用于大多数算法,因为它们需要数值输入。类别特征编码就是将这些非数值数据转换为数值形式的过程。Scikit-learn提供了多种编码器来简化这一任务,本教程将逐一介绍它们。
1. LabelEncoder:目标变量编码
LabelEncoder专门用于编码目标变量(y),即机器学习模型要预测的标签。它将类别转换为从0开始的整数。
- 为什么使用:许多Scikit-learn算法要求目标变量为数值,例如分类问题中的标签。
- 如何使用:导入
LabelEncoder,拟合并转换数据。
from sklearn.preprocessing import LabelEncoder
# 示例数据
y = ['cat', 'dog', 'dog', 'bird', 'cat']
# 创建LabelEncoder实例
le = LabelEncoder()
# 拟合并转换
y_encoded = le.fit_transform(y)
print("编码后的目标变量:", y_encoded)
print("类别映射:", list(zip(le.classes_, range(len(le.classes_)))))
输出:编码后的目标变量为 [0 1 1 2 0],映射为 [('bird', 0), ('cat', 1), ('dog', 2)](注意:顺序可能因字母排序而不同)。
2. OneHotEncoder:特征变量编码
OneHotEncoder用于编码特征变量(X),创建二进制列(0或1)来表示每个类别。这避免了引入虚假的序关系,适用于无序类别。
- 为什么使用:避免算法误将类别视为有序(如编码为1、2、3可能被误解为等级)。
- 如何使用:通常与
ColumnTransformer或Pipeline结合使用。
from sklearn.preprocessing import OneHotEncoder
import numpy as np
# 示例数据
X_categorical = [['red'], ['green'], ['blue'], ['red']]
# 创建OneHotEncoder实例,不指定drop参数(默认不删除)
ohe = OneHotEncoder(sparse_output=False)
X_encoded = ohe.fit_transform(X_categorical)
print("OneHot编码后的特征:")
print(X_encoded)
print("类别名称:", ohe.get_feature_names_out())
输出:一个3x3矩阵,每列对应一个颜色类别(例如,红色为[1,0,0])。
3. OrdinalEncoder:有序类别编码
OrdinalEncoder适用于有序类别特征,如教育程度(高中、本科、硕士)或评分(低、中、高),它保留类别之间的等级关系。
- 为什么使用:当类别有明确顺序时,OrdinalEncoder可以编码为数字而不损失顺序信息。
- 如何使用:指定类别顺序或让编码器自动推断。
from sklearn.preprocessing import OrdinalEncoder
# 示例数据:有序类别
X_ordinal = [['low'], ['medium'], ['high'], ['medium']]
# 指定类别顺序
categories = [['low', 'medium', 'high']]
oe = OrdinalEncoder(categories=categories)
X_encoded = oe.fit_transform(X_ordinal)
print("Ordinal编码后的特征:")
print(X_encoded)
输出:[[0.], [1.], [2.], [1.]],其中0=低、1=中、2=高。
4. 编码后维度处理:避免多重共线性
当使用OneHotEncoder时,创建多个二进制列可能导致多重共线性(Multicollinearity),即特征间高度相关,影响模型稳定性。Scikit-learn提供了drop参数来处理这个问题。
- 如何使用drop='first':删除第一个类别列,以避免多重共线性。例如,对于n个类别,OneHotEncoder会生成n-1列。
# 使用drop='first'避免多重共线性
ohe_drop = OneHotEncoder(drop='first', sparse_output=False)
X_encoded_drop = ohe_drop.fit_transform(X_categorical)
print("使用drop='first'后的特征:")
print(X_encoded_drop)
print("剩余类别名称:", ohe_drop.get_feature_names_out())
输出:删除第一个类别(如红色)后,特征矩阵减少一列。这有助于线性回归等算法避免共线性问题。
5. 综合示例与最佳实践
在实际项目中,你可能需要处理多个特征。以下是一个综合示例,演示如何结合使用这些编码器。
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
# 创建示例DataFrame
data = pd.DataFrame({
'color': ['red', 'green', 'blue', 'red'], # 无序类别
'size': ['small', 'medium', 'large', 'medium'], # 有序类别
'label': ['yes', 'no', 'yes', 'no'] # 目标变量
})
# 分离特征和目标
X = data[['color', 'size']]
y = data['label']
# 使用ColumnTransformer编码特征
preprocessor = ColumnTransformer(
transformers=[
('color', OneHotEncoder(drop='first'), ['color']), # 无序类别,避免多重共线性
('size', OrdinalEncoder(categories=[['small', 'medium', 'large']]), ['size']) # 有序类别
]
)
# 编码目标变量
le = LabelEncoder()
y_encoded = le.fit_transform(y)
# 转换特征
X_encoded = preprocessor.fit_transform(X)
print("编码后的特征矩阵形状:", X_encoded.shape)
print("编码后的目标变量:", y_encoded)
最佳实践总结:
- 使用LabelEncoder编码目标变量(y)。
- 对于无序特征变量(X),优先使用OneHotEncoder,并考虑
drop='first'以避免多重共线性。 - 对于有序特征变量,使用OrdinalEncoder以保留顺序信息。
- 在复杂项目中,结合ColumnTransformer和Pipeline来提高代码可维护性。
- 始终检查编码后的数据形状和映射,确保符合预期。
通过本教程,你应能掌握Scikit-learn中类别特征编码的基础知识。继续练习,并在实际数据上应用这些技巧以加深理解!