《sklearn机器学习——数据预处理》离散化
sklearn 数据预处理中的离散化(Discretization)
离散化是将连续型数值特征转换为离散区间(分箱/bins)的过程,常用于简化模型、增强鲁棒性、处理非线性关系或满足某些算法对离散输入的要求(如朴素贝叶斯、决策树等)。sklearn 提供了两种主要的离散化方法:等宽分箱(KBinsDiscretizer) 和 等频分箱(使用
pd.qcut
等,但 sklearn 本身主要提供 KBinsDiscretizer)。
核心思想
- 离散化(Binning / Quantization):将连续变量的值域划分为若干个区间(称为“箱”或“bin”),然后用箱的索引或标签代替原始值。
- 目的:
- 降低噪声影响。
- 简化数据分布。
- 转换非线性关系为线性可分形式。
- 适配只能处理离散特征的模型。
常用函数或类
1.sklearn.preprocessing.KBinsDiscretizer
(K-bins离散化)
这是 sklearn 中用于离散化的主要类。
参数说明
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
n_bins | int 或 array-like, shape (n_features,) | 5 | 每个特征的分箱数量。若为整数,则所有特征使用相同箱数;若为数组,则分别指定每个特征的箱数。 |
encode | {‘onehot’, ‘onehot-dense’, ‘ordinal’} | ‘onehot’ | 编码方式: - 'ordinal' : 返回每个样本所属箱的整数索引(0 到 n_bins-1)- 'onehot' : 返回稀疏矩阵形式的独热编码- 'onehot-dense' : 返回稠密矩阵形式的独热编码 |
strategy | {‘uniform’, ‘quantile’, ‘kmeans’} | ‘quantile’ | 分箱策略: - 'uniform' : 等宽分箱(每个箱宽度相同)- 'quantile' : 等频分箱(每个箱样本数大致相同)- 'kmeans' : 使用一维 K-Means 聚类确定箱边界 |
属性(训练后可用)
属性 | 说明 |
---|---|
bin_edges_ | list of arrays, 每个特征的分箱边界(包含左右端点) |
n_bins_ | 实际每个特征使用的箱数(可能因数据分布调整) |
返回值
fit_transform(X)
或transform(X)
返回:- 若
encode='ordinal'
→ndarray
,形状(n_samples, n_features)
,值为箱索引(从0开始) - 若
encode='onehot'
→scipy.sparse.csr_matrix
- 若
encode='onehot-dense'
→ndarray
,形状(n_samples, n_features * n_bins)
- 若
简单示例代码
from sklearn.preprocessing import KBinsDiscretizer
import numpy as np# 生成示例数据
X = np.array([[1.2], [2.5], [3.7], [4.1], [5.8], [6.3], [7.9], [8.2], [9.6], [10.0]])print("原始数据:")
print(X.ravel())# 创建离散化器:3个箱,等宽策略,序数编码
discretizer = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform')# 拟合并转换
X_discretized = discretizer.fit_transform(X)print("\n离散化后(ordinal编码):")
print(X_discretized.ravel().astype(int))# 查看分箱边界
print("\n分箱边界:")
for i, edges in enumerate(discretizer.bin_edges_):print(f"特征 {i}: {edges}")# 使用 onehot-dense 编码
discretizer_onehot = KBinsDiscretizer(n_bins=3, encode='onehot-dense', strategy='uniform')
X_onehot = discretizer_onehot.fit_transform(X)print("\n离散化后(onehot-dense编码):")
print(X_onehot)
输出示例:
原始数据:
[ 1.2 2.5 3.7 4.1 5.8 6.3 7.9 8.2 9.6 10. ]离散化后(ordinal编码):
[0 0 0 1 1 1 2 2 2 2]分箱边界:
特征 0: [ 1.2 4. 6.8 10. ]离散化后(onehot-dense编码):
[[1. 0. 0.][1. 0. 0.][1. 0. 0.][0. 1. 0.][0. 1. 0.][0. 1. 0.][0. 0. 1.][0. 0. 1.][0. 0. 1.][0. 0. 1.]]
注意事项
- 数据分布影响:strategy=‘uniform’ 对异常值敏感;‘quantile’ 更鲁棒。
- 边界处理:边界值默认归入右侧箱(左闭右开),但最大值归入最后一个箱。
- 新数据转换:使用训练好的 discretizer.transform(X_new),超出训练范围的值会被分配到最近的箱(首箱或末箱)。
- 特征维度:支持多维特征,每个特征独立分箱。
应用场景
- 与朴素贝叶斯结合(要求离散特征)
- 减少过拟合(尤其在小数据集)
- 特征工程中构造分段线性模型
- 数据可视化分组统计
离散化是特征工程中强大而实用的技术,合理使用可显著提升模型性能与解释性。
2.sklearn.preprocessing.Binarizer
(Binarization 特征二值化)
🎯 核心思想
Binarizer
的核心思想是将数值型特征根据指定阈值(threshold)转换为二进制形式(0 或 1):
- 大于阈值 → 1
- 小于等于阈值 → 0
这是一种无监督、无状态的离散化方法,不依赖数据分布,仅根据预设阈值进行硬划分。常用于:
- 文本处理中将词频/TF-IDF 转换为“是否出现”
- 图像像素二值化(黑白化)
- 简化连续特征为布尔特征
⚙️ 参数详解
参数名 | 类型 | 默认值 | 说明 |
---|---|---|---|
threshold | float | 0.0 | 二值化阈值。当特征值 > threshold 时输出 1,否则输出 0。 |
copy | bool | True | 是否复制输入数据。若设为 False ,则尝试原地修改(仅当输入为 NumPy 数组且 dtype 兼容时有效)。 |
💡 注意:
Binarizer
是无状态转换器(stateless transformer) —— 它不从数据中学习任何参数,.fit()
方法仅用于接口兼容,不执行任何计算。
🧰 主要方法
方法 | 说明 |
---|---|
fit(X[, y]) | 什么都不做,直接返回 self 。用于兼容 sklearn 的 fit/transform 接口。 |
transform(X) | 对输入 X 执行二值化操作,返回二值化后的数组或稀疏矩阵。 |
fit_transform(X) | 等价于 .fit(X).transform(X) ,直接返回二值化结果。 |
📦 返回值
- 类型:与输入
X
类型一致(NumPy 数组或 scipy 稀疏矩阵) - 形状:与输入
X
形状相同(n_samples, n_features)
- 元素值:
0.0
或1.0
(dtype 通常为float64
,除非输入是整型且copy=False
) - 稀疏性:若输入是稀疏矩阵,输出也保持稀疏格式(节省内存)
🧪 简单示例代码
from sklearn.preprocessing import Binarizer
import numpy as np# 示例数据:3个样本,4个特征
X = np.array([[2.1, -1.5, 0.0, 3.3],[0.5, 4.0, -2.2, 1.1],[-0.3, 0.8, 1.7, -0.9]
])print("原始数据 X:")
print(X)
print("数据类型:", X.dtype)# 创建 Binarizer 实例,阈值设为 1.0
binarizer = Binarizer(threshold=1.0)# 执行二值化
X_binary = binarizer.fit_transform(X)print("\n二值化后(threshold=1.0):")
print(X_binary)
print("数据类型:", X_binary.dtype)
输出示例:
原始数据 X:
[[ 2.1 -1.5 0. 3.3][ 0.5 4. -2.2 1.1][-0.3 0.8 1.7 -0.9]]
数据类型: float64二值化后(threshold=1.0):
[[1. 0. 0. 1.][0. 1. 0. 1.][0. 0. 1. 0.]]
数据类型: float64
📚 实际应用场景:文本二值化
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.preprocessing import Binarizercorpus = ["apple banana apple","banana cherry","apple cherry banana"
]# 生成词频矩阵
vectorizer = CountVectorizer()
X_counts = vectorizer.fit_transform(corpus)
print("词频矩阵:")
print(X_counts.toarray())# 二值化:只关心词是否出现(>0 即为1)
binarizer = Binarizer(threshold=0)
X_binary = binarizer.fit_transform(X_counts)
print("\n二值化矩阵(是否出现):")
print(X_binary.toarray())
✅ 输出:
词频矩阵:
[[2 1 0][0 1 1][1 1 1]]二值化矩阵(是否出现):
[[1 1 0][0 1 1][1 1 1]]
⚠️ 注意事项
- 阈值选择很重要:例如图像常用 127(0~255),文本常用 0。
- 支持稀疏矩阵:对大型稀疏数据(如文本)非常高效。
- Pipeline 友好:可无缝集成到 sklearn Pipeline 中。
- 无状态性:可在训练集和测试集上直接使用,无需“学习”。
✅ 总结
Binarizer 是一个轻量、高效、无状态的特征二值化工具,适用于需要将连续值简化为布尔值的场景。其核心是阈值判断,使用简单,性能优异,是 sklearn 预处理工具箱中的实用组件。