1.感知机原理
感知机是Rosenblatt在1957年提出的,是神经网络与支持向量机的基础。
感知机是二分类的线性模型,其输入为实例的特征空间,输出为实例的类别,取+1和-1两个值,属于判别模型。
2.感知机模型
2.1 超平面的定义
令w1,w2,…wn,v都是实数® ,其中至少有一个wi不为零,由所有满足线性方程w1x1+w2x2+…+wnxn=v的点X=[x1,x2,…xn]组成的集合,称为空间R的超平面。
从定义可以看出:超平面就是点的集合。集合中的某一点X,与向量w=[w1,w2,…,wn]的内积,等于v
特殊地,如果令v等于0,对于训练集中某个点X:
wX=w1x1+w2x2+…+wnxn>0,将X标记为一类
wX=w1x1+w2x2+…+wn*xn<0,将X标记为另一类
2.2 数据集的线性可分性
对于数据集T= {(x1,y1),(x2,y2),…,(xn,yn)},其中,
x
i
∈
R
n
xi∈R^n
xi∈Rn,
y
i
∈
Y
=
+
1
,
−
1
yi∈Y={+1,-1}
yi∈Y=+1,−1,i=1,2,…,n
若存在某个超平面S: wx+b=0
将数据集中的所有样本点正确分类,即T为线性可分。
正确分类:若wxi>0,则(xi,yi)中yi=1;若wxi<0,则(xi,yi)中yi=-1
因此,给定超平面 wx=0,对于数据集 T中任何一个点(xi, yi),都有yi(w*xi)>0,这样T中所有的样本点都被正确地分类了。
如果有某个点(Xi, yi),使得yi(w*Xi)<0,则称超平面w*X对该点分类失败,这个点就是一个误分类的点。
2.3 感知机模型
其中w和b 称为模型的参数,
w
∈
R
n
w∈R^n
w∈Rn称为权值,b 称为偏置,w⋅x 表示 w和x 的内积
3.感知机学习算法
3.1 原始形式
思路:
总结:当一个实例点被误分的时候,即调整 w,b , 也就是调整 超平面所在的直线,让误分类的点划分到正确的一侧。
python实现算法核心代码:
def trainPerceptron(dataMat, labelMat,eta):
m,n = np.shape(np.mat(dataMat)) # mat生成数组,m是dataMat的样本点的个数,n是x的个数
w = np.zeros(n) # 初始化w与x一样大小的全0数组
b = 0
flag = True # 定义一个判断是否找到最优w和b的标志
while flag:
for i in range(m):
if np.any(labelMat[i] * (np.dot(w,dataMat[i]) + b)<= 0):
w = w + eta*np.dot(labelMat[i], dataMat[i])
b = b + eta*labelMat[i]
print("w, b:", w, b)
flag = True
break
else:
flag = False
return w, b
测试代码
import numpy as np
x = np.array([[3,3], [4,3], [1,1]])
y = [1, 1, -1]
eta = 1
trainPerceptron(x, y,eta)
结果
w, b: [3. 3.] 1
3.2 对偶形式
基本思想:
将
w
w
w 和
b
b
b 表示为实例
x
i
x_i
xi 和标记
y
i
y_i
yi线性组合的形式,通过求解其系数而求得
w
、
b
w、b
w、b 。假设
w
0
,
b
0
为
0
w0,b0为0
w0,b0为0,对误分类点
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi) 通过
w
=
w
+
η
y
i
x
i
w=w+ηy_ix_i
w=w+ηyixi
b
=
b
+
η
y
i
b=b+ηy_i
b=b+ηyi
逐步修改
w
,
b
w,b
w,b,设修改
n
n
n次,则
w
,
b
w,b
w,b 关于
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi)的增量分别为
α
i
y
i
x
i
α_iy_ix_i
αiyixi和
α
i
y
i
α_iy_i
αiyi, 其中
α
i
=
n
i
η
α_i=n_iη
αi=niη ,则最后学习到的
w
,
b
w,b
w,b可以分别表示为
w
=
∑
i
=
1
n
α
i
y
i
x
i
w=\displaystyle\sum_{i=1}^{n} α_iy_ix_i
w=i=1∑nαiyixi
b
=
∑
i
=
1
n
α
i
y
i
b=\displaystyle\sum_{i=1}^{n} αiyi
b=i=1∑nαiyi
这里,
α
i
≥
0
,
=
1
,
2
,
⋯
N
,
α
i
=
n
i
η
,
n
i
α_i≥0,=1,2,⋯N, α_i=n_iη ,n_i
αi≥0,=1,2,⋯N,αi=niη,ni 的意义是样本
i
i
i被误分的次数,所以当
η
=
1
η=1
η=1时,表示第
i
i
i 个样本由于被误分而更新的次数,实例点更新次数越多,表明它距离分离超平面越近,也就越难正确分类。
思路:
python实现算法核心代码:
def trainmodel(data, label,eta):
dataMat = np.mat(data)
labelMat = np.mat(label).transpose() #x.transpose()实现x的转置
b = 0
m,n = np.shape(dataMat) # m为样本点的个数,n为特征的个数
alpha = np.mat(np.zeros((m, 1)))
flag = True
while flag:
for i in range(m):
if label[i] * (float(np.multiply(alpha, labelMat).T*(dataMat*dataMat[i,:].T)) + b) <= 0:
alpha[i] = alpha[i] + eta
b = b + eta * labelMat[i]
w = np.multiply(labelMat, alpha).T*dataMat
print(i, alpha[i], w, b)
flag = True
break
else:
flag = False
w = (np.multiply(labelMat, alpha).T*dataMat).T
return w, b
测试代码
import numpy as np
x = np.array([[3,3], [4,3], [1,1]])
y = [1, 1, -1]
eta = 1
trainmodel(x, y,eta)
结果
0 [[1.]] [[3. 3.]] [[1]]
2 [[1.]] [[2. 2.]] [[0]]
2 [[2.]] [[1. 1.]] [[-1]]
2 [[3.]] [[0. 0.]] [[-2]]
0 [[2.]] [[3. 3.]] [[-1]]
2 [[4.]] [[2. 2.]] [[-2]]
2 [[5.]] [[1. 1.]] [[-3]]
out:(matrix([[1.],
[1.]]), matrix([[-3]]))
基于sklearn的感知机
# 下载python里面自带的digits数据集
from sklearn.datasets import load_digits
digits = load_digits()
#数据标准化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(digits.data)
x_scaled=scaler.transform(digits.data)
# 将数据和类分别赋予x,y:
x = x_scaled
y=digits.target
# 将数据和类分别赋予x,y:
x = x_scaled
y=digits.target
# 调用sklearn,使用感知机预测
from sklearn.neural_network import MLPClassifier
mlp=MLPClassifier(hidden_layer_sizes=(30,30,30),activation='logistic',max_iter=100)
mlp.fit(x_train,y_train)
out:MLPClassifier(activation='logistic', alpha=0.0001, batch_size='auto',
beta_1=0.9, beta_2=0.999, early_stopping=False, epsilon=1e-08,
hidden_layer_sizes=(30, 30, 30), learning_rate='constant',
learning_rate_init=0.001, max_iter=100, momentum=0.9,
nesterovs_momentum=True, power_t=0.5, random_state=None,
shuffle=True, solver='adam', tol=0.0001, validation_fraction=0.1,
verbose=False, warm_start=False)
# 进行预测,并观察结果:
from sklearn.metrics import classification_report
predicted=mlp.predict(x_test)
print(classification_report(y_test, predicted))
precision recall f1-score support
0 1.00 0.96 0.98 45
1 0.82 0.78 0.80 51
2 0.84 0.86 0.85 43
3 0.88 0.79 0.84 48
4 0.82 0.93 0.87 40
5 0.73 0.79 0.76 38
6 0.92 0.98 0.95 47
7 0.90 0.88 0.89 42
8 0.88 0.77 0.82 48
9 0.77 0.83 0.80 48
avg / total 0.86 0.86 0.86 450
# 进行调参,并观察参数改变对预测效果的影响:
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
if __name__ == '__main__':
pipeline = Pipeline([
('mlp',MLPClassifier(hidden_layer_sizes=(30,30,30),max_iter=100))
])
parameters = {
'mlp__activation': ('identity','logistic','tanh','relu'),
'mlp__solver': ('lbfgs','sgd','adam')
}
grid_search = GridSearchCV(pipeline, parameters,verbose=1,n_jobs=-1)
grid_search.fit(x_train, y_train)
print('最佳效果:%0.3f' % grid_search.best_score_)
print('最优参数:')
best_parameters = grid_search.best_estimator_.get_params()
for param_name in sorted(parameters.keys()):
print('\t%s: %r' % (param_name, best_parameters[param_name]))
predictions = grid_search.predict(x_test)
print(classification_report(y_test, predictions))
最佳效果:0.960
最优参数:
mlp__activation: 'relu'
mlp__solver: 'lbfgs'
precision recall f1-score support
0 0.98 0.98 0.98 45
1 0.92 0.94 0.93 51
2 0.98 1.00 0.99 43
3 1.00 0.98 0.99 48
4 0.98 1.00 0.99 40
5 0.95 0.95 0.95 38
6 1.00 0.96 0.98 47
7 1.00 0.95 0.98 42
8 0.90 0.96 0.93 48
9 0.98 0.96 0.97 48
avg / total 0.97 0.97 0.97 450