李航统计学习--感知机算法实现(python)

感知机

1.感知机是根据输入实例的特征向量 x x x对其进行二类分类的线性分类模型:

f ( x ) = sign ⁡ ( w ⋅ x + b ) f(x)=\operatorname{sign}(w \cdot x+b) f(x)=sign(wx+b)

感知机模型对应于输入空间(特征空间)中的分离超平面 w ⋅ x + b = 0 w \cdot x+b=0 wx+b=0

2.感知机学习的策略是极小化损失函数:

min ⁡ w , b L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) \min _{w, b} L(w, b)=-\sum_{x_{i} \in M} y_{i}\left(w \cdot x_{i}+b\right) w,bminL(w,b)=xiMyi(wxi+b)

损失函数对应于误分类点到分离超平面的总距离。

3.感知机学习算法是基于随机梯度下降法的对损失函数的最优化算法,有原始形式和对偶形式。算法简单且易于实现。原始形式中,首先任意选取一个超平面,然后用梯度下降法不断极小化目标函数。在这个过程中一次随机选取一个误分类点使其梯度下降。

4.当训练数据集线性可分时,感知机学习算法是收敛的。感知机算法在训练数据集上的误分类次数 k k k满足不等式:

k ⩽ ( R γ ) 2 k \leqslant\left(\frac{R}{\gamma}\right)^{2} k(γR)2

当训练数据集线性可分时,感知机学习算法存在无穷多个解,其解由于不同的初值或不同的迭代顺序而可能有所不同。


感知机模型

f ( x ) = s i g n ( w ⋅ x + b ) f(x) = sign(w\cdot x + b) f(x)=sign(wx+b)

sign ⁡ ( x ) = { + 1 , x ⩾ 0 − 1 , x < 0 \operatorname{sign}(x)=\left\{\begin{array}{ll}{+1,} & {x \geqslant 0} \\ {-1,} & {x<0}\end{array}\right. sign(x)={+1,1,x0x<0

给定训练集:

T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , ⋯   , ( x N , y N ) } T=\left\{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \cdots,\left(x_{N}, y_{N}\right)\right\} T={(x1,y1),(x2,y2),,(xN,yN)}

定义感知机的损失函数

L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) L(w, b)=-\sum_{x_{i} \in M} y_{i}\left(w \cdot x_{i}+b\right) L(w,b)=xiMyi(wxi+b)


算法

随即梯度下降法 Stochastic Gradient Descent

随机抽取一个误分类点使其梯度下降。
y i ( w ⋅ x i + b ) ⩽ 0 y_{i}\left(w \cdot x_{i}+b\right)\leqslant 0 yi(wxi+b)0
则判断为误分类点,然后进行w和b的更新:

w = w + η y i x i w = w + \eta y_{i}x_{i} w=w+ηyixi

b = b + η y i b = b + \eta y_{i} b=b+ηyi

当实例点被误分类,即位于分离超平面的错误侧,则调整 w w w, b b b的值,使分离超平面向该无分类点的一侧移动,直至误分类点被正确分类,其中 η \eta η为学习率

实现1将手动实现感知机算法,数据集则采用sklearn中鸢尾花数据集。

数据集介绍:iris数据集由Fisher在1936年整理,包含4个特征(Sepal.Length(花萼长度)、Sepal.Width(花萼宽度)、Petal.Length(花瓣长度)、Petal.Width(花瓣宽度)),特征值都为正浮点数,单位为厘米。目标值为鸢尾花的分类(Iris Setosa(山鸢尾)、Iris Versicolour(杂色鸢尾),Iris Virginica(维吉尼亚鸢尾))。
为了实现感知机算法,本文拿出iris数据集中两个分类的数据和[sepal length,sepal width]作为特征,去识别出花的类型。

实现1:

# @Author: coderdz
# @File: Perceptron.py
# @Site: github.com/dingzhen7186
# @Ended Time : 2020/9/21

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.datasets import load_iris

class Perceptron():
	def __init__(self):
		 # w初始化为全1数组
		self.w = np.ones(len(data[0]) - 1, dtype = np.float32)
		self.b = 0
		self.rate = 0.5 # 初始化学习率
	
	# 感知机训练, 找出最合适的w, b
	def fit(self, x_train, y_train):
		while True:
			flag = True # 标记是否存在误分类数据
			for i in range(len(x_train)): # 遍历训练数据
				xi = x_train[i]
				yi = y_train[i]
				 # 判断 yi * (wx + b) <= 0
				if yi * (np.inner(self.w, xi) + self.b) <= 0:
					flag = False # 找到误分类数据, flag标记为False
					 # 更新w, b值
					self.w += self.rate * np.dot(xi, yi)
					self.b += self.rate * yi
			if flag:
				break
		 # 输出w = ? , b = ?
		print('w = ' + str(self.w) + ', b = ' + str(self.b))

	# 图形显示结果
	def show(self, data):
		x_ = np.linspace(4, 7, 10)
		y_ = -(self.w[0] * x_ + self.b) / self.w[1]
		 # 画出这条直线
		plt.plot(x_, y_)
		 # 画出数据集的散点图
		plt.plot(data[:50, 0], data[:50, 1], 'bo', c = 'blue', label = '0')
		plt.plot(data[50:100, 0], data[50:100, 1], 'bo', c = 'orange', label = '1')
		plt.xlabel('sepal length')
		plt.ylabel('sepal width')
		plt.legend()
		plt.show()

iris = load_iris()
# 通过DataFrmae对象获取iris数据集对象, 列名为该数据集样本的特征名
df = pd.DataFrame(iris.data, columns = iris.feature_names)
# 增加label列为它们的分类标签
df['label'] = iris.target
df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
#print(df.label.value_counts()) 不同标签的样本数量
# 2:50 1:50 0:50

# 画出散点图查看特征点的分布
plt.scatter(df[:50]['sepal length'].values, df[:50]['sepal width'].values, label='0')
plt.scatter(df[50:100]['sepal length'].values, df[50:100]['sepal width'].values, label='1')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.legend()
plt.show()

# 选择数据集
data = np.array(df.iloc[:100, [0, 1, -1]])
# 数据集划分
x, y = data[:, :-1], data[:, -1]
# 将y数据集值变为1和-1
y = np.array([1 if i == 1 else -1 for i in y])

# 开始训练
p = Perceptron()
p.fit(x, y)
p.show(data)

输出如下:

w = [ 39.85006  -50.400837], b = -63.5

在这里插入图片描述


实现2将采用sklearn中已经实现好了的Perceptron感知机,然后调用相关方法实现二分类。

实现2:

# @Author: coderdz
# @File: Perceptron.py
# @Site: github.com/dingzhen7186
# @Ended Time : 2020/9/21

import sklearn
from sklearn.linear_model import Perceptron
from sklearn.datasets import load_iris
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# 数据预处理
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']
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])

# 模型训练
clf = Perceptron(fit_intercept = True, max_iter = 1000, tol = None, shuffle = True)
clf.fit(x, y)
# 输出参数w, b
print('w = ' + str(clf.coef_) + ', b = ' + str(clf.intercept_))

# 画出图形
plt.figure(figsize = (10, 10)) #设置画布大小
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.title('鸢尾花线性数据示例')

# 画出散点图, iris-setosa:山鸢尾, iris-versicolour: 杂色鸢尾
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_ = np.arange(4, 8)
y_ = -(clf.coef_[0][0]*x_ + clf.intercept_) / clf.coef_[0][1]
plt.plot(x_, y_)

plt.legend() # 显示图例
plt.grid(False) # 不显示网络
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.show()

输出如下:

w = [[ 66.1 -83.3]], b = [-106.]

在这里插入图片描述
我的导师李胜开组会说了一句话,我觉得说的很好,“前途是光明的,道路是曲折的”,大家一起加油吧!

  • 10
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值