CHAPTER 09
机器学习入门(scikit-learn)
掌握机器学习的核心概念和工作流程。scikit-learn 提供了统一的 API,让你用几行代码就能训练和评估模型。
机器学习核心概念
核心概念
什么是机器学习?
机器学习是让计算机从数据中自动学习规律,而不是手动编写规则。传统编程:输入数据 + 规则 → 输出结果;机器学习:输入数据 + 期望结果 → 学出规则(模型)。
| 类型 | 特点 | 典型算法 | 应用场景 |
|---|---|---|---|
| 监督学习 | 有标签数据 | 线性回归、随机森林 | 房价预测、垃圾邮件分类 |
| 无监督学习 | 无标签数据 | K-Means、PCA | 用户聚类、降维 |
| 强化学习 | 通过奖惩学习 | PPO、DQN | 游戏 AI、机器人控制 |
关键概念
过拟合(Overfitting)与欠拟合(Underfitting)
过拟合:模型在训练集上准确率极高,但在新数据上表现差——死记硬背,不会举一反三。欠拟合:模型太简单,连训练集都学不好。理想状态是训练集和验证集准确率都高且相近。
scikit-learn 的统一 API
scikit-learn 最大的优点是所有算法都有统一的接口:fit() 训练,predict() 预测,score() 评分。换算法只需改一行代码。
PYTHON · scikit-learn 基础流程
from sklearn.datasets import load_iris
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, classification_report
# 1. 加载数据集(鸢尾花,经典入门数据集)
iris = load_iris()
X, y = iris.data, iris.target
print(f"特征形状: {X.shape}, 类别数: {len(set(y))}")
# 2. 切分数据集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 3. 特征标准化(零均值,单位方差)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train) # 在训练集上 fit
X_test = scaler.transform(X_test) # 测试集只用 transform!
# 4. 训练模型
model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train) # 两行搞定训练
# 5. 评估
y_pred = model.predict(X_test)
print(f"准确率: {accuracy_score(y_test, y_pred):.4f}")
print(classification_report(y_test, y_pred))
数据泄露(Data Leakage)陷阱
StandardScaler 必须在训练集上 fit,然后用同样的参数 transform 测试集。如果用测试集做 fit_transform,测试集的信息就"泄露"给了模型,评估结果会虚高。这是初学者最常犯的错误之一。
常用算法一览
scikit-learn 统一的 API 让换算法变得极其简单。了解各算法的特点,在合适的场景选对工具:
PYTHON · 换算法只需一行
from sklearn.linear_model import LogisticRegression, LinearRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
# 所有算法接口完全一样!
models = {
"逻辑回归": LogisticRegression(),
"决策树": DecisionTreeClassifier(max_depth=5),
"随机森林": RandomForestClassifier(n_estimators=100),
"梯度提升": GradientBoostingClassifier(),
"SVM": SVC(kernel="rbf"),
"KNN": KNeighborsClassifier(n_neighbors=5),
}
# 快速对比所有算法的效果
for name, clf in models.items():
clf.fit(X_train, y_train)
acc = clf.score(X_test, y_test)
print(f"{name:10s}: {acc:.4f}")
| 算法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 逻辑回归 | 可解释性强、速度快 | 只能线性决策边界 | 二分类基线模型 |
| 随机森林 | 强大、抗过拟合 | 黑盒、速度慢 | 结构化数据首选 |
| 梯度提升 (XGBoost) | Kaggle 竞赛冠军 | 参数多、训练慢 | 结构化数据最强 |
| SVM | 小数据集效果好 | 大数据慢、参数敏感 | 文本分类、小数据集 |
模型评估与交叉验证
单次划分训练/测试集的结果受随机性影响。交叉验证(Cross-Validation)通过多次不同划分取平均,得到更可靠的评估结果。
PYTHON · 评估指标与交叉验证
from sklearn.model_selection import cross_val_score, StratifiedKFold
from sklearn.metrics import (
accuracy_score, precision_score,
recall_score, f1_score, roc_auc_score,
confusion_matrix
)
model = RandomForestClassifier(n_estimators=100, random_state=42)
# 5折交叉验证
cv_scores = cross_val_score(model, X, y, cv=5, scoring="accuracy")
print(f"CV 准确率: {cv_scores.mean():.4f} ± {cv_scores.std():.4f}")
# 评估各指标(在测试集上)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(f"准确率 (Accuracy): {accuracy_score(y_test, y_pred):.4f}")
print(f"精确率 (Precision): {precision_score(y_test, y_pred, average='macro'):.4f}")
print(f"召回率 (Recall): {recall_score(y_test, y_pred, average='macro'):.4f}")
print(f"F1 Score: {f1_score(y_test, y_pred, average='macro'):.4f}")
# 混淆矩阵:可视化预测错误的分布
cm = confusion_matrix(y_test, y_pred)
print("混淆矩阵:\n", cm)
准确率不是万能的
如果正负样本比例严重不均(比如 99% 负样本),模型只要全预测负就有 99% 准确率,但毫无用处。这时应该用 F1 Score 或 AUC-ROC 来评估。在医疗 AI(疾病检测)中,召回率比准确率更重要——漏诊代价更高。
超参数调优
PYTHON · 网格搜索调参
from sklearn.model_selection import GridSearchCV
model = RandomForestClassifier(random_state=42)
# 定义要搜索的参数范围
param_grid = {
"n_estimators": [50, 100, 200],
"max_depth": [None, 5, 10],
"min_samples_split": [2, 5],
}
# 5折交叉验证 + 网格搜索
grid_search = GridSearchCV(
model, param_grid,
cv=5, scoring="f1_macro",
n_jobs=-1 # 用所有 CPU 核心并行
)
grid_search.fit(X_train, y_train)
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳得分: {grid_search.best_score_:.4f}")
# 用最佳参数的模型进行预测
best_model = grid_search.best_estimator_
final_score = best_model.score(X_test, y_test)
print(f"测试集得分: {final_score:.4f}")
调参的核心原则
不要在测试集上调参!正确流程:训练集训练 → 验证集(或交叉验证)调参 → 确定模型后最终用测试集评估一次。测试集必须保持"纯洁",代表真实未见数据。