【统计学习方法by李航】第二章实践——感知机

第二章实践

  • 一、代码:
  • 二、感知机,代码解释(有部分删改):
  • 三、自己写的代码,求出的w和b是差不多的,没有用pandas和numpy

 
链接:[ 全文章目录 ]

一、代码:


!!!第二部分代码无法直接在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()#画出图例

在jupyter notebook中的输出是这样的:
【统计学习方法by李航】第二章实践——感知机_第1张图片

三、自己写的代码,求出的w和b是差不多的,没有用pandas和numpy


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)

 


感知机结束… …
 
链接:[ 全文章目录 ]

你可能感兴趣的:(统计学习方法,机器学习)