第202集:数据预处理
1. 数据预处理概述
1.1 什么是数据预处理
数据预处理(Data Preprocessing)是指在进行机器学习模型训练之前,对原始数据进行一系列转换和处理,使其适合用于模型训练的过程。它是机器学习流程中至关重要的一步,直接影响模型的性能和准确性。
1.2 数据预处理的重要性
- 提高模型性能:高质量的数据可以显著提升模型的准确性和泛化能力
- 解决数据质量问题:处理缺失值、异常值等问题
- 加速模型训练:数据标准化可以使训练过程更加稳定和高效
- 降低计算复杂度:通过特征选择和降维减少数据维度
2. 数据预处理的主要步骤
2.1 数据收集与整合
- 从多种来源收集数据
- 数据格式统一化
- 数据整合与合并
2.2 数据探索与分析(EDA)
- 数据基本统计信息
- 数据分布分析
- 特征相关性分析
- 可视化分析
2.3 数据清洗
- 缺失值处理
- 异常值检测与处理
- 重复数据处理
2.4 特征工程
- 特征选择
- 特征提取
- 特征转换
2.5 数据转换
- 数据标准化
- 数据归一化
- 数据编码
2.6 数据拆分
- 训练集、验证集、测试集划分
- 交叉验证设置
3. 缺失值处理
3.1 缺失值的类型
- 完全随机缺失(MCAR):缺失与任何变量无关
- 随机缺失(MAR):缺失与其他变量相关
- 非随机缺失(MNAR):缺失与缺失值本身相关
3.2 缺失值处理方法
3.2.1 删除法
# 删除包含缺失值的行
df.dropna()
# 删除包含缺失值的列
df.dropna(axis=1)
# 删除指定阈值以上的缺失值
df.dropna(thresh=len(df)*0.7, axis=1)3.2.2 填充法
# 常数填充
df.fillna(0)
# 均值填充
df.fillna(df.mean())
# 中位数填充
df.fillna(df.median())
# 众数填充
df.fillna(df.mode().iloc[0])
# 前向填充
df.fillna(method='ffill')
# 后向填充
df.fillna(method='bfill')3.2.3 插值法
# 线性插值
df.interpolate(method='linear')
# 多项式插值
df.interpolate(method='polynomial', order=2)
# 样条插值
df.interpolate(method='spline', order=2)3.2.4 模型预测法
from sklearn.impute import KNNImputer
# K近邻填充
imputer = KNNImputer(n_neighbors=5)
df_filled = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)
from sklearn.impute import SimpleImputer
# 简单填充
simple_imputer = SimpleImputer(strategy='mean')
df_filled = pd.DataFrame(simple_imputer.fit_transform(df), columns=df.columns)4. 异常值处理
4.1 异常值的类型
- 点异常:单个异常值
- 上下文异常:特定上下文下的异常值
- 集体异常:一组数据点的异常
4.2 异常值检测方法
4.2.1 统计方法
# Z-score方法
from scipy import stats
z_scores = np.abs(stats.zscore(df))
df_clean = df[(z_scores < 3).all(axis=1)]
# 箱线图方法
Q1 = df.quantile(0.25)
Q3 = df.quantile(0.75)
IQR = Q3 - Q1
df_clean = df[~((df < (Q1 - 1.5 * IQR)) | (df > (Q3 + 1.5 * IQR))).any(axis=1)]4.2.2 机器学习方法
# 孤立森林
from sklearn.ensemble import IsolationForest
iso_forest = IsolationForest(contamination=0.05, random_state=42)
anomalies = iso_forest.fit_predict(df)
df_clean = df[anomalies == 1]
# 局部异常因子
from sklearn.neighbors import LocalOutlierFactor
lof = LocalOutlierFactor(n_neighbors=20, contamination=0.05)
anomalies = lof.fit_predict(df)
df_clean = df[anomalies == 1]4.3 异常值处理策略
- 删除:删除异常值记录
- 修正:将异常值修正为合理值
- 转换:使用对数、幂等变换减少异常值影响
- 保留:某些情况下异常值包含重要信息
5. 数据标准化与归一化
5.1 标准化(Standardization)
将数据转换为均值为0,标准差为1的分布:
# 手动标准化
(df - df.mean()) / df.std()
# 使用sklearn
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df_scaled = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)5.2 归一化(Normalization)
将数据缩放到[0, 1]区间:
# 手动归一化
(df - df.min()) / (df.max() - df.min())
# 使用sklearn
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
df_normalized = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)5.3 其他缩放方法
5.3.1 MaxAbsScaler
将数据缩放到[-1, 1]区间:
from sklearn.preprocessing import MaxAbsScaler
scaler = MaxAbsScaler()
df_scaled = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)5.3.2 RobustScaler
对异常值不敏感的缩放方法:
from sklearn.preprocessing import RobustScaler
scaler = RobustScaler()
df_scaled = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)6. 数据编码
6.1 标签编码(Label Encoding)
将分类变量转换为整数:
# 使用pandas
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
df['category_encoded'] = encoder.fit_transform(df['category'])
# 使用pandas
pd.factorize(df['category'])6.2 独热编码(One-Hot Encoding)
将分类变量转换为二进制特征:
# 使用pandas
pd.get_dummies(df, columns=['category'])
# 使用sklearn
from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder(sparse_output=False)
category_encoded = encoder.fit_transform(df[['category']])
df_encoded = pd.concat([df, pd.DataFrame(category_encoded, columns=encoder.get_feature_names_out())], axis=1)6.3 目标编码(Target Encoding)
使用目标变量的均值编码分类特征:
# 使用category_encoders
from category_encoders.target_encoder import TargetEncoder
encoder = TargetEncoder()
df['category_encoded'] = encoder.fit_transform(df['category'], df['target'])6.4 序数编码(Ordinal Encoding)
保留分类变量的顺序信息:
from sklearn.preprocessing import OrdinalEncoder
encoder = OrdinalEncoder(categories=[['低', '中', '高']])
df['level_encoded'] = encoder.fit_transform(df[['level']])7. 数据拆分
7.1 训练集与测试集拆分
from sklearn.model_selection import train_test_split
# 简单拆分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 分层拆分(保持类别比例)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)7.2 训练集、验证集、测试集拆分
# 方法1:两次拆分
X_train_val, X_test, y_train_val, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
X_train, X_val, y_train, y_val = train_test_split(X_train_val, y_train_val, test_size=0.25, random_state=42)
# 方法2:使用sklearn.model_selection.KFold
from sklearn.model_selection import KFold
kf = KFold(n_splits=5, shuffle=True, random_state=42)
for train_index, test_index in kf.split(X):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
# 训练和评估模型
# 方法3:使用sklearn.model_selection.StratifiedKFold
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
for train_index, test_index in skf.split(X, y):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
# 训练和评估模型8. 数据预处理工具
8.1 pandas
- 数据读取与处理
- 缺失值处理
- 数据转换
- 数据聚合与分组
8.2 scikit-learn
- 数据缩放(StandardScaler, MinMaxScaler等)
- 数据编码(LabelEncoder, OneHotEncoder等)
- 缺失值填充(SimpleImputer, KNNImputer等)
- 异常值检测(IsolationForest, LocalOutlierFactor等)
8.3 numpy
- 数值计算
- 数组操作
- 统计分析
8.4 category_encoders
- 高级分类变量编码方法
9. 数据预处理流程示例
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.impute import SimpleImputer
# 1. 数据读取
df = pd.read_csv('data.csv')
# 2. 数据探索
print(df.head())
print(df.info())
print(df.describe())
print(df.isnull().sum())
# 3. 缺失值处理
imputer = SimpleImputer(strategy='mean')
numerical_cols = df.select_dtypes(include=['float64', 'int64']).columns
df[numerical_cols] = imputer.fit_transform(df[numerical_cols])
# 4. 异常值处理
z_scores = np.abs(stats.zscore(df[numerical_cols]))
df = df[(z_scores < 3).all(axis=1)]
# 5. 数据编码
encoder = LabelEncoder()
categorical_cols = df.select_dtypes(include=['object']).columns
df[categorical_cols] = df[categorical_cols].apply(encoder.fit_transform)
# 6. 数据标准化
scaler = StandardScaler()
df[numerical_cols] = scaler.fit_transform(df[numerical_cols])
# 7. 数据拆分
X = df.drop('target', axis=1)
y = df['target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 8. 数据保存
pd.to_pickle((X_train, X_test, y_train, y_test), 'processed_data.pkl')10. 数据预处理的最佳实践
- 了解数据:充分理解数据的含义和业务背景
- 保留原始数据:在预处理前备份原始数据
- 逐步处理:分步进行预处理,每一步都进行验证
- 避免数据泄漏:只在训练集上进行预处理,然后应用到验证集和测试集
- 选择合适的方法:根据数据类型和问题选择合适的预处理方法
- 记录处理步骤:详细记录所有预处理步骤,确保可重复性
- 评估预处理效果:通过模型性能评估预处理的效果
- 调整预处理策略:根据模型性能调整预处理策略
11. 总结
数据预处理是机器学习流程中不可或缺的重要环节,它直接影响模型的性能和准确性。通过合适的数据预处理方法,可以有效解决数据质量问题,提高模型的训练效率和预测精度。在实际应用中,需要根据数据的特点和具体问题选择合适的预处理方法,并遵循数据预处理的最佳实践。
下一集我们将学习特征工程,进一步提升模型的性能。