哈喽,大家好~
最近收到一个问题:“特征不是越精细越好吗?为什么还要把数据变成只有0和1?”
这个问题很常见。今天我们就来聊聊机器学习中的一种特征预处理方法:二值化(Binarization)。
整个文章,会讲清楚二值化是什么、什么时候有用,并通过一个完整的 Python 案例,观察它对分类模型效果的影响~
01二值化到底是什么?
假设我们有一个特征:用户每天登录次数。
0.5、1.2、3.8、6.0、10.5
如果我们设置阈值为 ,就可以把它变成:
0、0、1、1、1
也就是:低于等于阈值记为0,高于阈值记为1。
数学表达式如下:
其中, 是原始特征, 是阈值, 是二值化后的结果。
你可以这样理解:我们不再关心“登录了多少次”,只关心“是否超过了某个重要标准”。
在 sklearn 中,可以使用 Binarizer:
from sklearn.preprocessing import Binarizer
binarizer = Binarizer(threshold=0)
X_binary = binarizer.fit_transform(X)
这里的 threshold=0 表示:大于0变成1,小于等于0变成0。
02为什么要进行二值化?
二值化主要有几个使用场景。
第一,处理本身就具有“有或无”含义的数据,比如词语是否出现、用户是否点击、设备是否在线。
第二,降低异常值影响。原始数值可能从1到10000变化很大,但二值化后只保留是否超过阈值。
第三,让模型更容易学习某种规则。例如,当温度超过30度时,设备故障概率明显提高,这时“是否超过30度”可能比具体温度更有解释性。
但它也会损失信息。比如特征值分别是4和100,二值化后可能都变成1,模型无法区分它们。
一句话概括的话,就是二值化可以增强规则感,但会牺牲数值细节。
03完整案例
下面我们构造一个分类数据集,比较原始特征和二值化特征在逻辑回归中的表现。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, Binarizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, f1_score
from sklearn.decomposition import PCA
# 1. 数据
X, y = make_classification(
n_samples=2900,
n_features=6,
n_informative=4,
n_redundant=1,
n_clusters_per_class=2,
class_sep=1.15,
random_state=42
)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, stratify=y, random_state=42
)
# 2. 标准化,避免不同特征量纲影响阈值
scaler = StandardScaler()
X_train_std = scaler.fit_transform(X_train)
X_test_std = scaler.transform(X_test)
# 3. 原始特征模型
raw_model = LogisticRegression(max_iter=1000)
raw_model.fit(X_train_std, y_train)
raw_pred = raw_model.predict(X_test_std)
print("原始特征 Accuracy:",
round(accuracy_score(y_test, raw_pred), 3))
print("原始特征 F1:",
round(f1_score(y_test, raw_pred), 3))
# 4. 使用0阈值进行二值化
binarizer = Binarizer(threshold=0)
X_train_bin = binarizer.fit_transform(X_train_std)
X_test_bin = binarizer.transform(X_test_std)
bin_model = LogisticRegression(max_iter=1000)
bin_model.fit(X_train_bin, y_train)
bin_pred = bin_model.predict(X_test_bin)
print("二值化 Accuracy:",
round(accuracy_score(y_test, bin_pred), 3))
print("二值化 F1:",
round(f1_score(y_test, bin_pred), 3))
# 5. PCA投影:观察二值化前后的结构
pca = PCA(n_components=2)
X_all_std = scaler.transform(X)
X_all_pca = pca.fit_transform(X_all_std)
X_all_bin = Binarizer(threshold=0).fit_transform(X_all_std)
X_bin_pca = pca.fit_transform(X_all_bin)
plt.figure(figsize=(13, 5))
plt.subplot(1, 2, 1)
plt.scatter(X_all_pca[:, 0], X_all_pca[:, 1],
c=y, cmap="turbo", s=22, alpha=0.75)
plt.title("Standardized Features + PCA")
plt.xlabel("Principal Component 1")
plt.ylabel("Principal Component 2")
plt.colorbar(label="Class")
plt.subplot(1, 2, 2)
plt.scatter(X_bin_pca[:, 0], X_bin_pca[:, 1],
c=y, cmap="turbo", s=22, alpha=0.75)
plt.title("Binarized Features + PCA")
plt.xlabel("Principal Component 1")
plt.ylabel("Principal Component 2")
plt.colorbar(label="Class")
plt.tight_layout()
plt.show()
# 6. 比较不同阈值
thresholds = np.linspace(-1.5, 1.5, 25)
acc_list, f1_list = [], []
for threshold in thresholds:
transformer = Binarizer(threshold=threshold)
train_bin = transformer.fit_transform(X_train_std)
test_bin = transformer.transform(X_test_std)
model = LogisticRegression(max_iter=1000)
model.fit(train_bin, y_train)
pred = model.predict(test_bin)
acc_list.append(accuracy_score(y_test, pred))
f1_list.append(f1_score(y_test, pred))
plt.figure(figsize=(9, 5))
plt.plot(thresholds, acc_list, "o-", color="#ff3366",
linewidth=2.5, label="Accuracy")
plt.plot(thresholds, f1_list, "s-", color="#00b4d8",
linewidth=2.5, label="F1-score")
plt.axvline(0, color="#222222", linestyle="--",
label="Default threshold = 0")
plt.xlabel("Binarization Threshold")
plt.ylabel("Score")
plt.title("Model Performance under Different Thresholds")
plt.grid(alpha=0.25)
plt.legend()
plt.tight_layout()
plt.show()
第一张图中的 PCA 投影,是把多维数据压缩到二维后进行观察。左图保留了连续数值变化,样本位置通常更加平滑;右图经过二值化后,数据结构会变得更加离散,部分样本可能被压缩到相似区域。
这张图主要帮助我们判断:二值化是否让类别边界更清晰,还是把原本有用的差异抹掉了。
第二张图展示不同阈值下的 Accuracy 和 F1-score。可以看到,阈值并不是越大越好。阈值太低,很多样本会变成1;阈值太高,又可能让大量样本变成0。
所以,实际项目中不能默认使用0,而应该根据验证集效果、业务规则和类别不平衡情况选择阈值。
04使用二值化时要注意什么?
首先,阈值最好只使用训练集确定,不能提前看测试集,否则会造成数据泄漏。
其次,如果不同特征的量纲差异很大,建议先标准化,再进行统一阈值处理。否则,身高、收入、次数等特征直接使用同一个阈值,通常没有实际意义。
最后,二值化不适合所有任务。对于图像像素、传感器读数、价格等信息,数值大小本身往往很重要,直接变成0和1可能导致效果下降。
总结
二值化的核心,就是通过阈值把连续特征转换成0和1。它简单、可解释,适合表达“是否发生”“是否超过标准”这类问题。
但二值化会损失数值细节,阈值也会直接影响模型效果。你可以继续尝试:比较二值化与 MinMaxScaler、StandardScaler 的效果;或者针对每个特征单独搜索最佳阈值。
总之就是说,二值化不是让数据“更高级”,而是把复杂数值转换成更明确的规则。是否值得使用,要看数据特点和验证结果。
最后
最近准备了16大块的内容,124个算法问题的总结,完整的机器学习小册,免费领取~

