参考资料:
1.李航《统计学习方法》;
2. github: https://github.com/fengdu78/lihang-code
感知机(perceptron)是二类分类的线性分类模型,其输入为实例的特征向量,输出为实例的类别,取值为+1,-1
感知机对应于输入空间中将实例划分成正负两类的分离超平面,属于判别模型
感知机学习旨在求出将训练数据进行线性划分的分离超平面为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化,求得感知机模型
感知机模型
假设输入空间是
χ
⊆
R
n
\chi \subseteq R^{n}
χ⊆Rn,输出空间是
y
=
{
+
1
,
−
1
}
y=\{+1,-1\}
y={+1,−1},输入
x
∈
χ
x\in \chi
x∈χ表示实例的特征向量,对应于输入空间
的点,输出
y
∈
Y
y\in Y
y∈Y表示实例的类别,由输入空间到输出空间的如下函数,称为感知机:(
w
,
b
w,b
w,b表示感知机模型的参数)
f
(
x
)
=
s
i
g
n
(
w
x
+
b
)
f(x)=sign(wx+b)
f(x)=sign(wx+b)
感知机的几何解释:
线性方程
w
x
+
b
=
0
wx+b=0
wx+b=0对应于特征空间
R
n
R^{n}
Rn中的一个超平面
S
S
S,其中
w
w
w是超平面的法向量,
b
b
b是超平面的截距, 超平面
S
S
S称为分离超平面
感知机学习的训练数据集为:
T
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
N
,
y
N
)
}
,
x
i
∈
R
n
,
y
i
∈
{
+
1
,
−
1
}
,
i
=
1
,
2
,
.
.
.
,
N
T=\{(x_{1},y_{1}),(x_{2},y_{2}),...,(x_{N},y_{N})\},x_{i} \in R^{n}, y_{i} \in \{{+1,-1}\},i=1,2,...,N
T={(x1,y1),(x2,y2),...,(xN,yN)},xi∈Rn,yi∈{+1,−1},i=1,2,...,N
感知机学习策略
感知机训练数据集是线性可分的,感知机学习的目标就是求得一个能够将训练集的正实例点和负实例点完全正确分开的分离超平面,即确定感知机模型参数,需要确定一个学习策略,即定义损失函数,并将损失函数极小化
输入空间
R
n
R^{n}
Rn中的任意一点
x
0
x_{0}
x0到超平面
S
S
S的距离:
∣
w
x
0
+
b
∣
∥
w
∥
,
∥
w
∥
是
w
的
L
2
范
数
\frac {|wx_{0}+b|}{\|w\|},\|w\|是w的L_{2}范数
∥w∥∣wx0+b∣,∥w∥是w的L2范数
对误分类的数据
(
x
i
,
y
i
)
(x_{i},y_{i})
(xi,yi)来说,
−
y
i
(
w
x
i
+
b
)
>
0
成
立
-y_{i}(wx_{i}+b)>0成立
−yi(wxi+b)>0成立
因为当
w
x
i
+
b
>
0
时
,
y
i
=
−
1
,
而
w
x
i
+
b
<
0
时
,
y
i
=
+
1
wx_{i}+b>0时,y_{i}=-1,而wx_{i}+b<0时,y_{i}=+1
wxi+b>0时,yi=−1,而wxi+b<0时,yi=+1,因而,误分类点到超平面
s
s
s的距离为:
−
y
i
w
x
i
+
b
∥
w
∥
-y_{i} \frac {wx_{i}+b}{\|w\|}
−yi∥w∥wxi+b
假设超平面S的误分类点集合为M,那么所有的误分类点到超平面
S
S
S的总距离为
−
1
∥
w
∥
∑
x
i
∈
M
y
i
(
w
x
i
+
b
)
- \frac {1}{\|w\|} \sum _{x_{i} \in M}y_{i} (wx_{i}+b)
−∥w∥1xi∈M∑yi(wxi+b)
不考虑 1 ∥ w ∥ \frac1{\|w\|} ∥w∥1,就得到感知机学习的损失函数(经验风险函数)
显然损失函数
L
(
w
,
b
)
L(w,b)
L(w,b)是非负的,如果没有误分类点,损失函数据就是0,而且误分类点越少,误分类点离超平面越近,
损失函数值越小
感知机学习算法
给定一个训练集:
T
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
N
,
y
N
)
}
T=\{(x_{1},y_{1}),(x_{2},y_{2}),...,(x_{N},y_{N})\}
T={(x1,y1),(x2,y2),...,(xN,yN)}
使得损失函数最小化: min w , b L ( w , b ) = − ∑ x i ∈ M y i ( w x i + b ) , M 为 误 分 类 点 的 集 合 \min \limits_{w,b}L(w,b)=-\sum _{x_{i} \in M}y_{i} (wx_{i}+b),M为误分类点的集合 w,bminL(w,b)=−∑xi∈Myi(wxi+b),M为误分类点的集合
感知机学习算法是误分类驱动的,具体采用随机梯度下降的方法,损失函数的梯度如下所示:
▽
w
L
(
w
,
b
)
=
−
∑
x
i
∈
M
y
i
x
i
\bigtriangledown _{w}L(w,b)=-\sum _{x_{i} \in M}y_{i}x_{i}
▽wL(w,b)=−xi∈M∑yixi
▽
b
L
(
w
,
b
)
=
−
∑
x
i
∈
M
y
i
\bigtriangledown _{b}L(w,b)=-\sum _{x_{i} \in M}y_{i}
▽bL(w,b)=−xi∈M∑yi
随机选取一个为误分类点,对
w
,
b
w,b
w,b进行更新:
w
←
w
+
η
y
i
x
i
,
b
←
b
+
η
y
i
w\leftarrow w+\eta y_{i}x_{i},b\leftarrow b+\eta y_{i}
w←w+ηyixi,b←b+ηyi
Algorithm
输入:训练数据集
T
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
N
,
y
N
)
}
T=\{(x_{1},y_{1}),(x_{2},y_{2}),...,(x_{N},y_{N})\}
T={(x1,y1),(x2,y2),...,(xN,yN)} ,其中
x
i
∈
R
n
,
y
i
∈
{
+
1
,
−
1
}
,
i
=
1
,
2
,
.
.
.
,
N
x_{i} \in R^{n}, y_{i} \in \{{+1,-1}\},i=1,2,...,N
xi∈Rn,yi∈{+1,−1},i=1,2,...,N
学习率 ?,(0<?≤1) ;
输出:
w
,
b
w,b
w,b ; 感知机模型:
f
(
x
)
=
s
i
g
n
(
w
x
+
b
)
f(x)=sign(wx+b)
f(x)=sign(wx+b)
(1)选取初值 w 0 , b 0 w_{0},b_{0} w0,b0 ;
(2)在训练集中选取数据 ( x i , y i ) (x_{i},y_{i}) (xi,yi) ;
(3)如果 y i ( w x i + b ) ≤ 0 y_{i}(wx_{i}+b)\leq0 yi(wxi+b)≤0 : w ← w + η y i x i , b ← b + η y i w\leftarrow w+\eta y_{i}x_{i},b\leftarrow b+\eta y_{i} w←w+ηyixi,b←b+ηyi;
(4)转置(2),直至模型中没有误分类点.
examples
拿出iris数据集中两个分类的数据和[sepal length, sepal width]作为特征
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
# 导入鸢尾花数据集
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]['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
class Model:
def __init__(self):
self.w = np.ones(len(data[0])-1, dtype=np.float32)
self.b = 0
self.l_rate = 0.1
def sign(self, x, w, b):
y = np.dot(x, w) + b
return y
def fit(self, X_train, y_train):
iswrong = False
while not iswrong:
wrong_count = 0
for d in range(len(X_train)):
X = X_train[d]
y = y_train[d]
if y * self.sign(X, self.w, self.b)<=0:
self.w = self.w + self.l_rate * np.dot(y,X)
self.b = self.b + self.l_rate * y
wrong_count += 1
if wrong_count == 0:
iswrong = True
return "Perceptron Model"
perceptron = Model()
perceptron.fit(X, y)
x_points = np.linspace(4,8,10)
y_ = -(perceptron.w[0]*x_points + perceptron.b)/perceptron.w[1]
plt.plot(x_points, y_, color='black')
plt.plot(data[:50,0], data[:50,1], 'bo', color='blue', label='0')
plt.plot(data[50:100,0], data[50:100,1], 'bo', color='orange', label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.legend()
使用sklearn进行感知机模型训练
from sklearn.linear_model import Perceptron
clf = Perceptron(fit_intercept=False, max_iter=1000, shuffle=False)
clf.fit(X,y)
print(clf.coef_)
print(clf.intercept_)
x_points = np.linspace(4,7,10)
y_ = -(clf.coef_[0][0]*x_points + clf.intercept_)/clf.coef_[0][1]
plt.plot(x_points, y_)
plt.plot(data[:50,0], data[:50,1], 'bo', color='blue', label='0')
plt.plot(data[50:100,0], data[50:100,1], 'bo', color='orange', label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.legend()