zoukankan      html  css  js  c++  java
  • Python实现鸢尾花数据集分类问题——使用LogisticRegression分类器

    . 逻辑回归   

    逻辑回归(Logistic Regression)是用于处理因变量为分类变量的回归问题,常见的是二分类或二项分布问题,也可以处理多分类问题,它实际上是属于一种分类方法。  

    概率p与因变量往往是非线性的,为了解决该类问题,我们引入了logit变换,使得logit(p)与自变量之  间存在线性相关的关系,逻辑回归模型定义如下:  

     1 #Sigmoid曲线:  
     2 import matplotlib.pyplot as plt  
     3 import numpy as np  
     4   
     5 def Sigmoid(x):  
     6     return 1.0 / (1.0 + np.exp(-x))  
     7   
     8 x= np.arange(-10, 10, 0.1)  
     9 h = Sigmoid(x)            #Sigmoid函数  
    10 plt.plot(x, h)  
    11 plt.axvline(0.0, color='k')   #坐标轴上加一条竖直的线(0位置)  
    12 plt.axhspan(0.0, 1.0, facecolor='1.0', alpha=1.0, ls='dotted')    
    13 plt.axhline(y=0.5, ls='dotted', color='k')  #在y=0.5的地方加上黑色虚线  
    14 plt.yticks([0.0,  0.5, 1.0])  #y轴标度  
    15 plt.ylim(-0.1, 1.1)       #y轴范围  
    16 plt.show()    

     二、鸢尾花分类问题的思路分析

    (1)选择使用LogisticRegression分类器,由于Iris数据集涉及到3个目标分类问题,而逻辑回归模型是二分类模型,用于二分类问题。因此,可以将其推广为多项逻辑回归模型multi-nominal logistic regression model),用于多分类。

    2)根据多项逻辑回归模型,编写代码,输入数据集,训练得到相应参数并作出预测。

    3)对预测出的数据的分类结果和原始数据进行可视化展示。

    三、多项逻辑回归模型的原理及推导过程

     假设类别 Y 的取值集合为 {1,2,...,K},那么多项逻辑回归模型是:

     

    其似然函数为:

     

    其中, 为模型在输入样本时,将其判为类别k 的概率;

    起到指示函数的作用,当K 等于样本的标签类别时为1,其余均为0

      对似然函数取对数,然后取负,得到(简记为:),最终要训练出的模型参数要使得的值取得最小。

    的推导过程如下:

     

    考虑到过拟合的发生,对加上一个正则项:

    可以写成:

    关于求梯度,得到:

    在上式中,第一项可以看成是类别k的后验期望值,第二项 视为类别k 的先验期望值,第三项是正则化项,用于缓解过拟合。

      接下来使用梯度下降法对参数 进行修正更新即可:

                           

    四、实现步骤

    4.1 读入数据文件

    这里需要注意的是,datas中取前两列作为特征(为了后期的可视化画图更加直观,故只取前两列特征值向量进行训练

     1 attributes=['SepalLength','SepalWidth','PetalLength','PetalWidth'] #鸢尾花的四个属性名
     2 
     3     datas=[]
     4     labels=[]
     5 
     6     # with open('IRIS_dataset.txt','r') as f:
     7     #     for line in f:
     8     #         linedata=line.split(',')
     9     #         datas.append(linedata[:-1]) #前4列是4个属性的值
    10     #         labels.append(linedata[-1].replace('
    ','')) #最后一列是类别
    11 
    12     #读入数据集的数据:
    13     data_file=open('IRIS_dataset.txt','r')
    14     for line in data_file.readlines():
    15         # print(line)
    16         linedata = line.split(',')
    17         # datas.append(linedata[:-1])  # 前4列是4个属性的值(误判的样本的个数为:7
    18         datas.append(linedata[:-3])  # 前2列是2个属性的值(误判的样本的个数为:30
    19         labels.append(linedata[-1].replace('
    ', ''))  # 最后一列是类别
    20 
    21     datas=np.array(datas)
    22     datas=datas.astype(float) #将二维的字符串数组转换成浮点数数组
    23     labels=np.array(labels)
    24     kinds=list(set(labels)) #3个类别的名字列表

    4.2 编写代码实现LogisticRegression算法

     1 # LogisticRegression算法,训练数据,传入参数为数据集(包括特征数据及标签数据),结果返回训练得到的参数 W
     2 def LogRegressionAlgorithm(datas,labels):
     3     kinds = list(set(labels))  # 3个类别的名字列表
     4     means=datas.mean(axis=0) #各个属性的均值
     5     stds=datas.std(axis=0) #各个属性的标准差
     6     N,M= datas.shape[0],datas.shape[1]+1  #N是样本数,M是参数向量的维
     7     K=3 #k=3是类别数
     8 
     9     data=np.ones((N,M))
    10     data[:,1:]=(datas-means)/stds #对原始数据进行标准差归一化
    11 
    12     W=np.zeros((K-1,M))  #存储参数矩阵
    13     priorEs=np.array([1.0/N*np.sum(data[labels==kinds[i]],axis=0) for i in range(K-1)]) #各个属性的先验期望值
    14 
    15     liklist=[]
    16     for it in range(1000):
    17         lik=0 #当前的对数似然函数值
    18         for k in range(K-1): #似然函数值的第一部分
    19             lik -= np.sum(np.dot(W[k],data[labels==kinds[k]].transpose()))
    20         lik +=1.0/N *np.sum(np.log(np.sum(np.exp(np.dot(W,data.transpose())),axis=0)+1)) #似然函数的第二部分
    21         liklist.append(lik)
    22 
    23         wx=np.exp(np.dot(W,data.transpose()))
    24         probs=np.divide(wx,1+np.sum(wx,axis=0).transpose()) # K-1 *N的矩阵
    25         posteriorEs=1.0/N*np.dot(probs,data) #各个属性的后验期望值
    26         gradients=posteriorEs - priorEs +1.0/100 *W #梯度,最后一项是高斯项,防止过拟合
    27         W -= gradients #对参数进行修正
    28     print("输出W为:",W)
    29     return

    4.3 编写predict_fun()预测函数

    根据训练得到的参数W和数据集,进行预测。输入参数为数据集和由LogisticRegression算法得到的参数W,返回值为预测的值。

     1 #根据训练得到的参数W和数据集,进行预测。输入参数为数据集和由LogisticRegression算法得到的参数W,返回值为预测的值
     2 def predict_fun(datas,W):
     3     N, M = datas.shape[0], datas.shape[1] + 1  # N是样本数,M是参数向量的维
     4     K = 3  # k=3是类别数
     5     data = np.ones((N, M))
     6     means = datas.mean(axis=0)  # 各个属性的均值
     7     stds = datas.std(axis=0)  # 各个属性的标准差
     8     data[:, 1:] = (datas - means) / stds  # 对原始数据进行标准差归一化
     9 
    10     # probM每行三个元素,分别表示data中对应样本被判给三个类别的概率
    11     probM = np.ones((N, K))
    12     print("data.shape:", data.shape)
    13     print("datas.shape:", datas.shape)
    14     print("W.shape:", W.shape)
    15     print("probM.shape:", probM.shape)
    16     probM[:, :-1] = np.exp(np.dot(data, W.transpose()))
    17     probM /= np.array([np.sum(probM, axis=1)]).transpose()  # 得到概率
    18 
    19     predict = np.argmax(probM, axis=1).astype(int)  # 取最大概率对应的类别
    20     print("输出predict为:", predict)
    21     return predict

     4.4 绘制图像

     

    1)确定坐标轴范围,x,y轴分别表示两个特征

     1 # 1.确定坐标轴范围,x,y轴分别表示两个特征
     2     x1_min, x1_max = datas[:, 0].min(), datas[:, 0].max()  # 第0列的范围
     3     x2_min, x2_max = datas[:, 1].min(), datas[:, 1].max()  # 第1列的范围
     4     x1, x2 = np.mgrid[x1_min:x1_max:150j, x2_min:x2_max:150j]  # 生成网格采样点,横轴为属性x1,纵轴为属性x2
     5     grid_test = np.stack((x1.flat, x2.flat), axis=1)  # 测试点
     6     #.flat 函数将两个矩阵都变成两个一维数组,调用stack函数组合成一个二维数组
     7     print("grid_test = 
    ", grid_test)
     8 
     9     grid_hat = predict_fun(grid_test,W)  # 预测分类值
    10     grid_hat = grid_hat.reshape(x1.shape)  # 使之与输入的形状相同
    11     #grid_hat本来是一唯的,调用reshape()函数修改形状,将其grid_hat转换为两个特征(长度和宽度)
    12     print("grid_hat = 
    ", grid_hat)
    13     print("grid_hat.shape: = 
    ", grid_hat.shape) # (150, 150)

    (2)指定默认字体

    1 # 2.指定默认字体
    2     mpl.rcParams['font.sans-serif'] = [u'SimHei']
    3     mpl.rcParams['axes.unicode_minus'] = False

    (3)绘制图像

     1 # 3.绘制图像
     2     cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
     3     cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
     4 
     5     alpha = 0.5
     6 
     7     plt.pcolormesh(x1, x2, grid_hat, cmap=plt.cm.Paired)  # 预测值的显示
     8     # 调用pcolormesh()函数将x1、x2两个网格矩阵和对应的预测结果grid_hat绘制在图片上
     9     # 可以发现输出为三个颜色区块,分布表示分类的三类区域。cmap=plt.cm.Paired/cmap=cm_light表示绘图样式选择Paired主题
    10     # plt.scatter(datas[:, 0], datas[:, 1], c=labels, edgecolors='k', s=50, cmap=cm_dark)  # 样本
    11     plt.plot(datas[:, 0], datas[:, 1], 'o', alpha=alpha, color='blue', markeredgecolor='k')
    12     ##绘制散点图
    13     plt.scatter(datas[:, 0], datas[:, 1], s=120, facecolors='none', zorder=10)  # 圈中测试集样本
    14     plt.xlabel(u'花萼长度', fontsize=13)  #X轴标签
    15     plt.ylabel(u'花萼宽度', fontsize=13)  #Y轴标签
    16     plt.xlim(x1_min, x1_max) # x 轴范围
    17     plt.ylim(x2_min, x2_max) # y 轴范围
    18     plt.title(u'鸢尾花LogisticRegression二特征分类', fontsize=15)
    19     # plt.legend(loc=2)  # 左上角绘制图标
    20     # plt.grid()
    21     plt.show()

    五、 实验结果

    (1)运行程序输出的参数:

    使用二个特征:

    输出W为: [[-0.41462351  1.26263398  0.26536423]

               [-1.07260354 -2.44478672  1.96448439]]

    输出predict为: [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1  1 1 1 1 2 1 1 1 1 1 1 1 1 0 0 0 2 0 2 0 2 0 2 2 2 2 2 2 0 2 2 2 2 2 2 2 2  0 0 0 0 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2 0 2 2 0 2 0 0 0 0 2 0 0 0 0  0 0 2 2 0 0 0 0 2 0 2 0 0 0 0 2 2 0 0 0 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0  0 2]

    误判的样本的个数为:28

     

    使用四个特征:

    输出W为:

     [[-0.09363942 -1.41359443  1.17376524 -2.3116611  -2.20018596]

     [ 1.44071982 -0.05960463 -0.31391519 -0.87589944 -1.83255315]]

    输出predict为: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0  0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1  1 1 1 2 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 1 2 2 2 2  2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2  2 2]

    误判的样本的个数为:8

     

     

    (2)数据可视化结果如下:

     

     

     

     

    六、结果分析与比较

      由以上实验结果可以看出,使用了二特征的误判的样本个数为28(样本总数为150),而使用了四个特征的训练结果,误判的样本个数为8,在一定程度上可以解释使用的特征数过少的话,会导致欠拟合的情况发生。

      为了后期的可视化画图更加直观,故只取前两列特征值向量进行训练。结果展示如上图所示。

     

     

    完整实现代码详见:【GitHub

     

    【Reference】

    1、Logistic回归多分类之鸢尾花

    2、https://blog.csdn.net/BTUJACK/article/details/79761461

    3、https://blog.csdn.net/eastmount/article/details/77920470

  • 相关阅读:
    css
    css加号波浪号
    C++对象池
    C++11 智能指针
    C++内存泄漏检测(调试工具)
    JSONP是个嘛玩意?解决跨域问题?
    使用django + KindEditor 开发个人博客系统
    前端文本框插件KindEditor
    jQuery AJAX
    Django ModelForm表单验证
  • 原文地址:https://www.cnblogs.com/shenxiaolin/p/8857158.html
Copyright © 2011-2022 走看看