python感知机实现

来源:互联网 发布:物联网域名交易平台 编辑:程序博客网 时间:2024/05/29 07:06

感知机(perceptron)作为机器学习的基础,理解了感知机的原理以及实现,就基本知道机器学习的本质了:

“通过对错误数据集的学习,不断调整更新自身的参数,使得模型参数对当前系统的输入数据集,得到最佳输出”

上面是自己个人的理解。

本文主要是参考了李航的《统计学习方法》,然后使用python实现了感知机,并对二维数据集进行分类,验证了算法的有效性。

本文主要内容如下:

  1. 感知机基本原理

  2. 算法步骤

  3. 代码实现


下面先贴出最终的运行结果,数据集红色点集合,以及蓝色点集合是二分类数据集,红线为最终的分类平面,运行结果如下:

这里写图片描述

输出console中

  1. epoch代表每行的错误率,

  2. array,代表学习的参数权重 w1, w2, 偏置 b

代码结构图如下,数据集为2维如图,最后一列为其类别,(为了方便,最终训练中把 0 转化为了 -1):

这里写图片描述

感知机基本原理


感知机是二分类的线性分类模型,其输入为实例的特征向量,输出为实例的类别取+1、-1。感知机将输入空间分为正负两类的超平面,称为判别模型。感知机的学习目的在于求出最佳超平面,由此导入基于误分类的损失函数。利用随机梯度下降法(**不是严格上的随机梯度下降法**)对损失函数进行最小化,求得感知机模型。

感知机是神经网络与支持向量机的基础。

定义如下(截图来自本人的笔记):

这里写图片描述

具体模型可见下图:

这里写图片描述

具体解释如下(截图来自本人笔记):

这里写图片描述

假设数据是线性可分的,那如何找到这样一个超平面呢?即确定感知机模型参数w、b。由此我们需要一个学习策略,即定义(经验)损失函数并将损失函数最小化。

loss损失函数的选取要考虑到w,b的连续可导,因此我们选择误分类点到超平面的距离。

误分类数据(本来y=1结果却分类为了-1,而-1分类为了1)因此y(w*x+b)<0

这里写图片描述

算法步骤


前面提到:

机器学习通过对错误数据集的学习,不断调整更新自身的参数,使得模型参数对当前系统的输入数据集,得到最佳输出

当有误分类数据的时候,对于感知机

误分类数据(本来y=1结果却分类为了-1,而-1分类为了1)因此y(w*x+b)<0

对于w,b计算梯度:
这里写图片描述

至于为何加上学习率,主要是更好的调整w,b的变化,一般取0.01

这里写图片描述

这里写图片描述

(图片来自李航博士《统计学习方法》)

至于具体的神经网络的学习与理解,建议看下,这个英文教材,也有中文版,自己网上搜索一下。

http://neuralnetworksanddeeplearning.com/chap1.html

本bolg的代码风格,就是模仿这个教程。

代码实现


接下来是代码的实现了,本文的数据集是二维特征(见上面代码结构图),对应公式:

y=w2x2+w1x1+b

代码与数据集合见本人github

代码的总体思路:

  1. 从dataset.txt读取数据,生成训练数据形式(将类别0转化为了-1,主要是方便运算)

  2. 生成感知机类,以及随机梯度下降法(不是严格上的随机梯度下降法)参数,并训练网络

  3. 画出训练数据集的散点图,以及最终生成的分类平面

# _*_ coding:utf-8 _*_import numpy as npfrom utils.FileUtil import get_line_lstimport matplotlib.pyplot as pltclass Perception(object):    def __init__(self, var_num):        """var_num为特征的个数,本例中设为2"""        # self.w = np.random.randn(1, var_num)        # 参数初始化        self.w = np.ones(var_num)        self.b = 1        self.var_num = var_num        # 错误率低于0.02则终止        self.min_error_rate = 0.02    def train(self, train_data, eta):        """        training model        :param train_data: array like [[1, 2, -1], [1.1, 0.8, 1]]        :param eta: learning rate:        :return none:        """        for item in train_data:            output = (np.dot(self.w, item[0:-1]) + self.b)*item[-1]            if output <= 0:                self.w += eta * item[-1] * item[0:-1]                self.b += eta * item[-1]    def sgd(self, train_data, epoch, eta, batch_size):        """        Training perception model by stochastic gradient descent        :param train_data: 2D array like [[1.1, 2.3, -1]] the last                            item -1 train_date[0][-1] means label        :param epoch:        :param eta:learning rate        :return:none        """        for i in xrange(epoch):            np.random.shuffle(train_data)            batch_lst = [train_data[k:k+batch_size] for k in xrange(0, len(train_data), batch_size)]            for mini_batch in batch_lst:                self.train(mini_batch, eta)            current_error_rate = self.get_error_rate(train_data)            print 'epoch {0} current_error_rate: {1}'.format(i+1, current_error_rate)            print self.get_current_para()            if current_error_rate <= self.min_error_rate:                break    def get_error_rate(self, validate_data):        all_len = validate_data.shape[0]        error_len = 0        for item in validate_data:            output = np.dot(self.w, item[0:-1]) + self.b            output = 1 if output >= 0 else -1            error = True if output != item[-1] else False            if error:                error_len += 1        return float(error_len) / all_len    def get_current_para(self):        return self.w, self.b    def get_weight(self):        return self.w    def get_bias(self):        return self.bdef generate_data(data_path):    lst_data = get_line_lst(data_path)    # lst_ret = []    # for item in lst_data:    #     lst_ret.append([float(s) for s in item.split()])    # the following one line  is equivalent to the above for loop    lst_ret = [[float(s) for s in item.split()] for item in lst_data]    ret_arr = np.array(lst_ret)    # change all the label whose value is 0 to -1    for i in xrange(ret_arr.shape[0]):        if ret_arr[i][-1] == 0:            ret_arr[i][-1] = -1    return ret_arrdef plot_data_scatter(train_data, w, b):    x = np.linspace(-5, 5, 10)    plt.figure()    # 画散点图(plot scatter)    for i in range(len(train_data)):        if train_data[i][-1] == 1:            plt.scatter(train_data[i][0], train_data[i][1], c=u'b')        else:            plt.scatter(train_data[i][0], train_data[i][1], c=u'r')    # 画感知机分类,slope斜率图    plt.plot(x, -(w[0]*x+b) / w[1], c=u'r')    plt.show()if __name__ == '__main__':    data_path = '../dataset/perception/dataset.txt'    train_data = generate_data(data_path)    # epoch迭代次数,eta学习率,var_num特征个数    epoch, eta, var_num, batch_size = 100, 0.1, 2, 20    # 创建感知机对象    p = Perception(var_num)    # 训练    p.sgd(train_data, epoch, eta, batch_size)    # 画出最终的分类模型    plot_data_scatter(train_data, p.get_weight(), p.get_bias())

转载注明出处,并在下面留言!!!

http://blog.csdn.net/haluoluo211/article/details/78066956

原创粉丝点击