感知机
1. 用途
感知机是二分类的新型分类模型,输入为实例的特征向量,输出为实例的类别,取+1,-1值。感知机对应于输入空间中将实例划分为正负两类的超平面,属于判别模型。
2. 感知机三要素
-
模型
从输入空间到输出空间的函数:
f ( x ) = s i g n ( w . x + b ) f(x) = sign(w.x+b) f(x)=sign(w.x+b)
称为感知机模型,其中sign()是符号函数,w和b是要求的模型参数。线性方程
w . x + b = 0 w.x + b = 0 w.x+b=0
对应于特征空间 R n R^n Rn中的一个分类超平面,其中w是超平面的法向量,b是超平面的截距。
-
学习策略(定义损失函数)
确定感知机的模型参数需要一个学习策略,即定义一个损失函数并将损失函数最小化,这里感知机的损失函数选择的是所有误分类点到分离超平面的距离之和。对于误分类的点 ( x i , y i ) (x_i, y_i) (xi,yi)来说,满足:
− y i ∗ ( w ⋅ x i + b ) ⩾ 0 -y_i*(w\cdot x_i + b) \geqslant 0 −yi∗(w⋅xi+b)⩾0
因此误分类点到分类超平面的距离是:
∣ w ⋅ x i + b ∣ / ∣ ∣ w ∣ ∣ = − y i ∗ ( w ⋅ x i + b ) / ∣ ∣ w ∣ ∣ |w\cdot x_i + b| / ||w|| = -y_i*(w\cdot x_i + b) / ||w|| ∣w⋅xi+b∣/∣∣w∣∣=−yi∗(w⋅xi+b)/∣∣w∣∣
其中 ∣ ∣ w ∣ ∣ ||w|| ∣∣w∣∣可以省去因为数据是新型可分的,也就是说正类和负类点可以完全分开,最后损失函数值为0,所以它对结果没有影响。所以最终损失函数为:
L ( w , b ) = − ∑ x i ϵ M y i ∗ ( w ⋅ x i + b ) L(w,b) = -\sum_{x_i\epsilon M}y_i*(w\cdot x_i + b) L(w,b)=−xiϵM∑yi∗(w⋅xi+b)
其中M是误差点的集合。
-
学习算法(随机梯度下降,一次只选一个数据点进行更新参数)
- 初始化 w w w和b为0向量和0数值。
- 在训练集中选取点 ( x i , y i ) (x_i, y_i) (xi,yi)
- 利用 − y i ∗ ( w ⋅ x i + b ) ⩾ 0 -y_i*(w\cdot x_i + b) \geqslant 0 −yi∗(w⋅xi+b)⩾0判断选取的点是否为误差点
- 如果是误差点,则更新参数 w w w和b: w : = w + l r ∗ y i ∗ x i w := w + lr*y_i*x_i w:=w+lr∗yi∗xi b : = b + l r ∗ y i b := b + lr*y_i b:=b+lr∗yi
- 跳转到第二步,直到对于新更新的模型来说数据集中没有误分类点
3. 感知机的python实现
import numpy as np
import matplotlib.pyplot as plt
# 定义一个感知机类
class MyPerception():
def __init__(self):
self.w = np.zeros(train.shape[1])
self.b = 0
self.lr = 1
def fit(self, train, y):
i = 0
while i < train.shape[0]:
# 判断该点是否为误分类点,如果是那么就开始更新参数,如果不是就不更新参数
if (y[i]*(self.w @ train[i].T + self.b)) <= 0:
self.w += self.lr * y[i] *train[i].T
self.b += self.lr*y[i]
i = 0 # 如果该点是误分类点,更新好模型后要重新从数据集中第一个元素取值
else:
i += 1
return self.w, self.b
def draw(train, y):
# 画出训练数据中的点
plt.scatter(train[:2, 0], train[:2, 1], marker='o', label='1')
plt.scatter(train[2, 0], train[2, 1], marker='x', label='-1')
# 画出分离超平面 w*x + b = 0 即 w0*x0 + w1*x1 + b = 0
x0 = np.array([0, 6]) # 生成分离超平面上两点的x0值
x1 = -(b + w[0]*x0) / w[1] # 生成两点对应的x1值
plt.plot(x0, x1, color='red')
plt.axis([0, 6, 0, 4]) # 设置两坐标轴的起始值,后面两个是x1轴的起始值。使得看起来美观一些
plt.xlabel('x0')
plt.ylabel('x1')
plt.legend()
plt.show()
if __name__ == "__main__":
# 创造一个数据集
train = np.array([[3, 3], [4, 3], [1, 1]])
y = np.array([1, 1, -1])
# 创建感知机类
perception = MyPerception()
w, b = perception.fit(train, y)
print(w, b)
draw(train, y)
下面是调用sklearn来实现感知机
from sklearn.linear_model import Perceptron
import numpy as np
train = np.array([[3, 3], [3, 4], [1, 1]])
y = np.array([1, 1, -1])
"""
penalty是正则化,可以选l1正则化:稀疏特征值数量,l2正则化:平均权重值使权重值不要相差过大,alpha是正则化系数,值越大表明对模型约束越大
eta0是学习率(0,1],tol是终止条件:上一次迭代损失值和这一次迭代损失之之差<tol,max_iter是最大迭代次数,如果tol不为0,则默认为1000
"""
# perceptron = Perceptron(penalty="l2", alpha=0.01, eta0=1, max_iter=50, tol=1e-3)
perceptron = Perceptron()
perceptron.fit(train, y)
print('w:{}, b:{}, n_iter:{}, acc:{:.1%}'.format(perceptron.coef_, perceptron.intercept_,
perceptron.n_iter_, perceptron.score(train, y)))
print(perceptron.predict(np.array([[2, 0]]))) # predict()方法用来给出新样本的预测值