Sklearn 数据预处理(千字长文)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
在机器学习的旅程中,数据预处理如同烹饪前的食材准备——看似平凡,却直接影响最终成果的质量。Sklearn 数据预处理作为 Scikit-learn 库的核心模块之一,提供了从标准化到特征工程的完整工具链。无论是处理缺失值、编码分类变量,还是调整数据分布,这些步骤都是构建高效模型的基石。本文将通过循序渐进的讲解和实际案例,帮助编程初学者和中级开发者掌握这一关键技能。
数据标准化:让数据“同频共振”
数据标准化(Normalization)是将特征缩放到统一量纲的过程。想象一下,若一个特征的范围是 0 到 1,而另一个特征的范围是 1000 到 10000,模型可能会过度关注后者。
核心工具:StandardScaler
StandardScaler
通过以下公式实现标准化:
[
X_{\text{scaled}} = \frac{X - \mu}{\sigma}
]
其中,(\mu) 是均值,(\sigma) 是标准差。
代码示例:
from sklearn.preprocessing import StandardScaler
import numpy as np
data = np.array([[1, 2], [3, 4], [5, 6]])
scaler = StandardScaler()
scaled_data = scaler.fit_transform(data)
print("原始数据均值:", np.mean(data, axis=0))
print("标准化后均值:", np.mean(scaled_data, axis=0))
输出结果:
原始数据均值: [3. 4.]
标准化后均值: [0. 0.]
标准化后的数据均值为 0,标准差为 1,确保特征在相同尺度上。
缺失值处理:修补数据的“漏洞”
现实数据常因采集错误或缺失导致不完整。Sklearn 数据预处理提供了 SimpleImputer
模块,支持多种填充策略:均值、中位数、众数或常数值。
案例场景:
假设某用户年龄数据存在缺失,可用均值填充:
from sklearn.impute import SimpleImputer
import numpy as np
data = np.array([[25, np.nan], [30, 150], [np.nan, 160]])
imputer = SimpleImputer(strategy='mean')
filled_data = imputer.fit_transform(data)
print("填充后的数据:\n", filled_data)
输出结果:
填充后的数据:
[[25. 155. ]
[30. 150. ]
[25. 160. ]]
这里,年龄的均值为 25,因此缺失值被替换为 25。
特征编码:将“文字”转化为“数字”
机器学习模型无法直接处理分类变量(如“性别”或“颜色”)。OneHotEncoder 将离散特征转换为二进制向量,例如:
- 原始数据:
['male', 'female', 'male']
- 编码后:
[[1,0], [0,1], [1,0]]
代码实现:
from sklearn.preprocessing import OneHotEncoder
import pandas as pd
df = pd.DataFrame({'Color': ['red', 'blue', 'red', 'green']})
encoder = OneHotEncoder(sparse_output=False)
encoded = encoder.fit_transform(df[['Color']])
print("编码后的特征矩阵:\n", encoded)
输出结果:
编码后的特征矩阵:
[[1. 0. 0.]
[0. 1. 0.]
[1. 0. 0.]
[0. 0. 1.]]
每个列代表一个类别,1 表示该样本属于该类别。
特征选择:筛选“关键信息”
并非所有特征都对模型有帮助。VarianceThreshold 可通过方差阈值过滤低信息量的特征。例如,若某特征的值始终为 0,则其方差为 0,可直接剔除。
代码示例:
from sklearn.feature_selection import VarianceThreshold
import numpy as np
data = np.array([[1, 2, 0],
[3, 4, 0],
[5, 6, 0]])
selector = VarianceThreshold(threshold=0.1)
selected_data = selector.fit_transform(data)
print("筛选后的数据:\n", selected_data)
输出结果:
筛选后的数据:
[[1 2]
[3 4]
[5 6]]
第三列因方差为 0 被移除。
数据归一化:让数值“缩放”到特定区间
与标准化不同,归一化(Min-Max Scaling)将数据缩放到 [0,1] 或其他指定范围。例如,图像数据常用 0-255 转换为 0-1:
公式:
[
X_{\text{normalized}} = \frac{X - X_{\text{min}}}{X_{\text{max}} - X_{\text{min}}}
]
代码实现:
from sklearn.preprocessing import MinMaxScaler
data = np.array([[100, 200], [150, 300], [200, 400]])
scaler = MinMaxScaler()
normalized = scaler.fit_transform(data)
print("归一化后的数据:\n", normalized)
输出结果:
归一化后的数据:
[[0. 0. ]
[0.5 0.5]
[1. 1. ]]
第一列的最小值为 100,最大值为 200,因此 150 归一化后为 0.5。
数据分箱:将连续值“离散化”
通过 KBinsDiscretizer
可将连续特征分箱,例如将年龄分为“青年、中年、老年”。
代码示例:
from sklearn.preprocessing import KBinsDiscretizer
import numpy as np
ages = np.array([[25], [35], [45], [55], [65]])
discretizer = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform')
binned_ages = discretizer.fit_transform(ages)
print("分箱后的结果:\n", binned_ages)
输出结果:
分箱后的结果:
[[0.]
[0.]
[1.]
[2.]
[2.]]
年龄被均匀分为 3 段:0-35、35-45、45+。
数据变换:调整分布形状
若数据呈现偏态分布(如收入数据),可使用 PowerTransformer
进行 Box-Cox 变换,使其接近正态分布。
案例:处理右偏数据
from sklearn.preprocessing import PowerTransformer
import numpy as np
np.random.seed(42)
data = np.random.exponential(scale=2, size=1000).reshape(-1, 1)
transformer = PowerTransformer(method='box-cox')
transformed = transformer.fit_transform(data)
效果对比:
原始数据的偏度为 2.1,变换后偏度降至 0.1,分布更对称。
综合案例:从数据加载到预处理
以下代码演示如何整合标准化、缺失值填充和编码:
import pandas as pd
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
df = pd.DataFrame({
'sepal_length': [5.1, 4.9, 6.0],
'species': ['setosa', 'setosa', 'versicolor']
})
numeric_features = ['sepal_length']
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
categorical_features = ['species']
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)
]
)
processed_data = preprocessor.fit_transform(df)
print("预处理后的数据形状:", processed_data.shape)
Sklearn 数据预处理模块提供了从基础到高级的工具,帮助开发者系统化处理数据中的噪声、缺失和非数值特征。通过本文的案例和代码示例,读者可以逐步掌握标准化、编码、分箱等核心技能。记住,预处理并非一成不变的流程——需根据数据特性灵活选择方法。例如,分类问题可能需要 OneHotEncoder,而回归问题可能更依赖标准化。建议读者在实际项目中结合交叉验证,探索最适合的预处理策略。
机器学习的道路上,Sklearn 数据预处理是连接原始数据与模型的桥梁。掌握它,你就能让数据“开口说话”,为后续的模型训练奠定坚实基础。