《统计学习方法》(李航 第二版)课后习题及其代码实现
学习解析优秀的代码,源文件为.ipynb格式
代码来自github项目:fengdu78/lihang-code:
《统计学习方法》的代码实现 (github.com)
第2章 感知机
第2章 感知机
1.感知机是根据输入实例的特征向量\(x\)对其进行二类分类的线性分类模型:
\[
f(x)=\operatorname{sign}(w \cdot x+b)
\]
感知机模型对应于输入空间(特征空间)中的分离超平面\(w \cdot x+b=0\)。
2.感知机学习的策略是极小化损失函数:
\[
\min _{w, b} L(w, b)=-\sum_{x_{i} \in M} y_{i}\left(w \cdot
x_{i}+b\right)
\]
损失函数对应于误分类点到分离超平面的总距离。
3.感知机学习算法是基于随机梯度下降法的对损失函数的最优化算法,有原始形式和对偶形式。算法简单且易于实现。原始形式中,首先任意选取一个超平面,然后用梯度下降法不断极小化目标函数。在这个过程中一次随机选取一个误分类点使其梯度下降。
4.当训练数据集线性可分时,感知机学习算法是收敛的。感知机算法在训练数据集上的误分类次数\(k\)满足不等式:
\[
k \leqslant\left(\frac{R}{\gamma}\right)^{2}
\]
当训练数据集线性可分时,感知机学习算法存在无穷多个解,其解由于不同的初值或不同的迭代顺序而可能有所不同。
二分类模型
\(f(x) = sign(w\cdot x + b)\)
\(\operatorname{sign}(x)=\left\{\begin{array}{ll}{+1,}
& {x \geqslant 0} \\ {-1,} &
{x<0}\end{array}\right.\)
给定训练集:
\(T=\left\{\left(x_{1},
y_{1}\right),\left(x_{2}, y_{2}\right), \cdots,\left(x_{N},
y_{N}\right)\right\}\)
定义感知机的损失函数
\(L(w, b)=-\sum_{x_{i} \in M} y_{i}\left(w
\cdot x_{i}+b\right)\)
算法
随即梯度下降法 Stochastic Gradient Descent
随机抽取一个误分类点使其梯度下降。
\(w = w + \eta y_{i}x_{i}\)
\(b = b + \eta y_{i}\)
当实例点被误分类,即位于分离超平面的错误侧,则调整\(w\), \(b\)的值,使分离超平面向该无分类点的一侧移动,直至误分类点被正确分类
拿出iris数据集中两个分类的数据和[sepal length,sepal width]作为特征
1 2 3 4 5
| import pandas as pd import numpy as np from sklearn.datasets import load_iris import matplotlib.pyplot as plt %matplotlib inline
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| iris = load_iris() df = pd.DataFrame(iris.data, columns=iris.feature_names) df['label'] = iris.target df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label'] df.label.value_counts()
plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], label='0') plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], label='1') plt.xlabel('sepal length') plt.ylabel('sepal width') plt.legend()
data = np.array(df.iloc[:100, [0, 1, -1]]) X, y = data[:, :-1], data[:, -1] y = np.array([1 if i == 1 else -1 for i in y])
|
Perceptron
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| # 数据线性可分,二分类数据 # 此处为一元一次线性方程
class Model: def __init__(self): self.w = np.ones(len(data[0]) - 1, dtype=np.float32) # 初始化权重向量w,长度为特征数减1,初始化为全1 self.b = 0 # 初始化偏置b为0 self.l_rate = 0.1 # 学习率设置为0.1
def sign(self, x, w, b): y = np.dot(x, w) + b # 计算样本x与权重w的点积加上偏置b return y
# 随机梯度下降法 def fit(self, X_train, y_train): is_wrong = False while not is_wrong: wrong_count = 0 for d in range(len(X_train)): X = X_train[d] # 获取第d个样本特征向量 y = y_train[d] # 获取第d个样本的标签 if y * self.sign(X, self.w, self.b) <= 0: # 如果样本被错误分类 self.w = self.w + self.l_rate * np.dot(y, X) # 更新权重向量w self.b = self.b + self.l_rate * y # 更新偏置b wrong_count += 1 if wrong_count == 0: is_wrong = True return 'Perceptron Model!'
def score(self): pass
perceptron = Model() # 创建Perceptron对象 perceptron.fit(X, y) # 使用训练集X和标签y训练感知器模型 x_points = np.linspace(4, 7, 10) # 在4到7之间生成10个等间距的点作为横轴数据 y_ = -(perceptron.w[0] * x_points + perceptron.b) / perceptron.w[1] # 根据感知器模型的权重和偏置计算对应的纵轴数据 plt.plot(x_points, y_) # 绘制分类边界线
plt.plot(data[:50, 0], data[:50, 1], 'bo', color='blue', label='0') # 绘制类别0的样本点,蓝色圆点 plt.plot(data[50:100, 0], data[50:100, 1], 'bo', color='orange', label='1') # 绘制类别1的样本点,橙色圆点 plt.xlabel('sepal length') # 设置横轴标签为'sepal length' plt.ylabel('sepal width') # 设置纵轴标签为'sepal width' plt.legend() # 添加图例
|
scikit-learn实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import sklearn from sklearn.linear_model import Perceptron sklearn.__version__
clf = Perceptron(fit_intercept=True, max_iter=1000, shuffle=True) clf.fit(X, y)
print(clf.coef_) print(clf.intercept_)
plt.figure(figsize=(10, 10))
plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False plt.title('鸢尾花线性数据示例')
plt.scatter(data[:50, 0], data[:50, 1], c='b', label='Iris-setosa') plt.scatter(data[50:100, 0], data[50:100, 1], c='orange', label='Iris-versicolor')
x_points = np.arange(4, 8) y_ = -(clf.coef_[0][0] * x_points + clf.intercept_) / clf.coef_[0][1] plt.plot(x_points, y_)
plt.legend() plt.grid(False) plt.xlabel('sepal length') plt.ylabel('sepal width') plt.legend()
|
现在可以看到,所有的两种鸢尾花都被正确分类了。
第2章感知机-习题
习题2.1
Minsky 与 Papert
指出:感知机因为是线性模型,所以不能表示复杂的函数,如异或
(XOR)。验证感知机为什么不能表示异或。
总的来说,在二维坐标系上画出的点位无法感知机的线性分类器的一条线性函数正确划分,因此无法使用感知机。(或许采用非线性分类器可以?
解答:
对于异或函数XOR,全部的输入与对应的输出如下:
1 |
1 |
-1 |
1 |
-1 |
1 |
-1 |
1 |
1 |
-1 |
-1 |
-1 |
参考代码:https://github.com/wzyonggege/statistical-learning-method
本文代码更新地址:https://github.com/fengdu78/lihang-code
习题解答:https://github.com/datawhalechina/statistical-learning-method-solutions-manual
中文注释制作:机器学习初学者公众号:ID:ai-start-com
配置环境:python 3.5+