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−z, z=wTx+b,
其中,y=11+e−x 被称作Sigmoid函数。
Logistic Regression算法是将线性函数的结果映射到了Sigmoid函数中,即y=11+e(wTx+b)。
Sigmoid函数
下图绘制了Sigmoid函数形状,如图所示,sigmoid函数输出值范围在(0,1)之间,即代表了数据属于某一类别的概率,0.5是作为判别的临界值。
# 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()
1.2.IRIS数据集介绍
Iris也称鸢尾花卉数据集,是常用的分类实验数据集,由R.A. Fisher于1936年收集整理的。其中包含3种植物种类,分别是山鸢尾(setosa)变色鸢尾(versicolor)和维吉尼亚鸢尾(virginica),每类50个样本,共150个样本。
该数据集包含4个特征变量,1个类别变量。iris每个样本都包含了4个特征:花萼长度,花萼宽度,花瓣长度,花瓣宽度,以及1个类别变量(label)。我们需要建立一个分类器,分类器可以通过这4个特征来预测鸢尾花卉种类是属于山鸢尾,变色鸢尾还是维吉尼亚鸢尾。其中有一个类别是线性可分的,其余两个类别线性不可分,这在最后的分类结果绘制图中可观察到。
变量名 | 变量解释 | 数据类型 |
---|---|---|
sepal_length | 花萼长度(单位cm | numeric |
sepal_width | 花萼宽度(单位cm) | numeric |
petal_length | 花瓣长度(单位cm) | numeric |
petal_width | 花瓣宽度(单位cm) | numeric |
species | 种类 | categorical |
# 导入所需要的包
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)
iris_path = '/home/kesci/input/iris/iris.csv'
data = pd.read_csv(iris_path)
data.head()
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)
# 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()
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()
2.1. 导入鸢尾花数据集矩阵
在这篇入门教程中,暂且不进行数据转换至numpy矩阵的指导,因为scikit库中已经内置了矩阵形式的iris数据集,我们可以直接导入使用。 如果想了解 如何将原始数据转变成机器学习算法可学习的numpy数据集,以及 数据预处理 和 降维 的小伙伴,可以关注下一篇教程 用逻辑回归实现鸢尾花数据集分类(2)。
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
iris = load_iris()
# data对应了样本的4个特征,共150个样本,即150行x4列的矩阵
print("Iris Dataset contains %s samples in total,%s features."%(iris.data.shape[0], iris.data.shape[1]))
iris.data[:5]
target代表150个样本对应的类别label,即150行x1列的矩阵
样本的类别label含义
Class Label | Meaning |
---|---|
0 | 山鸢尾(setosa) |
1 | 变色鸢尾(versicolor)) |
2 | 维吉尼亚鸢尾(virginica) |
print("Labels' shape %s." %(iris.target.shape))
iris.target
2.2 创建训练集与测试集
在这里我们先前取两列数据(即特征花萼长度与宽度)进行对数几率回归的分类。这个例子借鉴于此。 用train_test_split函数将原始数据集按7:3的比例分成训练集与测试集
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)
x_train.shape,y_train.shape,x_test.shape, y_test.shape
# 画出训练集数据点
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)
iplot(fig)
2.3. 模型搭建与分类器训练
- 导入模型,调用逻辑回归LogisticRegression()函数。
- penalty: 正则化选择参数(惩罚项的种类),默认方式为L2正则化
- C: 正则项系数的倒数
- solver: 对于多分类任务, 使用‘newton-cg’, ‘sag’, ‘saga’ and ‘lbfgs’ 来解决多项式loss
- multi_class: 默认值‘ovr’适用于二分类问题,对于多分类问题,用‘multinomial’在全局的概率分布上最小化损失
- 训练LogisticRegression分类器
- 调用fit(x,y)的方法来训练模型,其中x为数据的属性,y为所属类型。
- 利用训练得到的模型对数据集进行预测 predict(),返回预测结果。
Tips: 可以通过点击cell中的+来“添加代码片段功能”来直接导入需要的代码
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)
print("Logistic Regression模型训练集的准确率:%.3f" %lr.score(x_train, y_train))
print("Logistic Regression模型测试集的准确率:%.3f" %lr.score(x_test, y_test))
LogisticRegression分类器正确率分析
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)
target_names = ['setosa', 'versicolor', 'virginica']
print(metrics.classification_report(y_test, y_hat, target_names = target_names))
# 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)) # 生成网格采样点
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) # 使之与输入的形状相同
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类线性不可分。