前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python感知机实现

python感知机实现

作者头像
bear_fish
发布2018-09-14 09:58:14
1.2K0
发布2018-09-14 09:58:14
举报

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1338365

感知机(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=w2∗x2+w1∗x1+by=w_2*x_2 + w_1*x_1 + b

代码数据集合见本人github

代码的总体思路:

  1. 从dataset.txt读取数据,生成训练数据形式(将类别0转化为了-1,主要是方便运算)
  2. 生成感知机类,以及随机梯度下降法(不是严格上的随机梯度下降法)参数,并训练网络
  3. 画出训练数据集的散点图,以及最终生成的分类平面
# _*_ coding:utf-8 _*_
import numpy as np
from utils.FileUtil import get_line_lst
import matplotlib.pyplot as plt


class 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.b


def 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_arr


def 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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年09月22日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 感知机基本原理
  • 算法步骤
  • 代码实现
    • 转载注明出处,并在下面留言!!!
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档