Python 机器学习数据预处理
在机器学习和数据挖掘任务中,原始数据往往存在噪声、缺失值或格式不统一等问题。数据预处理是建模前至关重要的一步,直接影响模型的性能和收敛速度。本文将详细介绍五种常见的数据预处理方式:归一化、标准化、缺失值填充、分类型特征编码以及连续型特征处理,并提供完整的 Python 代码案例。
1. 归一化 (Normalization)
归一化旨在将数值特征缩放到一个特定的区间,通常是 [0, 1]。这在梯度下降算法中非常有用,可以加速收敛。在 sklearn 中,我们使用 MinMaxScaler 来实现这一功能。
1.1 MinMaxScaler 基础用法
MinMaxScaler 有一个重要参数 feature_range,用于控制数据压缩到的范围,默认为 [0, 1]。
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
import numpy as np
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
df = pd.DataFrame(data)
print("原始数据:")
print(df)
scaler = MinMaxScaler()
scaler.fit(data)
result = scaler.transform(data)
print("\n归一化后结果:")
print(result)
1.2 一步完成训练与转换
在实际应用中,通常可以将拟合和转换合并为一步:
scaler = MinMaxScaler(feature_range=[0, 1])
result_ = scaler.fit_transform(data)
print("\n一步转换结果:")
print(result_)
1.3 逆归一化
有时我们需要将归一化后的数据还原回原始尺度,以便解释结果:
original_data = scaler.inverse_transform(result)
print("\n逆归一化还原:")
print(original_data)
1.4 自定义范围与大数据处理
如果希望将数据压缩到特定区间(例如 [5, 10]),可设置 feature_range:
scaler_custom = MinMaxScaler(feature_range=[5, 10])
result_custom = scaler_custom.fit_transform(data)
print("\n范围 [5, 10] 归一化:")
print(result_custom)
对于大数据集,可以使用 partial_fit 进行增量学习,避免一次性加载所有数据到内存:
1.5 使用 NumPy 手动实现
理解原理有助于调试,NumPy 实现如下:
X = np.array([[-1, 2], [-0.5, 6], [0, 10], [1, 18]])
X_min = X.min(axis=0)
X_max = X.max(axis=0)
X_nor = (X - X_min) / (X_max - X_min)
print("\nNumPy 归一化:")
print(X_nor)
X_returned = X_nor * (X_max - X_min) + X_min
print("\nNumPy 逆归一化:")
print(X_returned)
2. 标准化 (Standardization)
标准化是将数据转换为均值为 0、方差为 1 的分布(标准正态分布)。这个过程称为 Z-score normalization。当数据存在异常值时,标准化比归一化更稳健。
2.1 StandardScaler 基础用法
from sklearn.preprocessing import StandardScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = StandardScaler()
scaler.fit(data)
print("均值:", scaler.mean_)
print("方差:", scaler.var_)
x_std = scaler.transform(data)
print("\n标准化结果:")
print(x_std)
2.2 验证统计特性
print("\n转换后均值:", x_std.mean())
print("转换后标准差:", x_std.std())
2.3 一步完成
scaler = StandardScaler()
x_std_step = scaler.fit_transform(data)
2.4 逆标准化
x_original = scaler.inverse_transform(x_std)
print("\n逆标准化还原:")
print(x_original)
2.5 标准化与归一化的选择建议
- StandardScaler: 大多数机器学习算法的首选,特别是涉及距离度量(如 KNN、SVM)、聚类、逻辑回归、神经网络等。它对异常值的敏感度低于 MinMaxScaler。
- MinMaxScaler: 适用于不涉及距离度量的场景,或者需要将数据严格限制在特定区间的情况(如图像像素强度量化)。
建议: 优先尝试 StandardScaler,若效果不佳再考虑 MinMaxScaler。
3. 缺失值填充 (Missing Value Imputation)
真实数据集中常包含缺失值。直接删除可能导致信息丢失,因此需要根据情况选择合适的填充策略。
3.1 数据准备与检查
import pandas as pd
import numpy as np
data = pd.DataFrame({
'Age': [22, 38, np.nan, 26, 35, np.nan, 54],
'Embarked': ['S', 'C', 'Q', 'S', 'S', 'C', np.nan]
})
print("原始数据:")
print(data.info())
print(data.head())
3.2 使用 SimpleImputer 填充
sklearn 提供了 SimpleImputer 类来处理缺失值。
from sklearn.impute import SimpleImputer
Age = data.loc[:, "Age"].values.reshape(-1, 1)
imp_mean = SimpleImputer(strategy="mean")
Age_mean = imp_mean.fit_transform(Age)
imp_median = SimpleImputer(strategy="median")
Age_median = imp_median.fit_transform(Age)
imp_const = SimpleImputer(strategy="constant", fill_value=0)
Age_const = imp_const.fit_transform(Age)
Embarked = data.loc[:, "Embarked"].values.reshape(-1, 1)
imp_mode = SimpleImputer(strategy="most_frequent")
Embarked_mode = imp_mode.fit_transform(Embarked)
3.3 应用填充结果
data["Age"] = Age_median.flatten()
data["Embarked"] = Embarked_mode.flatten()
print("\n填充后数据:")
print(data.info())
print(data.head())
3.4 Pandas 原生方法
Pandas 也提供了便捷的缺失值处理方法:
data["Age"] = data["Age"].fillna(data["Age"].median())
4. 处理分类型特征:编码与哑变量
大多数机器学习算法只能处理数值型数据。文本型特征需要转换为数值。
4.1 LabelEncoder (标签编码)
适用于目标变量(Y),将类别映射为整数。
from sklearn.preprocessing import LabelEncoder
y = pd.Series(['No', 'Unknown', 'Yes', 'Yes', 'No'])
le = LabelEncoder()
label_encoded = le.fit_transform(y)
print("类别映射:", le.classes_)
print("编码结果:", label_encoded)
print("\n还原结果:", le.inverse_transform(label_encoded))
4.2 OrdinalEncoder (有序编码)
适用于特征矩阵中的有序分类变量。
from sklearn.preprocessing import OrdinalEncoder
data_features = [['Male', 'S'], ['Female', 'C'], ['Male', 'Q']]
enc = OrdinalEncoder()
encoded_features = enc.fit_transform(data_features)
print("\n有序编码结果:")
print(encoded_features)
print("类别:", enc.categories_)
4.3 OneHotEncoder (独热编码)
适用于无序分类变量(名义变量),避免引入虚假的大小关系。
from sklearn.preprocessing import OneHotEncoder
x = pd.DataFrame({'Sex': ['male', 'female', 'male'], 'Embarked': ['S', 'C', 'Q']})
enc_ohe = OneHotEncoder(sparse_output=False)
result = enc_ohe.fit_transform(x)
print("\n独热编码结果:")
print(result)
print("特征名称:", enc_ohe.get_feature_names_out())
print("\n还原数据:")
print(pd.DataFrame(enc_ohe.inverse_transform(result), columns=x.columns))
5. 处理连续型特征:二值化与分段
5.1 二值化 (Binarization)
根据阈值将连续值转换为 0 或 1。
from sklearn.preprocessing import Binarizer
age = pd.DataFrame({'Age': [20, 30, 40, 50, 60]})
threshold = 30
binarizer = Binarizer(threshold=threshold)
age_arr = age.values.reshape(-1, 1)
transformed_age = binarizer.fit_transform(age_arr)
print("\n二值化结果 (>30 为 1):")
print(transformed_age)
5.2 分箱 (Discretization)
将连续变量划分为多个区间(箱),转化为分类变量。
from sklearn.preprocessing import KBinsDiscretizer
age = pd.DataFrame({'Age': [20, 25, 30, 35, 40, 45, 50, 55, 60]})
x = age.values.reshape(-1, 1)
est_ord = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform')
result_ord = est_ord.fit_transform(x)
print("\n分箱 (Ordinal):")
print(set(result_ord.ravel()))
est_ohe = KBinsDiscretizer(n_bins=3, encode='onehot', strategy='uniform')
result_ohe = est_ohe.fit_transform(x).toarray()
print("\n分箱 (OneHot):")
print(result_ohe)
总结
数据预处理是机器学习流程中的基石。本文涵盖了以下核心内容:
- 缩放: 区分了归一化 (MinMax) 和标准化 (Z-score) 的适用场景。
- 缺失值: 展示了均值、中位数、众数及常数填充策略。
- 编码: 讲解了 LabelEncoder、OrdinalEncoder 和 OneHotEncoder 的区别。
- 离散化: 介绍了二值化和分箱技术。
在实际项目中,建议先探索性数据分析 (EDA),了解数据分布后再选择预处理方案。同时,务必在训练集上拟合预处理器,然后应用到测试集,防止数据泄露。通过规范化的预处理流程,可以显著提升模型的泛化能力和预测精度。