Machine Learning: Scikit-learn入门 — 统一API与第一个ML模型完全指南
Scikit-learn的统一API让所有算法用同样的方式调用——学会一个,就会全部。
1. 你将学到
- Scikit-learn设计哲学与统一API:fit → predict → score
- Estimator/Transformer/Predictor三大接口详解
- 第一个模型:用Iris数据集训练决策树分类器,完整走通train-test-split → fit → predict → evaluate
- 数据预处理Pipeline:StandardScaler + 模型的链式组合
- Bob的首次尝试:用sklearn对SalesPredict小样本数据做简单预测
2. 一个ML新人的真实故事
(1) 痛点:每个算法的API都不一样
Bob尝试了3个不同的ML库,每个的调用方式都不同——一个用train(),一个用fit_model(),一个用learn()。他花了2天时间读文档才搞清楚怎么调用,换一个算法又要重新学。API不统一是ML入门的最大障碍。
(2) Scikit-learn的解法
Scikit-learn定义了统一的API设计:所有算法都遵循fit → predict → score三步法,换算法只需改一行。
PYTHON
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
# Same API, different algorithm - just change the model class
models = {
"LinearRegression": LinearRegression(),
"RandomForest": RandomForestRegressor(n_estimators=100),
}
for name, model in models.items():
model.fit(X_train, y_train)
score = model.score(X_test, y_test)
print(f"{name}: R² = {score:.3f}")
(3) 收益:学一个API覆盖30+算法
Bob掌握了sklearn的统一API后,30+种算法的调用方式全部统一——从LinearRegression到XGBoost,只需换一个类名。
3. Scikit-learn设计哲学与统一API
(1) 统一API模式
graph LR
A[Estimator<br/>Base Class] --> B[Transformer<br/>fit + transform]
A --> C[Predictor<br/>fit + predict]
A --> D[Model<br/>fit + predict + score]
B --> E[StandardScaler<br/>PCA<br/>OneHotEncoder]
C --> F[KMeans<br/>DBSCAN]
D --> G[LinearRegression<br/>RandomForest<br/>SVM]
(2) 三大接口
| 接口 | 核心方法 | 用途 | 示例 |
|---|---|---|---|
| Estimator | fit(X, y) |
从数据学习参数 | 所有模型的基类 |
| Transformer | fit() + transform() + fit_transform() |
数据预处理 | StandardScaler, PCA |
| Predictor | fit() + predict() |
预测输出 | LinearRegression, SVM |
▶ 示例:Estimator/Transformer/Predictor使用模式
PYTHON
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import numpy as np
# Generate sample data
rng = np.random.default_rng(42)
X = rng.uniform(0, 100, (200, 3))
y = 50 + 0.8 * X[:, 0] + 1.2 * X[:, 1] - 0.5 * X[:, 2] + rng.normal(0, 5, 200)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Transformer: StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train) # fit + transform in one step
X_test_scaled = scaler.transform(X_test) # only transform (use training stats)
# Predictor: LinearRegression
model = LinearRegression()
model.fit(X_train_scaled, y_train)
predictions = model.predict(X_test_scaled)
score = model.score(X_test_scaled, y_test)
print(f"R² score: {score:.4f}")
print(f"Coefficients: {model.coef_}")
print(f"Intercept: {model.intercept_:.2f}")
输出:
TEXT
📖 仅展示
# 执行成功
4. 第一个ML模型:Iris分类
(1) 完整ML工作流
▶ 示例:Iris决策树分类完整流程
PYTHON
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
# Step 1: Load data
iris = load_iris()
X, y = iris.data, iris.target
print(f"Features: {iris.feature_names}")
print(f"Classes: {iris.target_names}")
print(f"Shape: {X.shape}")
# Step 2: Split train/test
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
print(f"Train: {X_train.shape[0]}, Test: {X_test.shape[0]}")
# Step 3: Train model
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)
# Step 4: Predict
y_pred = model.predict(X_test)
# Step 5: Evaluate
acc = accuracy_score(y_test, y_pred)
print(f"\nAccuracy: {acc:.4f}")
print(f"\nClassification Report:\n{classification_report(y_test, y_pred, target_names=iris.target_names)}")
print(f"Confusion Matrix:\n{confusion_matrix(y_test, y_pred)}")
输出:
TEXT
📖 仅展示
Features: ['sepal length (cm)', 'sepal width (cm)', ...]
Classes: ['setosa' 'versicolor' 'virginica']
Shape: (150, 4)
Train: 105, Test: 45
Accuracy: 1.0000
▶ 示例:可视化决策树
PYTHON
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(12, 8))
plot_tree(model, feature_names=iris.feature_names,
class_names=iris.target_names, filled=True, ax=ax)
plt.title("Iris Decision Tree (max_depth=3)")
plt.tight_layout()
plt.savefig("iris_tree.png", dpi=150)
输出:
TEXT
📖 仅展示
# 执行成功
(2) train_test_split详解
| 参数 | 含义 | 推荐值 |
|---|---|---|
| test_size | 测试集比例 | 0.2-0.3 |
| random_state | 随机种子 | 42 (可复现) |
| stratify | 分层抽样 | 分类任务必须设置 |
| shuffle | 是否打乱 | 默认True |
5. 数据预处理Pipeline
(1) 为什么需要Pipeline
Pipeline将预处理和模型绑定为一个整体,避免数据泄露(测试集信息泄露到训练过程)。
▶ 示例:StandardScaler + 模型的Pipeline
PYTHON
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
iris = load_iris()
X, y = iris.data, iris.target
# Build pipeline
pipe = Pipeline([
("scaler", StandardScaler()),
("classifier", LogisticRegression(max_iter=200)),
])
# Cross-validation with pipeline (no data leakage!)
scores = cross_val_score(pipe, X, y, cv=5, scoring="accuracy")
print(f"CV Accuracy: {scores.mean():.4f} +/- {scores.std():.4f}")
# Fit on full data and predict
pipe.fit(X, y)
new_sample = [[5.1, 3.5, 1.4, 0.2]]
prediction = pipe.predict(new_sample)
print(f"Prediction: {iris.target_names[prediction[0]]}")
输出:
TEXT
📖 仅展示
# 执行成功
(2) Pipeline vs 手动预处理
| 维度 | 手动预处理 | Pipeline |
|---|---|---|
| 数据泄露风险 | 高(容易用测试集fit scaler) | 低(Pipeline自动隔离) |
| 代码可读性 | 分散 | 集中 |
| 交叉验证 | 需手动循环 | cross_val_score(pipe) |
| 部署便捷性 | 需分别保存scaler和model | 保存一个pipeline对象 |
▶ 示例:SalesPredict基线Pipeline
PYTHON
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
# Simulate SalesPredict data
rng = np.random.default_rng(42)
n = 500
df = pd.DataFrame({
"ad_spend": rng.uniform(10, 100, n),
"traffic": rng.uniform(100, 1000, n),
"category": rng.choice(["Elec", "Cloth", "Food"], n),
"is_weekend": rng.choice([0, 1], n),
})
df["revenue"] = 50 + 0.8 * df["ad_spend"] + 0.1 * df["traffic"] + rng.normal(0, 10, n)
# Define feature groups
num_features = ["ad_spend", "traffic"]
cat_features = ["category", "is_weekend"]
# ColumnTransformer for mixed preprocessing
preprocessor = ColumnTransformer([
("num", StandardScaler(), num_features),
("cat", OneHotEncoder(drop="first"), cat_features),
])
# Full pipeline
pipe = Pipeline([
("preprocessor", preprocessor),
("model", LinearRegression()),
])
X = df.drop(columns=["revenue"])
y = df["revenue"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
pipe.fit(X_train, y_train)
score = pipe.score(X_test, y_test)
print(f"SalesPredict Baseline R²: {score:.4f}")
# Predict
sample = pd.DataFrame({"ad_spend": [50], "traffic": [500], "category": ["Elec"], "is_weekend": [1]})
pred = pipe.predict(sample)
print(f"Predicted revenue: {pred[0]:.1f} thousand USD")
输出:
TEXT
📖 仅展示
# 执行成功
6. 模型评估基础
(1) 分类 vs 回归评估指标
| 任务 | 指标 | 含义 | sklearn函数 |
|---|---|---|---|
| 分类 | Accuracy | 正确率 | accuracy_score |
| 分类 | Precision | 精确率 | precision_score |
| 分类 | Recall | 召回率 | recall_score |
| 分类 | F1 | 精确与召回调和 | f1_score |
| 回归 | MAE | 平均绝对误差 | mean_absolute_error |
| 回归 | MSE | 均方误差 | mean_squared_error |
| 回归 | R² | 决定系数 | r2_score |
▶ 示例:回归模型全面评估
PYTHON
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import numpy as np
y_true = np.array([100, 150, 200, 250, 300])
y_pred = np.array([95, 160, 190, 260, 310])
mae = mean_absolute_error(y_true, y_pred)
mse = mean_squared_error(y_true, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_true, y_pred)
mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100
print(f"MAE: {mae:.2f} thousand USD")
print(f"RMSE: {rmse:.2f} thousand USD")
print(f"R²: {r2:.4f}")
print(f"MAPE: {mape:.1f}%")
输出:
TEXT
📖 仅展示
# 执行成功
❓ 常见问题
Q fit_transform和transform有什么区别?
A fit_transform = fit + transform,用于训练集(学习参数并转换);transform只用已学参数转换,用于测试集。测试集绝不能fit,否则数据泄露。
Q Pipeline的好处是什么?
A 三大好处——1) 防数据泄露(交叉验证时自动隔离fit/transform);2) 代码简洁(一个对象包含全部步骤);3) 部署方便(保存一个pickle文件)。
Q random_state=42是什么意思?
A 设置随机种子确保可复现。42是编程界的"答案"梗(来自《银河系漫游指南》),不影响结果质量。
Q stratify参数什么时候必须设置?
A 分类任务必须设置。stratify=y确保训练集和测试集中各类别比例与原始数据一致,避免小类别全被分到测试集。
Q cross_val_score的cv=5是什么意思?
A 5折交叉验证——数据分成5份,轮流用4份训练1份验证,最终取5次的平均。比单次train_test_split更可靠。
Q ColumnTransformer和Pipeline有什么区别?
A Pipeline是串联(上一步输出=下一步输入),ColumnTransformer是并联(不同列用不同转换器,最后合并)。通常两者组合使用。
📖 小节
- sklearn统一API:Estimator(fit) → Transformer(fit+transform) → Predictor(fit+predict+score)
- 完整ML流程:加载数据 → 拆分训练/测试 → fit训练 → predict预测 → score评估
- Pipeline将预处理+模型绑定为整体,防止数据泄露,简化部署
- ColumnTransformer处理混合类型特征(数值用StandardScaler,类别用OneHotEncoder)
- 分类评估用accuracy/precision/recall/F1,回归评估用MAE/RMSE/R²/MAPE
- cross_val_score实现交叉验证,比单次拆分更可靠
📝 作业
- 基础题(难度⭐):用sklearn加载Iris数据集,用LogisticRegression训练分类器,输出accuracy。提示:参考第4节的完整流程。
- 进阶题(难度⭐⭐):构建Pipeline(StandardScaler + LogisticRegression),用5折交叉验证对比有scaler和无scaler的accuracy差异。提示:Pipeline vs 单独model分别cross_val_score。
- 挑战题(难度⭐⭐⭐):用ColumnTransformer构建混合Pipeline处理SalesPredict数据(数值列标准化+类别列独热编码),然后用LinearRegression训练,计算R²和MAE。提示:参考第5节的SalesPredict Pipeline示例。