别再死记硬背了!用Python+Scikit-learn复现机器学习期末考点(决策树/神经网络/SVM实战)
用Python代码解锁机器学习核心概念:决策树、神经网络与SVM实战指南
期末考试前的死记硬背总是让人头疼,尤其是面对机器学习中那些抽象的理论概念。与其机械记忆公式和定义,不如打开Jupyter Notebook,用代码亲手构建这些算法模型。本文将带你用Scikit-learn库,通过实践理解决策树划分准则、神经网络反向传播和SVM核函数等核心考点。
1. 从理论到代码:建立机器学习思维框架
传统学习方式往往将理论与实践割裂,导致学生在考试中只能生硬地回忆定义。而代码驱动的学习方法能让你直观感受算法内部运作机制。比如,当你调整决策树的max_depth参数并观察准确率变化时,过拟合的概念会变得具体而清晰。
为什么代码实践比纯理论学习更有效?
- 视觉化理解 :数学公式在代码实现中转化为可观察的数据变化
- 即时反馈 :调整参数后能立即看到模型表现的变化
- 错误发现 :在代码调试过程中自然理解算法限制条件
- 知识留存 :动手操作形成的记忆比被动阅读更持久
我们先配置实验环境:
# 基础环境配置
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
# 常用数据集加载
iris = datasets.load_iris()
X_iris, y_iris = iris.data, iris.target
# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(
X_iris, y_iris, test_size=0.3, random_state=42)
2. 决策树:从划分准则到剪枝实战
决策树是理解机器学习基础概念的绝佳起点。通过代码实验,我们可以直观比较不同划分准则的效果,并观察剪枝如何影响模型泛化能力。
2.1 三种划分准则对比实现
Scikit-learn提供了决策树的完整实现,我们可以轻松比较信息增益、增益率和基尼指数:
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
# 不同划分准则的决策树
criteria = ['gini', 'entropy', 'log_loss']
results = {}
for criterion in criteria:
clf = DecisionTreeClassifier(criterion=criterion, random_state=42)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
acc = accuracy_score(y_test, y_pred)
results[criterion] = acc
# 结果对比
print("不同划分准则准确率:")
for criterion, acc in results.items():
print(f"{criterion}: {acc:.4f}")
关键观察点 :
- 基尼指数(gini)计算效率通常更高
- 信息增益(entropy)对类别分布更敏感
- 实际应用中差异可能不大,但理解原理对调参很重要
2.2 剪枝技术可视化实验
剪枝是解决决策树过拟合的核心技术。通过以下代码可以直观看到剪枝效果:
# 剪枝效果实验
depths = range(1, 10)
train_scores = []
test_scores = []
for depth in depths:
clf = DecisionTreeClassifier(max_depth=depth, random_state=42)
clf.fit(X_train, y_train)
train_scores.append(clf.score(X_train, y_train))
test_scores.append(clf.score(X_test, y_test))
# 绘制学习曲线
plt.figure(figsize=(10, 6))
plt.plot(depths, train_scores, 'o-', label='Training Accuracy')
plt.plot(depths, test_scores, 's-', label='Test Accuracy')
plt.xlabel('Tree Depth')
plt.ylabel('Accuracy')
plt.legend()
plt.title('Pre-pruning Effect on Model Performance')
plt.show()
这个实验清晰地展示了:
- 随着树深度增加,训练准确率持续提高
- 测试准确率在某个点达到峰值后开始下降(过拟合)
- 最佳深度是测试准确率最高的点
3. 神经网络:BP算法与过拟合控制
神经网络常被视为"黑箱",但通过代码拆解,我们可以理解其内部工作机制,特别是误差反向传播过程。
3.1 简单神经网络实现
使用Scikit-learn的MLPClassifier可以快速构建神经网络:
from sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import StandardScaler
# 数据标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 构建神经网络
mlp = MLPClassifier(hidden_layer_sizes=(10,),
activation='logistic',
solver='sgd',
learning_rate_init=0.1,
max_iter=1000,
random_state=42)
# 训练过程可视化
train_errors = []
test_errors = []
for i in range(100):
mlp.partial_fit(X_train_scaled, y_train, classes=np.unique(y_iris))
train_errors.append(1 - mlp.score(X_train_scaled, y_train))
test_errors.append(1 - mlp.score(X_test_scaled, y_test))
plt.figure(figsize=(10, 6))
plt.plot(train_errors, label='Training Error')
plt.plot(test_errors, label='Test Error')
plt.xlabel('Epochs')
plt.ylabel('Error Rate')
plt.legend()
plt.title('Neural Network Learning Process')
plt.show()
BP算法关键点 :
- 误差从输出层向输入层反向传播
- 权重根据误差梯度方向调整
- 学习率控制每次更新的步长
3.2 神经网络过拟合控制策略
神经网络特别容易过拟合,以下是几种实用策略的代码实现:
# 不同正则化强度对比
alphas = [0.0001, 0.001, 0.01, 0.1]
results = {}
for alpha in alphas:
mlp = MLPClassifier(hidden_layer_sizes=(10,),
alpha=alpha,
random_state=42)
mlp.fit(X_train_scaled, y_train)
train_score = mlp.score(X_train_scaled, y_train)
test_score = mlp.score(X_test_scaled, y_test)
results[alpha] = (train_score, test_score)
# 展示结果
print("正则化效果对比:")
for alpha, (train, test) in results.items():
print(f"Alpha={alpha}: Train={train:.4f}, Test={test:.4f}")
实用技巧 :
- 早停法(early stopping):监控验证集表现,停止在性能下降时
- Dropout:随机忽略部分神经元,增强鲁棒性
- 权重约束:限制权重大小,防止某些神经元主导决策
4. SVM:从线性可分到核技巧
支持向量机(SVM)的强大之处在于它能处理各种复杂的数据分布。通过代码实验,我们可以直观理解硬间隔、软间隔和核技巧的区别。
4.1 三种SVM类型实现
from sklearn.svm import SVC
# 生成不同分布的数据
X, y = datasets.make_classification(n_samples=100, n_features=2,
n_redundant=0, n_informative=2,
random_state=1, n_clusters_per_class=1)
# 添加噪声制造近似线性可分情况
rng = np.random.RandomState(42)
X_noisy = X.copy()
X_noisy[:10] += 2 * rng.randn(10, 2)
# 三种SVM模型
models = {
'Linear SVM (hard margin)': SVC(kernel='linear', C=1000),
'Linear SVM (soft margin)': SVC(kernel='linear', C=0.1),
'RBF Kernel SVM': SVC(kernel='rbf', gamma=1, C=1)
}
# 可视化决策边界
plt.figure(figsize=(15, 5))
for i, (title, model) in enumerate(models.items()):
model.fit(X_noisy, y)
# 绘制决策边界
plt.subplot(1, 3, i+1)
plt.scatter(X_noisy[:, 0], X_noisy[:, 1], c=y, s=30, cmap=plt.cm.Paired)
ax = plt.gca()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
# 创建网格评估模型
xx = np.linspace(xlim[0], xlim[1], 30)
yy = np.linspace(ylim[0], ylim[1], 30)
YY, XX = np.meshgrid(yy, xx)
xy = np.vstack([XX.ravel(), YY.ravel()]).T
Z = model.decision_function(xy).reshape(XX.shape)
# 绘制决策边界和间隔
ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1],
alpha=0.5, linestyles=['--', '-', '--'])
ax.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1],
s=100, linewidth=1, facecolors='none', edgecolors='k')
plt.title(title)
plt.tight_layout()
plt.show()
关键区别 :
- 硬间隔:严格要求所有样本正确分类,对噪声敏感
- 软间隔:允许部分样本分类错误,提高泛化能力
- 核方法:将数据映射到高维空间解决非线性问题
4.2 SVM核函数选择与调参
核函数是SVM处理非线性问题的关键,不同核函数适用于不同数据分布:
# 不同核函数比较
kernels = ['linear', 'poly', 'rbf', 'sigmoid']
results = {}
for kernel in kernels:
svm = SVC(kernel=kernel, random_state=42)
svm.fit(X_train, y_train)
train_score = svm.score(X_train, y_train)
test_score = svm.score(X_test, y_test)
results[kernel] = (train_score, test_score)
# 结果展示
print("核函数性能对比:")
for kernel, (train, test) in results.items():
print(f"{kernel}核: Train={train:.4f}, Test={test:.4f}")
调参建议 :
- 线性核:适合高维特征,训练速度快
- RBF核:默认选择,适合大多数情况
- 多项式核:适合特定领域知识表明多项式关系存在时
- Sigmoid核:特定情况下使用,效果通常不如RBF
5. 模型评估:从准确率到学习曲线
理解各种评估指标并能正确应用是机器学习考试的重点。通过代码生成这些指标,比记忆定义更有助于理解。
5.1 综合评估指标实现
from sklearn.metrics import classification_report, confusion_matrix, roc_curve, auc
from sklearn.preprocessing import label_binarize
# 多分类评估指标
y_pred = mlp.predict(X_test_scaled)
print("分类报告:\n", classification_report(y_test, y_pred))
# 混淆矩阵可视化
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)
plt.title('Confusion Matrix')
plt.colorbar()
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
plt.show()
# ROC曲线(二分类示例)
y_test_bin = label_binarize(y_test, classes=[0, 1, 2])
y_score = mlp.predict_proba(X_test_scaled)
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(3): # 每个类别单独绘制
fpr[i], tpr[i], _ = roc_curve(y_test_bin[:, i], y_score[:, i])
roc_auc[i] = auc(fpr[i], tpr[i])
plt.figure(figsize=(10, 8))
for i in range(3):
plt.plot(fpr[i], tpr[i],
label='ROC curve of class {0} (area = {1:0.2f})'.format(i, roc_auc[i]))
plt.plot([0, 1], [0, 1], 'k--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Multi-class ROC')
plt.legend(loc="lower right")
plt.show()
5.2 偏差-方差分解实验
理解偏差和方差是诊断模型问题的关键。通过以下代码可以直观看到两者的权衡:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
# 生成非线性数据
np.random.seed(42)
X = np.random.uniform(-3, 3, size=100)
y = 0.5 * X**2 + X + 2 + np.random.normal(0, 1, size=100)
X = X.reshape(-1, 1)
# 不同复杂度模型
degrees = [1, 2, 10]
plt.figure(figsize=(15, 5))
for i, degree in enumerate(degrees):
polynomial_features = PolynomialFeatures(degree=degree, include_bias=False)
linear_regression = LinearRegression()
pipeline = Pipeline([("pf", polynomial_features), ("lr", linear_regression)])
pipeline.fit(X, y)
# 可视化拟合结果
plt.subplot(1, 3, i+1)
plt.scatter(X, y, s=20, edgecolor="black", c="darkorange", label="data")
X_test = np.linspace(-3, 3, 100).reshape(-1, 1)
plt.plot(X_test, pipeline.predict(X_test), color="cornflowerblue",
label="degree %d" % degree, linewidth=2)
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.title("Degree {}\nMSE = {:.2f}".format(
degree, np.mean((y - pipeline.predict(X))**2)))
plt.tight_layout()
plt.show()
实验结论 :
- 1次多项式(线性):高偏差,欠拟合
- 2次多项式:偏差和方差平衡良好
- 10次多项式:高方差,过拟合
更多推荐
所有评论(0)