用逻辑回归实现鸢尾花数据集分类(1)

鸢尾花数据集的分类问题指导 -- 对数几率回归(逻辑回归)问题研究 (1)

这一篇Notebook是应用对数几率回归(Logit Regression)对鸢尾花数据集进行品种分类的。首先会带大家探索一下数据集中的特征,类别信息。然后带大家从入门与进阶来学习应用逻辑回归分类。

1.背景介绍

1.1. 逻辑回归 Logistic Regression (对数几率回归 Logit Regression)

名字

关于名字,有文献将Logistic Regression译为“逻辑回归”, 但中文“逻辑”与logitic 和 logit 的含义相去甚远,因此在《机器学习》中意译为“对数几率回归”,简称“对率回归”。

线性回归

在介绍对数几率回归之前先介绍一下线性回归,线性回归的主要思想是通过历史数据拟合出一条直线,因变量与自变量是线性关系,对新的数据用这条直线进行预测。 线性回归的公式如下:

y=w0+w1x1+...+wnxn=wTx+b

逻辑回归

对数几率回归是一种广义的线性回归分析模型,是一种预测分析。虽然它名字里带回归,但实际上对数几率回归是一种分类学习方法。它不是仅预测出“类别”, 而是可以得到近似概率预测,这对于许多需要利用概率辅助决策的任务很有用。普遍应用于预测一个实例是否属于一个特定类别的概率,比如一封email是垃圾邮件的概率是多少。 因变量可以是二分类的,也可以是多分类的。因为结果是概率的,除了分类外还可以做ranking model。LR的应用场景很多,如点击率预测(CTR)、天气预测、一些电商的购物搭配推荐、一些电商的搜索排序基线等。

对数几率函数是一种“Sigmoid”函数,呈现S型曲线,它将z值转化为一个接近0或1的 y值。 对数几率回归公式如下:

y=g(z)=11+e−zz=wTx+b

其中,y=11+e−x 被称作Sigmoid函数。

Logistic Regression算法是将线性函数的结果映射到了Sigmoid函数中,即y=11+e(wTx+b)

Sigmoid函数

下图绘制了Sigmoid函数形状,如图所示,sigmoid函数输出值范围在(0,1)之间,即代表了数据属于某一类别的概率,0.5是作为判别的临界值。

In [3]:
# Sigmoid曲线:
import matplotlib.pyplot as plt
import numpy as np


def Sigmoid(x):
    return 1.0 / (1.0 + np.exp(-x))

x = np.arange(-10, 10, 0.1)
h = Sigmoid(x)  # Sigmoid函数
plt.plot(x, h)
plt.axvline(0.0, color='k')
plt.axhline(y=0.5, ls='dotted', color='k')
plt.yticks([0.0,  0.5, 1.0])  # y axis label
plt.title(r'Sigmoid函数曲线', fontsize = 15)
plt.text(5,0.8,r'$y = \frac{1}{1+e^{-z}}$', fontsize = 18)
plt.show()
/opt/conda/lib/python3.5/site-packages/matplotlib/font_manager.py:278: UserWarning: Matplotlib is building the font cache using fc-list. This may take a moment.
  'Matplotlib is building the font cache using fc-list. '

1.2.IRIS数据集介绍

Iris也称鸢尾花卉数据集,是常用的分类实验数据集,由R.A. Fisher于1936年收集整理的。其中包含3种植物种类,分别是山鸢尾(setosa)变色鸢尾(versicolor)和维吉尼亚鸢尾(virginica),每类50个样本,共150个样本。

该数据集包含4个特征变量,1个类别变量。iris每个样本都包含了4个特征:花萼长度,花萼宽度,花瓣长度,花瓣宽度,以及1个类别变量(label)。我们需要建立一个分类器,分类器可以通过这4个特征来预测鸢尾花卉种类是属于山鸢尾,变色鸢尾还是维吉尼亚鸢尾。其中有一个类别是线性可分的,其余两个类别线性不可分,这在最后的分类结果绘制图中可观察到。

变量名变量解释数据类型
sepal_length花萼长度(单位cmnumeric
sepal_width花萼宽度(单位cm)numeric
petal_length花瓣长度(单位cm)numeric
petal_width花瓣宽度(单位cm)numeric
species种类categorical
In [4]:
# 导入所需要的包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.plotly as py
import plotly.graph_objs as go
from sklearn.decomposition import PCA

from plotly.offline import init_notebook_mode, iplot
init_notebook_mode(connected = True)

1.2.1. 数据集预览

In [5]:
iris_path = '/home/kesci/input/iris/iris.csv'
data = pd.read_csv(iris_path)
In [6]:
data.head()
Out[6]:
 Sepal.LengthSepal.WidthPetal.LengthPetal.WidthSpecies
05.13.51.40.2setosa
14.93.01.40.2setosa
24.73.21.30.2setosa
34.63.11.50.2setosa
45.03.61.40.2setosa
1.2.2. 鸢尾花三类品种数量的饼图
In [7]:
labels = data.groupby('Species').size().index
values = data.groupby('Species').size()
trace = go.Pie(labels=labels, values=values)
layout = go.Layout(width=350, height=350)
fig = go.Figure(data=[trace], layout=layout)
iplot(fig)
33.3%33.3%33.3% Export to plot.ly »
setosaversicolorvirginica
In [8]:
# Feature Plot
groups = data.groupby(by = "Species")
means, sds = groups.mean(), groups.std()
means.plot(yerr = sds, kind = 'bar', figsize = (9, 5), table = True)
plt.show()
1.2.3. 绘制数据集的特征散点图

特征对两两之间的相关性散点图: 如图所示,特征散点图成对角分布,4个特征两两组合(任意两个特征作为x轴,y轴),不同品种的花用不同颜色标注:setosa(橙色),versicolor(绿色),virginica(粉色)。共有12种组合,其实只有6种,因为另外6种与之对称。

In [9]:
col_map = {'setosa': 'orange', 'versicolor': 'green', 'virginica': 'pink'}
pd.tools.plotting.scatter_matrix(data.loc[:, 'Sepal.Length':'Petal.Width']
, diagonal = 'kde', color = [col_map[lb] for lb in data['Species']], s = 75, figsize = (11, 6))
plt.show()
/opt/conda/lib/python3.5/site-packages/ipykernel_launcher.py:3: FutureWarning:

'pandas.tools.plotting.scatter_matrix' is deprecated, import 'pandas.plotting.scatter_matrix' instead.

2. Getting Started

2.1. 导入鸢尾花数据集矩阵

在这篇入门教程中,暂且不进行数据转换至numpy矩阵的指导,因为scikit库中已经内置了矩阵形式的iris数据集,我们可以直接导入使用。 如果想了解 如何将原始数据转变成机器学习算法可学习的numpy数据集,以及 数据预处理 和 降维 的小伙伴,可以关注下一篇教程 用逻辑回归实现鸢尾花数据集分类(2)

In [10]:
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
In [11]:
iris = load_iris()
In [12]:
# data对应了样本的4个特征,共150个样本,即150行x4列的矩阵
print("Iris Dataset contains %s samples in total,%s features."%(iris.data.shape[0], iris.data.shape[1]))
Iris Dataset contains 150 samples in total,4 features.
In [13]:
iris.data[:5]
Out[13]:
array([[5.1, 3.5, 1.4, 0.2],
       [4.9, 3. , 1.4, 0.2],
       [4.7, 3.2, 1.3, 0.2],
       [4.6, 3.1, 1.5, 0.2],
       [5. , 3.6, 1.4, 0.2]])

target代表150个样本对应的类别label,即150行x1列的矩阵

样本的类别label含义

Class LabelMeaning
0山鸢尾(setosa)
1变色鸢尾(versicolor))
2维吉尼亚鸢尾(virginica)
In [14]:
print("Labels' shape %s." %(iris.target.shape))
Labels' shape 150.
In [15]:
iris.target
Out[15]:
array([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, 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, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

2.2 创建训练集与测试集

在这里我们先前取两列数据(即特征花萼长度与宽度)进行对数几率回归的分类。这个例子借鉴于。 用train_test_split函数将原始数据集按7:3的比例分成训练集与测试集

In [16]:
from sklearn.model_selection import train_test_split

X = iris.data[:, :2]             # 取前两列数据
Y = iris.target

x_train, x_test, y_train, y_test = train_test_split(X,Y, test_size = 0.3, random_state = 0)
In [17]:
x_train.shape,y_train.shape,x_test.shape, y_test.shape
Out[17]:
((105, 2), (105,), (45, 2), (45,))
绘制前两列数据的散点图
In [18]:
# 画出训练集数据点
trace = go.Scatter(x = X[:,0], y = X[:,1], mode = 'markers', 
                    marker = dict(color = np.random.randn(150),size = 10, colorscale='Viridis',showscale=False))
layout = go.Layout(title = '训练点', xaxis=dict(title='花萼长度 Sepal length', showgrid=False),
                    yaxis=dict(title='花萼宽度 Sepal width',showgrid=False),
                    width = 700, height = 380)
fig = go.Figure(data=[trace], layout=layout)
In [19]:
iplot(fig)
567822.533.544.5 Export to plot.ly »
训练点花萼长度 Sepal length花萼宽度 Sepal width

2.3. 模型搭建与分类器训练

  1. 导入模型,调用逻辑回归LogisticRegression()函数。
    • penalty: 正则化选择参数(惩罚项的种类),默认方式为L2正则化
    • C: 正则项系数的倒数
    • solver: 对于多分类任务, 使用‘newton-cg’, ‘sag’, ‘saga’ and ‘lbfgs’ 来解决多项式loss
    • multi_class: 默认值‘ovr’适用于二分类问题,对于多分类问题,用‘multinomial’在全局的概率分布上最小化损失
  2. 训练LogisticRegression分类器
    • 调用fit(x,y)的方法来训练模型,其中x为数据的属性,y为所属类型。
  3. 利用训练得到的模型对数据集进行预测 predict(),返回预测结果。

Tips: 可以通过点击cell中的+来“添加代码片段功能”来直接导入需要的代码

In [20]:
from sklearn.linear_model import LogisticRegression

# lr = LogisticRegression(C = 1e5) # C: Inverse of regularization strength
lr = LogisticRegression(penalty='l2',solver='newton-cg',multi_class='multinomial')
lr.fit(x_train,y_train)
Out[20]:
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
          intercept_scaling=1, max_iter=100, multi_class='multinomial',
          n_jobs=1, penalty='l2', random_state=None, solver='newton-cg',
          tol=0.0001, verbose=0, warm_start=False)

2.4. 模型评估

In [21]:
print("Logistic Regression模型训练集的准确率:%.3f" %lr.score(x_train, y_train))
print("Logistic Regression模型测试集的准确率:%.3f" %lr.score(x_test, y_test))
Logistic Regression模型训练集的准确率:0.829
Logistic Regression模型测试集的准确率:0.822

LogisticRegression分类器正确率分析

In [22]:
from sklearn import metrics
y_hat = lr.predict(x_test)
accuracy = metrics.accuracy_score(y_test, y_hat) #错误率,也就是np.average(y_test==y_pred)
print("Logistic Regression模型正确率:%.3f" %accuracy)
Logistic Regression模型正确率:0.822
In [23]:
target_names = ['setosa', 'versicolor', 'virginica']
print(metrics.classification_report(y_test, y_hat, target_names = target_names))
             precision    recall  f1-score   support

     setosa       1.00      1.00      1.00        16
 versicolor       0.81      0.72      0.76        18
  virginica       0.62      0.73      0.67        11

avg / total       0.83      0.82      0.82        45

2.5. 可视化分类结果

绘制图像

下图会绘制逻辑回归分类器在鸢尾花数据集上的决策边界,不同类别的数据点用不同颜色标注。 为了能可视化分类效果,我们会画出决策边界(decision boundry)。

1.确定坐标轴范围,x,y轴各表示一个特征

- 先取二维数组的第一列特征(花萼长度)的最大最小值和步长h = .02生成数组,
- 再取二维数组的第二列特征(花萼宽度)的最大最小值和步长h = .02生成数组,

最后由meshgrid()函数在网格[x_min, x_max] x [y_min, y_max] 中绘制出。生成两个网格矩阵x1, x2

In [24]:
# Plot the decision boundary. For that, we will assign a color to each
# point in the mesh [x_min, x_max]x[y_min, y_max].
x1_min, x1_max = X[:, 0].min() - .5, X[:, 0].max() + .5 # 第0列的范围
x2_min, x2_max = X[:, 1].min() - .5, X[:, 1].max() + .5 # 第1列的范围
h = .02
x1, x2 = np.meshgrid(np.arange(x1_min, x1_max, h), np.arange(x2_min, x2_max, h)) # 生成网格采样点
In [25]:
grid_test = np.stack((x1.flat, x2.flat), axis=1)  # 测试点
grid_hat = lr.predict(grid_test)                  # 预测分类值
# grid_hat = lr.predict(np.c_[x1.ravel(), x2.ravel()])
grid_hat = grid_hat.reshape(x1.shape)             # 使之与输入的形状相同
In [55]:
plt.figure(1, figsize=(6, 5))
# 预测值的显示, 输出为三个颜色区块,分布表示分类的三类区域
plt.pcolormesh(x1, x2, grid_hat,cmap=plt.cm.Paired) 

# plt.scatter(X[:, 0], X[:, 1], c=Y,edgecolors='k', cmap=plt.cm.Paired)
plt.scatter(X[:50, 0], X[:50, 1], marker = '*', edgecolors='red', label='setosa')
plt.scatter(X[50:100, 0], X[50:100, 1], marker = '+', edgecolors='k', label='versicolor')
plt.scatter(X[100:150, 0], X[100:150, 1], marker = 'o', edgecolors='k', label='virginica')
plt.xlabel('花萼长度-Sepal length')
plt.ylabel('花萼宽度-Sepal width')
plt.legend(loc = 2)

plt.xlim(x1.min(), x1.max())
plt.ylim(x2.min(), x2.max())
plt.title("Logistic Regression 鸢尾花分类结果", fontsize = 15)
plt.xticks(())
plt.yticks(())
plt.grid()

plt.show()

如图所示,setosa类线性可分,而versicolor类与virginica类线性不可分。

  • 18
    点赞
  • 157
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值