目录
统计学习方法——感知机
2.1 感知机模型
2.2.1 数据集的线性可分性
2.2.2 感知机学习策略
2.3 感知机学习算法
2.4 python实现
运行结果
reference
统计学习方法——感知机
感知机(perceptron)是二类分类的线性分类模型,输入为实例的特征向量,输出为实例的类别,取+1和-1二值。感知机对应与输入空间(特征空间)中将实例划分为正负两类的分离超平面,属于判别模型。
2.1 感知机模型
2.2.1 数据集的线性可分性
上述定义通俗来说,假如在二维平面,有一条直线可以把两类数据分开, 就是线性可分数据, 分不开就是线性不可分
如图2.1
2.2.2 感知机学习策略
输入空间
到任意一点
到超平面S的距离:
为方便统一,一般将任意向量x的
-范数定义为:
对于误分类点
来说:
成立,
因为
,此时
,同理,因为
,此时
误分类点到超平面S的距离是:
假设误分类点集合为M,所有误分类点到S的总距离为:
因为最终误分类点为零,所有不必考虑
,得到最终的损失函数为:
2.3 感知机学习算法
感知机是误分类驱动的,任取一个超平面
,采用随机梯度下降算法(stochasticc gradient descent)极小化目标函数。
解:构建最优化模型:
(1) 取初值
(2) 第一次迭代: 对
,
,
未正确分类,更新
,
得到线性模型:
第二次迭代: 对
未正确分类,更新
,
得到线性模型:
第三次迭代: 对
未正确分类,更新
,
得到线性模型:
第四次迭代: 对
未正确分类,更新
,
得到线性模型:
第五次迭代: 对
未正确分类,更新
,
得到线性模型:
第六次迭代: 对
未正确分类,更新
,
得到线性模型:
第七次迭代: 对
未正确分类,更新
,
得到线性模型:
误分类点为0,迭代结束,表格如下
2.4 python实现
# -*- coding: utf-8 -*-
# @Time : 2020/11/16 19:20
# @Author : gwk
# @File : Perceptron.py
import numpy as np
import random
import matplotlib.pyplot as plt
def createdata():
"""
创建数据
:return:返回特征和标签
"""
# data = []
# for i in range(100):
# x = random.randint(0, 100)
# y = random.randint(0, 100)
# if x + y > 100:
# data.append(((x, y), 1))
# elif x + y < 100:
# data.append(((x, y), -1))
# train = data
train = [((3, 3), 1), ((4, 3), 1), ((1, 1), -1)]
feature = []
label = []
for i in train:
feature.append(i[0])
label.append(i[1])
feature = np.array(feature)
label = np.array(label)
return feature, label
class perceptron:
def __init__(self):
self.w = np.array([0, 0])
self.b = 0
self.learning_rate = 1
def updata(self, w, b, x, y):
"""
更新w,b
:param w: 权重(weight)
:param b: 偏置(bias)
:param x: 特征向量
:param y: 标签
:return: 无
"""
self.w = w + self.learning_rate*y*x
self.b = b + self.learning_rate*y
def sign(self, w, x, b):
"""
符号函数
:param w:
:param x:
:param b:
:return: 返回+1或-1
"""
return np.sign(np.dot(w, x) + b)
def train_random(self, feature, label):
"""
随机梯度下降法训练模型
:param feature:特征
:param label: 标签
:return: 返回最终w,b
"""
flag = True
while flag:
count = len(feature)
index = [i for i in range(len(feature))]
random.shuffle(index)
for i in index:
if self.sign(self.w, feature[i], self.b)*label[i] <= 0:
print("误分点为:", feature[i])
self.updata(self.w, self.b, feature[i], label[i])
else:
count -= 1
if count == 0:
flag = False
print("最终w=", self.w, "最终b=", self.b)
return self.w, self.b
class show:
def draw_curve(self, feature, label, w, b):
"""
绘图
:param feature: 特征
:param label: 标签
:param w: 权重
:param b: 偏置
:return:
"""
coordinate_x = []
coordinate_y = []
for i in range(len(feature)):
coordinate_x.append(feature[i][0])
coordinate_y.append(feature[i][1])
if label[i] == 1:
plt.plot(feature[i][0], feature[i][1], 'o'+'r', ms=10)
else:
plt.plot(feature[i][0], feature[i][1], 'x'+'g', ms=10)
dx = np.arange(0, max(coordinate_x), 1)
dy = []
for i in dx:
# w[1]可能会为0报错
dy.append(-(w[0]*i+b)/w[1])
plt.plot(dx, dy)
plt.show()
if __name__ == '__main__':
m, n = createdata()
x = np.array(m)
y = np.array(n)
neuron = perceptron()
show = show()
w, b = neuron.train_random(x, y)
show.draw_curve(m, n, w, b)
运行结果:
构造二分类数据集测试:
# 用如下代码代替train数据集
data = []
for i in range(1000):
x = random.randint(0, 100)
y = random.randint(0, 100)
if x > y:
data.append(((x, y), 1))
elif x < y:
data.append(((x, y), -1))
train = data
得到如下结果:
再换一个: