Menu
CoddyTech

类别不平衡

本课属于 Coddy Machine Learning 学习旅程的“监督学习”单元。第 24 课,共 58 课。

100 名患者中有 95 人健康时,一个总是预测患者健康的模型准确率为 95%,却一个病人也识别不出来。对于类别不平衡的数据,准确率会掩盖问题:

在患病患者占 5% 的数据上,三个模型的准确率和召回率柱状图。总是预测健康:准确率 0.95,召回率 0.00。普通模型:0.98 和 0.62。平衡模型:0.94 和 0.92

有两个修正。stratify=y 会让两组都保持 95 比 5 的比例,这样测试集中就会有患病患者可供检测。class_weight="balanced" 会让每个少数类样本占更大的权重:

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=0, stratify=y)
model = LogisticRegression(max_iter=1000, class_weight="balanced")

平衡模型牺牲了一点准确率,换来了捕获更多案例的能力。对于罕见案例,要看召回率和精确率,而不是准确率。

challenge icon

挑战

中等

工厂约有 5% 的轴承会提前损坏。起始代码会拆分测试台的记录,并评估一个普通模型,但它的测试集只有 2 个故障轴承,因此 0.993 这个数值意义不大。

  1. 修正拆分方式,让两组中的故障轴承占比相同。
  2. 训练第二个模型,提高故障行的权重,并按下面的格式打印结果行。

另一个测试台的数据:

Faulty bearings: train 8.1%, test 7.8%
Plain: accuracy 0.947, recall 0.417
Balanced: accuracy 0.900, recall 0.833

亲手试试

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, recall_score

# 测试台上的每个轴承对应一行:faulty 中的 1 表示该轴承不久后发生了故障
parts = pd.read_csv("bearings.csv")
features = ["vibration_mm_s", "temp_c", "noise_db", "hours_k"]
X = parts[features]
y = parts["faulty"]

# 修正这里的数据划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)
print(f"Faulty bearings: train {y_train.mean() * 100:.1f}%, test {y_test.mean() * 100:.1f}%")

scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

plain = LogisticRegression(max_iter=1000)
plain.fit(X_train, y_train)
pred = plain.predict(X_test)
print(f"Plain: accuracy {accuracy_score(y_test, pred):.3f}, recall {recall_score(y_test, pred):.3f}")

# 在下方编写你的代码
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

监督学习中的所有课

自己练习: Python 在线编译器