!!!第二部分代码无法直接在python中运行,要在jupyter notebook等环境中打开。
Github链接:代码(打开无代码,换个浏览器试试)
数据使用说明:
这里使用的是sklearn中的iris数据集。该数据集的x是150行4列的矩阵;y是150行1列的矩阵,数值选择为(0,1,2)将y分为三类。
下标从0 ~ 49是类0,下标从50 ~ 99是类1,下标从100 ~ 149是类2。
为了简单起见,对于x,我们只取第一列和第二列的数据,即[sepal length,sepal width];对于y,我们只选择类0与类1(即下标从0~99)。
import pandas as pd #数据分析常用库
import numpy as np #数学计算常用库
from sklearn.datasets import load_iris #导入iris数据集
import matplotlib.pyplot as plt #导入画图功能
%matplotlib inline #画图功能初始化
###################################################################
# 数据加载与预处理
iris = load_iris() #load_iris()函数返回一个可供操作的对象(类型是sklearn.utils.Bunch)
df = pd.DataFrame(iris.data, columns=['sepal length', 'sepal width', 'petal length', 'petal width']) #iris.data从就是感知机的x,columns是每列的名字
df['label'] = iris.target #iris.target是感知机的y;这句话的意思是,增加一列,列的名字叫label,列的数据从iris.target里取
data = np.array(df.iloc[:100, [0, 1, -1]])
'''这句话是一个数据拆分,
np.array():将括号里面的东西转化成一个存储单一数据类型的多维数组(这 里就代表二维数组)
df.iloc[:100, [0, 1, -1]]:逗号左边,下标从0到99;逗号右边,取下标为0,为1,以及最后一列。
总的来说,就是把第一二和最后一列的数据拿出来,当作一个新的二维数组'''
X, y = data[:,:-1], data[:,-1] #把第一二列的数据给X,把最后一列的数据给y;逗号前面的 “:” 代表那一列全部元素
y = np.array([1 if i == 1 else -1 for i in y]) #把y中的元素换成1或-1(本来是0和1的)
###################################################################
#感知机模型
class Model:
def __init__(self): #构造函数
self.w = np.ones(len(data[0])-1, dtype=np.float32) #创建一个等于X长度、全为1、类型为float32的矩阵,在这里w是[ 1. 1.]
self.b = 0 #b
self.l_rate = 0.1 #学习率
def sign(self, x, w, b):
y = np.dot(x, w) + b #np.dot(x, w),求x与w的内积(点积)
return y
# 随机梯度下降法
def fit(self, X_train, y_train):
is_wrong = True #假设一开始有误分类点(这里我改了一下变量,方便理解)
while is_wrong: #如果有误分类点,就继续
wrong_count = 0 #误分类点数目初始化为0
for d in range(len(X_train)): #对每一行向量进行判断
X = X_train[d] #取出当前行的x
y = y_train[d] #取出当前行的y
if y * self.sign(X, self.w, self.b) <= 0: #如果经验损失函数小于0就说明其误分类(可以等于0是因为数据绝对线性可分)
self.w = self.w + self.l_rate*np.dot(y, X) #更新w
self.b = self.b + self.l_rate*y #更新b
wrong_count += 1 #误分类点数+1
if wrong_count == 0: #如果没有误分类点
is_wrong = False
###################################################################
#主程序
perceptron = Model() #创建一个对象
perceptron.fit(X, y) #通过梯度下降拟合
x_points = np.linspace(4, 7,10) #这个是标准线
y_ = -(perceptron.w[0]*x_points + perceptron.b)/perceptron.w[1] #这个是算出来的线
plt.plot(x_points, y_)
plt.plot(data[:50, 0], data[:50, 1], 'bo', color='blue', label='0')#画出类0的点
plt.plot(data[50:100, 0], data[50:100, 1], 'bo', color='orange', label='1')#画出类1的点
plt.xlabel('sepal length')#写出横坐标意思
plt.ylabel('sepal width')#写出纵坐标意思
plt.legend()#画出图例
from sklearn.datasets import load_iris
def l(iris, w, b, a):#经验损失函数,以哪两项为判断依据(下标从0开始)
i=0
while(i<100):#数据行数为150,但是0~49是1类,50~99是一类,100~149是一类;这里我们只用两类来进行分类就可以了
temp = 0#求向量w和向量x的内积
for j in range(2):
temp += w[j]*iris.data[i][j]
if(kind_y(iris.target[i]) * (temp+b)<0):#如果损失函数对某个点的值小于0,那么这个点就是误分类点
#l(data, change_w(w, a, change_w(w, a, kind_y(iris.target[i]), iris.data[i]), change_b(b, a, kind_y(iris.target[i])), a)#如果用递归,会超出递归上限的
w = change_w(w, a, kind_y(iris.target[i]), iris.data[i])
b = change_b(b, a, kind_y(iris.target[i]))
i=0
else:
i+=1
return w, b
def change_w(w, a, y, x):#更新w
for i in range(2):#iris数据集里面每一行是一个四维向量,我们只取前2个
w[i] += a*y*x[i]
return w
def change_b(b, a, y):#更新b
return b + a*y
def kind_y(y):#iris数据集是三分类的,类型为0,1,2.
if y==0:
return -1
else:
return 1
iris = load_iris()
w = [1, 1]
w, b = l(iris, w, 0, 0.1)
print(w,b)
感知机结束… …
链接:[ 全文章目录 ]