《sklearn机器学习——数据预处理》离散化

发布于:2025-09-15 ⋅ 阅读:(19) ⋅ 点赞:(0)

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.01.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 Binarizer

corpus = [
    "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 预处理工具箱中的实用组件。