Scikit-Learn进行数据预处理,从基础到实战全解析

数据预处理是机器学习流程中至关重要的一环,直接影响模型的训练效果和泛化能力。Scikit-Learn(sklearn)作为Python主流的机器学习库,提供了一套完整、易用的预处理工具集,涵盖缺失值填充、特征缩放、类别特征编码、数据划分等核心功能。本文从实际应用场景出发,详细讲解Sklearn数据预处理的常用方法、实现步骤及避坑要点。

一、数据预处理核心原则与准备工作

1. 核心原则

  • 数据泄露禁止:所有预处理操作(如特征缩放、缺失值填充)仅能基于训练集拟合,测试集需复用训练集的预处理规则,避免引入测试集信息;
  • 维度对齐:预处理后特征矩阵的维度需与模型输入要求一致;
  • 按需选择:不同模型对数据的要求不同(如线性模型需特征缩放,树模型无需),需针对性选择预处理方法。

2. 环境与数据准备

确保已安装所需库,本文以经典的泰坦尼克号数据集(含缺失值、类别特征)为例演示:

bash 复制代码
# 安装依赖
pip install scikit-learn pandas numpy
python 复制代码
# 导入工具库
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

# 加载数据集(可从Kaggle下载,或使用示例数据)
data = pd.read_csv('titanic.csv')
# 选取核心特征和标签
X = data[['Age', 'Fare', 'Pclass', 'Sex', 'Embarked']]  # 特征
y = data['Survived']  # 标签(是否存活)

# 划分训练集和测试集(先划分再预处理,避免数据泄露)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42  # 固定随机种子,结果可复现
)

二、缺失值处理:SimpleImputer

真实数据中缺失值是常态,Sklearn的SimpleImputer支持数值型、类别型数据的缺失值填充,核心参数为strategy(填充策略)。

1. 数值型特征缺失值填充

针对Age(年龄)、Fare(票价)等数值特征,常用填充策略:均值(mean)、中位数(median)、固定值(constant)。

python 复制代码
from sklearn.impute import SimpleImputer

# 1. 提取数值型特征
numeric_features = ['Age', 'Fare']
X_train_numeric = X_train[numeric_features]
X_test_numeric = X_test[numeric_features]

# 2. 实例化填充器(中位数填充,鲁棒性更强,抗异常值)
numeric_imputer = SimpleImputer(strategy='median')

# 3. 仅在训练集拟合(关键!),并转换训练集
X_train_numeric_imputed = numeric_imputer.fit_transform(X_train_numeric)
# 4. 用训练集的填充规则转换测试集
X_test_numeric_imputed = numeric_imputer.transform(X_test_numeric)

# 查看填充器的填充值(如Age的中位数)
print(f"Age的填充值:{numeric_imputer.statistics_[0]}")
print(f"Fare的填充值:{numeric_imputer.statistics_[1]}")

2. 类别型特征缺失值填充

针对Sex(性别)、Embarked(登船港口)等类别特征,常用填充策略:众数(most_frequent)、固定值(constant)。

python 复制代码
# 1. 提取类别型特征
categorical_features = ['Pclass', 'Sex', 'Embarked']
X_train_categorical = X_train[categorical_features]
X_test_categorical = X_test[categorical_features]

# 2. 实例化填充器(众数填充)
categorical_imputer = SimpleImputer(strategy='most_frequent')

# 3. 拟合训练集并转换
X_train_categorical_imputed = categorical_imputer.fit_transform(X_train_categorical)
X_test_categorical_imputed = categorical_imputer.transform(X_test_categorical)

三、类别特征编码:OneHotEncoder & LabelEncoder

类别特征(如Sex:male/female)无法直接输入模型,需转换为数值形式,Sklearn提供两种核心编码方式:

1. 独热编码(OneHotEncoder):适合无序类别特征

针对无大小关系的类别(如Embarked:C/Q/S),独热编码将每个类别转换为独立的二进制特征,避免模型误判类别间的大小关系。

python 复制代码
from sklearn.preprocessing import OneHotEncoder

# 实例化独热编码器(忽略未知类别,避免测试集出现新类别报错)
onehot_encoder = OneHotEncoder(sparse_output=False, handle_unknown='ignore')

# 拟合训练集的类别特征(已填充缺失值)
X_train_categorical_encoded = onehot_encoder.fit_transform(X_train_categorical_imputed)
# 转换测试集
X_test_categorical_encoded = onehot_encoder.transform(X_test_categorical_imputed)

# 查看编码后的特征名(便于理解)
print("编码后的类别特征名:", onehot_encoder.get_feature_names_out(categorical_features))

2. 标签编码(LabelEncoder):适合有序/二分类特征

仅适用于标签(y)或有序类别特征(如Pclass:1/2/3等舱位),不可用于无序特征的独热编码替代(会引入虚假顺序)。

python 复制代码
from sklearn.preprocessing import LabelEncoder

# 示例:对标签y进行编码(二分类可省略,此处仅演示)
le = LabelEncoder()
y_train_encoded = le.fit_transform(y_train)
y_test_encoded = le.transform(y_test)

四、特征缩放:StandardScaler & MinMaxScaler

特征缩放用于消除不同特征量纲的影响(如Age:0-100,Fare:0-500),核心适用于线性模型、SVM、KNN等对尺度敏感的模型。

1. 标准化(StandardScaler):均值为0,方差为1

适用于数据近似正态分布的场景,鲁棒性较强:

python 复制代码
from sklearn.preprocessing import StandardScaler

# 实例化标准化器
scaler = StandardScaler()

# 拟合训练集的数值特征(已填充缺失值)
X_train_numeric_scaled = scaler.fit_transform(X_train_numeric_imputed)
# 转换测试集
X_test_numeric_scaled = scaler.transform(X_test_numeric_imputed)

# 查看标准化参数(均值和标准差)
print(f"Age的均值:{scaler.mean_[0]}, 标准差:{scaler.scale_[0]}")

2. 归一化(MinMaxScaler):缩放到0-1区间

适用于数据分布无明显规律、需要固定范围的场景:

python 复制代码
from sklearn.preprocessing import MinMaxScaler

# 实例化归一化器
minmax_scaler = MinMaxScaler()

X_train_numeric_normalized = minmax_scaler.fit_transform(X_train_numeric_imputed)
X_test_numeric_normalized = minmax_scaler.transform(X_test_numeric_imputed)

五、预处理流水线:Pipeline(推荐!)

手动分步处理易出错且繁琐,Sklearn的Pipeline可将缺失值填充、编码、缩放等步骤封装为一个整体,避免数据泄露,简化流程。

1. 构建预处理流水线

python 复制代码
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer

# 1. 定义数值特征的预处理流程:缺失值填充 + 标准化
numeric_pipeline = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='median')),
    ('scaler', StandardScaler())
])

# 2. 定义类别特征的预处理流程:缺失值填充 + 独热编码
categorical_pipeline = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')),
    ('onehot', OneHotEncoder(sparse_output=False, handle_unknown='ignore'))
])

# 3. 整合数值和类别特征的预处理(ColumnTransformer按列处理)
preprocessor = ColumnTransformer(
    transformers=[
        ('numeric', numeric_pipeline, numeric_features),
        ('categorical', categorical_pipeline, categorical_features)
    ]
)

# 4. 拟合并转换训练集(一步完成所有预处理)
X_train_processed = preprocessor.fit_transform(X_train)
# 5. 转换测试集
X_test_processed = preprocessor.transform(X_test)

# 查看预处理后的特征维度
print(f"训练集预处理后维度:{X_train_processed.shape}")
print(f"测试集预处理后维度:{X_test_processed.shape}")

2. 流水线结合模型训练

可将预处理和模型训练封装为一个完整流水线,进一步简化流程:

python 复制代码
from sklearn.linear_model import LogisticRegression

# 构建完整流水线:预处理 + 模型训练
full_pipeline = Pipeline(steps=[
    ('preprocessor', preprocessor),
    ('classifier', LogisticRegression(random_state=42))
])

# 训练(自动先预处理训练集,再训练模型)
full_pipeline.fit(X_train, y_train)

# 预测(自动预处理测试集,再预测)
y_pred = full_pipeline.predict(X_test)

# 评估模型
from sklearn.metrics import accuracy_score
print(f"模型准确率:{accuracy_score(y_test, y_pred):.2f}")

六、其他常用预处理方法

1. 异常值处理:RobustScaler

针对含异常值的数据,RobustScaler基于分位数(中位数、四分位距)缩放,抗异常值影响:

python 复制代码
from sklearn.preprocessing import RobustScaler
robust_scaler = RobustScaler()
X_train_robust = robust_scaler.fit_transform(X_train_numeric_imputed)

2. 特征分箱:KBinsDiscretizer

将连续特征转换为离散类别(如Age分为少年/青年/中年/老年):

python 复制代码
from sklearn.preprocessing import KBinsDiscretizer
binner = KBinsDiscretizer(n_bins=4, encode='onehot', strategy='quantile')
X_train_binned = binner.fit_transform(X_train[['Age']])

3. 缺失值标记:MissingIndicator

除填充缺失值外,可额外添加"是否缺失"的特征,提升模型对缺失值的感知:

python 复制代码
from sklearn.impute import MissingIndicator
indicator = MissingIndicator()
X_train_missing = indicator.fit_transform(X_train_numeric)
# 合并原始特征和缺失标记特征
X_train_combined = np.hstack([X_train_numeric_imputed, X_train_missing])

七、预处理避坑指南

  1. 先划分数据集再预处理:绝对禁止先预处理再划分,否则测试集的均值/中位数等会包含训练集信息,导致模型评估偏乐观;
  2. OneHotEncoder处理未知类别 :设置handle_unknown='ignore',避免测试集出现训练集未见过的类别时报错;
  3. 稀疏矩阵优化:独热编码默认返回稀疏矩阵(sparse_output=True),适合高维数据,可减少内存占用;
  4. 有序类别特征编码 :若类别有顺序(如Pclass:1>2>3),可使用OrdinalEncoder,而非OneHotEncoder;
  5. 流水线参数调优 :可结合GridSearchCV对流水线中的参数(如填充策略、缩放方式)进行调优:
python 复制代码
from sklearn.model_selection import GridSearchCV

# 定义参数网格
param_grid = {
    'preprocessor__numeric__imputer__strategy': ['mean', 'median'],
    'classifier__C': [0.1, 1, 10]
}

# 网格搜索
grid_search = GridSearchCV(full_pipeline, param_grid, cv=5, scoring='accuracy')
grid_search.fit(X_train, y_train)
print(f"最优参数:{grid_search.best_params_}")
相关推荐
ULTRA??3 小时前
Informed RRT*算法,并包含圆形障碍物环境
人工智能·python·算法
黑客思维者4 小时前
XGW-9000 网关 DDR4/LPDDR4 内存子系统信号完整性仿真细化设计
开发语言·python·嵌入式硬件·ddr4·信号仿真
Felven4 小时前
华为昇腾310P模型转换失败问题解决
linux·python·模型训练·昇腾·310p
ekprada4 小时前
Day 41 卷积神经网络(CNN)基础与实战
人工智能·python·机器学习
Dingdangcat864 小时前
基于改进YOLO11-C2PSA-SEFFN的工业环境气体泄漏检测与定位系统实现
python
AI视觉网奇4 小时前
live2d 单图转模型 单图生成模型
java·前端·python
咸鱼加辣4 小时前
【python面试题】LRUCache
开发语言·python
LitchiCheng4 小时前
WSL2 中 pynput 无法捕获按键输入?
开发语言·python
中年程序员一枚4 小时前
Python 中处理视频添加 / 替换音频
开发语言·python·音视频