您的位置:首页 > 编程语言 > Python开发

深度学习之感知器的python实现,及用感知器实现鸢尾花的分类

2019-03-14 10:16 351 查看

机器学习一般用来处理结构化的数据,深度学习一般用来处理非结构化的数据,例如图像、视频、文字等。




权重更新过程: 如果真实是1,预测是0,则权重会增加,相当于为了达到阈值增加权重
如果真实是0,预测是1,则权重会降低,相当于为了达到阈值减少权重

实现步骤

  • 对权重进行初始化。(初始化为0或者很小的数值。)
  • 对训练集中每一个样本进行迭代,计算输出值y。
  • 根据输出值y与真实值,更新权重。
  • 循环步骤2。直到达到指定的次数(或者完全收敛)。

说明:
如果两个类别线性可分,则感知器一定会收敛。
如果两个类别线性不可分,则感知器一定不会收敛。

实现与门:

import numpy as np
# 定义数据集
X = np.array([[1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]])
# 定义标签(每个样本所属的分类)。
y = np.array([0, 0, 0, 1])
# 定义权重。对于单层感知器,权重通常初始化为0或者很小的数值。
# w = np.zeros(3)
w = np.random.random(3)
# 定义学习率。
eta = 0.1

for epoch in range(6):
for x, target in zip(X, y):

4000
# 计算净输入
z = np.dot(w, x)
# 根据净输入,计算分类值。
y_hat = 1 if z >= 0 else 0
# 根据预测值与真实值,进行权重调整。
w = w + eta * (target - y_hat) * x
# 注意数组的矢量化计算,相当于执行了以下的操作。
#     w[0] = w[0] + eta * (y - y_hat) * x[0]
#     w[1] = w[1] + eta * (y - y_hat) * x[1]
#     w[2] = w[2] + eta * (y - y_hat) * x[2]
print(target, y_hat)
print(w)


线性可分,能收敛

# 使用单层感知器无法实现异或门。
# 感知器的局限:如果两个类别的样本在空间中线性不可分,则感知器永远也不会收敛。
X = np.array([[1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]])
y = np.array([0, 1, 1, 0])
# w = np.zeros(3)
w = np.random.random(3)
eta = 0.1

for epoch in range(70):
for x, target in zip(X, y):
z = np.dot(w, x)
y_hat = 1 if z >= 0 else 0
w = w + eta * (target - y_hat) * x
print(target, y_hat)
print(w)

算法的Python实现
现在,我们使用Python语言来实现感知器算法,进行鸢尾花的分类。

class Perceptron:
"""通过Python语言实现感知器类。用来进行二分类任务。"""

def __init__(self, eta, epoch):
"""初始化方法。

Parameter:
-------
eta: float
学习率。
epoch: int
对训练集训练的轮数。
"""
self.eta = eta
self.epoch = epoch

def step(self, z):
"""阶跃函数。对净输入进行转换。

Parameter:
-----
z: 标量或数组类型
净输入。

Return:
------
t: 变量或数组类型。
分类的结果。0或者1。当z >= 0时,返回1,否则返回0。
"""
#         return 1 if z >= 0 else 0
return np.where(z >= 0, 1, 0)

def fit(self, X, y):
"""训练方法。

Parameter:
X: 类数组类型。形状为 (样本数量, 特征数量)
提供的训练集。
y: 类数组类型。形状为(样本数量,)
样本对应的标签(分类)
"""
# 对类型进行转换,不管是什么二维类型,统一转换成二维的ndarray数组类型。
X = np.asarray(X)
y = np.asarray(y)
# 注意:权重的数量要比特征的数量多1。多出来的一个就是偏置。
self.w_ = np.zeros(X.shape[1] + 1)
# 定义损失列表。用来存放每个epoch迭代之后,分类错误的数量。
self.loss_ = []
# 迭代epoch指定的轮数。
for i in range(self.epoch):
# 用来记录单次epoch的损失值(分类错误的数量)
loss = 0
for x, target in zip(X, y):
# 计算净输入
z = np.dot(x, self.w_[1:]) + self.w_[0]
# 根据净输入,计算分类。
y_hat = self.step(z)
#                 if target != y_hat:
#                     loss += 1
loss += target != y_hat
# 调整权重
self.w_[1:] += self.eta * (target - y_hat) * x
# 调整偏置
self.w_[0] += self.eta * (target - y_hat)
# 将损失值加入到损失列表当中。
self.loss_.append(loss)

def predict(self, X):
"""预测方法。根据提供的数据集X,返回每一个样本对应的标签(分类)。

Parameter:
-----
X: 类数组类型。形状为 (样本数量, 特征数量)
提供预测集。

Return:
-----
label: 类数组类型。形状为:(样本数量,)
预测的每一个便签分类。
"""
X = np.asarray(X)
# 计算净输入。(矢量化计算,没有使用循环分别对每一个样本求净输出)
z = np.dot(X, self.w_[1:]) + self.w_[0]
# 获取最终的分类结果。(一维数组类型。)
result = self.step(z)
return result

# 感知器类进行测试。
X = np.array([[1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]])
y = np.array([0, 0, 0, 1])
p = Perceptron(0.1, 7)
p.fit(X, y)
print(p.w_)
print(p.loss_)
# 使用感知器实现鸢尾花的分类。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import pandas as pd

# return_X_y设置为True,只返回Data与target。
X, y = load_iris(return_X_y=True)
# X.shape, y.shape
# np.concatenate 合并的数组,要求具有相同的维度,因此,需要将y变成
# 2维的形式。
data = pd.DataFrame(np.concatenate((X, y.reshape((-1, 1))), axis=1))
# np.sum(data.duplicated())
# display(data.shape)
data.drop_duplicates(inplace=True)
# display(data.shape)

# data[4].map({0:1, 1:-1, 2:2})
# data = data[data[4] != 2]
data[4] = data[4].map({0:10, 1:0, 2:1})
data = data[data[4] != 10]
data[4].value_counts()
# data[4].value_counts()
X, y = data.iloc[:, :4], data.iloc[:, 4]
train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.2, random_state=0)
# train_X.shape, test_X.shape
p = Perceptron(0.1, 20)
p.fit(train_X, train_y)
# 查看训练后的权重与损失情况。
# display(p.w_)
# display(p.loss_)
result = p.predict(test_X)
np.sum(test_y == result) / len(result)
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"] = False

plt.plot(test_y.values, "go", ms=15, label="真实值")
plt.plot(result, "rx", ms=15, label="预测值")
plt.title("感知器二分类预测")
plt.xlabel("样本序号")
plt.ylabel("样本类别")
plt.legend()
plt.show()

# 绘制损失曲线。(每个epoch预测样本错误的数量)
plt.plot(range(1, len(p.loss_) + 1), p.loss_, "o-")

split_index = test_size * len()
data[:split_index]  data[split_index:]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐