Task 01|基于逻辑回归的分类预测

知识背景

关于逻辑回归的几个问题

逻辑回归相比线性回归,有何异同?

逻辑回归和线性回归最大的不同点是逻辑回归解决的是分类问题,而线性回归解决的是回归问题。

逻辑回归又可以认为是广义线性回归的一种特殊形式,其特殊之处在于目标(label/target)的取值服从二元分布。

所谓逻辑回归是一种特殊的广义线性回归,我们可以通过狭义线性回归到逻辑回归的转化过程来理解。

狭义线性回归的表达式可表示为:
y = w*x+b

如果我们希望这个模型可以对二分类任务做出预测,即满足0,1分布,那么希望预测出来的值经过某种转换后可以分布在0,1两个值附近。
sigmoid函数可以做这样的转换,sigmoid函数的表达式为:

\delta(z) = \frac {1}{1+e^{-z}}

令:y=\delta(z)

则:\log\frac{y}{1-y}=z=w*x+b

可以看出,狭义线性回归采用y作为预测结果,逻辑回归则采用\log\frac{y}{1-y}作为预测结果。

逻辑回归还可以表示为:
y=sigmoid(w*x+b)

通过以上步骤推演,我们知道逻辑回归就是在线性回归的基础上,再做一个sigmoid计算。所以它们都可以用相同的方法,比如梯度下降来求解参数。


回归问题常用的性能度量指标

  • 点对点误差
    • MSE(Mean Square Error)均方误差 -- 预测数据和原始数据对应误差的平方和的均值
    • RMSE(Root Mean Square Error)-- 观测值与真实偏差的平方和与观测次数n比值的平方根,用来衡量观测值同真值之间的偏差
    • MAE(Mean Absolute Error)-- 计算模型输出与真实值之间的平均绝对误差
  • 带归一化的误差求解方法
    • MAPE(Mean Absolute Percentage Error)-- 不仅考虑预测值与真实值误差,还考虑误差与真实值之间的比例
    • MASE(Mean Absolute Scaled Error)-- 平均平方百分比误差
  • 点对面误差
    • R-Square决定系数(coefficient of determination)

分类问题常用的性能度量指标

  • 准确率:

    所有预测正确的样本与所有样本的比例
    Accuracy=\frac{TP+TN}{TP+FN+TN+FP}

  • 精确率:

    预测为正的样本中有多少是真正的正样本
    Precision=\frac{TP}{TP+FP}

  • 召回率:

    样本中的正例有多少被预测正确了
    Recall=\frac{TP}{TP+FN}

  • F1值:

    精确率和召回率的调和值
    F1=2*\frac{Precision*Recall}{Precision+Recall}

  • AUC(Area Under Curve):

    ROC曲线下的面积,ROC曲线是通过取不同的阈值来分别计算在每个阈值下,FPR(False Positive Rate)和TPR(True Positive Rate)的值来绘制的。


逻辑回归处理多标签分类问题时,一般怎么做?

如果y不是在[0,1]中取值,而是在k个类别中取值,这时问题就变成一个多分类问题。有两种方式可以处理该问题:

  • 当K个类别不是互斥的时候,即存在样本可能属于多个标签的情况,我们可以训练k个二分类的逻辑回归分类器。第i个分类器用以区分样本是否可以归为第i类,训练分类器时需要把标签重新整理为“第i类标签”和“非第i类标签”两类。通过这样的方法,我们就可以解决每个样本可能拥有多个标签的情况。
  • 当K个类别互斥的时候,即每个样本只属于一个标签,可以假设每个样本属于不同标签的概率服从于几何分布,使用多项式逻辑回归(Softmax Regression)来进行分类。

通过几个问题了解了逻辑回归后,接着就上代码来体验一番吧
本文将使用sklearn和著名的鸢尾花数据集来用逻辑回归做分类预测

学习目标

  • 了解逻辑回归理论
  • 掌握sklearn中LogisticsRegression的基本用法

Step 1:读取数据

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

#load data
from sklearn.datasets import load_iris

data = load_iris() # 数据特征
iris_labels = data.target # 数据标签
iris_names = data.target_names #iris分类对应的名字
iris_features = pd.DataFrame(data=data.data, columns=data.feature_names)

查看数据基本信息,大致了解一下特征和标签

# 查看数据基本信息

iris_features.info()

print(iris_features.head())
print(iris_names)

结果如下:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 4 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   sepal length (cm)  150 non-null    float64
 1   sepal width (cm)   150 non-null    float64
 2   petal length (cm)  150 non-null    float64
 3   petal width (cm)   150 non-null    float64
dtypes: float64(4)
memory usage: 4.8 KB
   sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)
0                5.1               3.5                1.4               0.2
1                4.9               3.0                1.4               0.2
2                4.7               3.2                1.3               0.2
3                4.6               3.1                1.5               0.2
4                5.0               3.6                1.4               0.2
['setosa' 'versicolor' 'virginica']

如上基本信息我们了解到:

  1. 一共有150个样本
  2. 每个样本有4个特征,都是float型。sepal length, sepal width, petal lengthpetal width分别代表花萼和花瓣的长宽。通过外观的长宽大小来判断植物的种类,也很符合人的学习习惯。
  3. 一共有3个标签:setosa, versicolor, virginica,分别代表3种花,在数据中表示为0, 1, 2.

再看看数据集中3类样本分别占的比例:

pd.Series(iris_labels).value_counts()

结果发现:

2    50
1    50
0    50

一共150个样本,3种花每种分别50个,分布还是很平均的嘛。

Step 2:数据可视化

一图胜千言,通过可视化的方法能更快更直观地了解数据,找到数据的特征,能让数据的学习和训练达到事半功倍的效果。

# 准备数据,为了不影响原数据,我们用原数据集的拷贝来画图
iris_all = iris_features.copy()
iris_all['label'] = iris_labels

# 查看数据分布
sns.pairplot(data=iris_all, diag_kind='hist', hue='label')
plt.show()
特征与标签组合的散点图

从图中可以看出:

  • petal width和petal length的区分能力比较好
  • 蓝色的这个类别主要集中在左下,集中在petal width和petal length的值比较小的部分,说明这个种类的花瓣又窄又短

通过箱线图来查看一下各个特征的数据分布:

# 从箱线图查看各个特征数据分布

for col in iris_features.columns:
    sns.boxplot(x='label', y = col, saturation=0.5, palette = 'pastel', data=iris_all)
    plt.title(col)
    plt.show()
petal length (cm)
petal width (cm)
sepal length (cm)
sepal width (cm)

通过数据分布也能明显看出来,petal length 和 petal width 的数据在各类别内集中,且在各类别间有较明显的区分度。
选取前三个特征绘制三维散点图:

from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

iris_all_class0 = iris_all[iris_all['label']==0].values
iris_all_class1 = iris_all[iris_all['label']==1].values
iris_all_class2 = iris_all[iris_all['label']==2].values

ax.scatter(iris_all_class0[:,0], iris_all_class0[:,1], iris_all_class0[:,2], label='setosa')
ax.scatter(iris_all_class1[:,0], iris_all_class1[:,1], iris_all_class1[:,2], label='versicolor')
ax.scatter(iris_all_class2[:,0], iris_all_class2[:,1], iris_all_class2[:,2], label='virginica')

ax.set_xlabel('sepal length')
ax.set_ylabel('sepal width')
ax.set_zlabel('petal length')

plt.legend()
plt.show()
三维散点图

三维散点图更清晰地看到了类别的区分。

Step 3:逻辑回归二分类训练

先用逻辑回归进行二分类训练,训练出一个区分0、1标签的分类器。

# 分割数据集和训练集
from sklearn.model_selection import train_test_split

# 先选取类别为0和1的数据,进行二分类训练
iris_features_part = iris_all[iris_all['label']<2]
iris_labels_part = iris_features_part.pop('label').tolist()

x_train, x_test, y_train, y_test = train_test_split(iris_features_part, iris_labels_part, test_size=0.3, random_state=2020)

参数解释:

  • test_size: test数据占的比例,例如0.3表示test数据占30%,train数据占70%
  • random_state: 随机数种子,代表该组随机数的编号,在重复实验中能保证每次得到的随机数是相同的。当为None时,每次得到的结果就会是随机的。

分好数据集,就可以用逻辑回归模型来训练了

from sklearn.linear_model import LogisticRegression

clf = LogisticRegression(random_state=0, solver='lbfgs')
clf.fit(x_train, y_train)

参数solver代表逻辑回归损失函数的优化方法,分别有4种方法,官方文档建议如下:

  • ‘liblinear’:Small dataset or L1 penalty
  • ‘lbfgs’、‘newton-cg’ or ‘sag’:Multinomial loss or large dataset
  • ‘sag’:Very Large dataset
    根据数据集的情况,我们选择了‘lbfgs’,这是拟牛顿法的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
# 在测试集和训练集上预测
train_pred = clf.predict(x_train)
test_pred = clf.predict(x_test)

# 预测结果检验
from sklearn import metrics

print('The accuracy in train data: ', metrics.accuracy_score(y_train, train_pred))
print('The accuracy in test data: ', metrics.accuracy_score(y_test, test_pred))

结果如下:

The accuracy in train data:  1.0
The accuracy in test data:  1.0

都达到了100%的准确率,就是这么秀~~
查看在测试集上的混淆矩阵:

confusion_matrix_result = metrics.confusion_matrix(test_pred, y_test)

plt.figure(figsize=(10, 8))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Wistia_r')

plt.xlabel('Predict labels')
plt.ylabel('Actual labels')
plt.show()
二分类混淆矩阵

Step 4:三种分类上的逻辑回归模型训练

和二分类任务下的方法相似,这次来进行多分类训练。从文章开头的几个问题可知,这个多分类问题属于互斥的多分类问题,即每个样本只能属于一个分类,我们使用多项式逻辑回归模型就可以了。

# 分割测试集和训练集(20%/80%)
x_train, x_test, y_train, y_test = train_test_split(iris_features, iris_labels, test_size=0.2, random_state=2020)

clf = LogisticRegression(random_state=0, solver='lbfgs')

clf.fit(x_train, y_train)

预测:

# 在训练集和测试集上预测

train_pred = clf.predict(x_train)
test_pred = clf.predict(x_test)

print('The accuracy in train data: ', metrics.accuracy_score(y_train, train_pred))
print('The accuracy in test data: ', metrics.accuracy_score(y_test, test_pred))

confusion_matrix_result = metrics.confusion_matrix(test_pred, y_test)

plt.figure(figsize=(10, 8))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Wistia_r')

plt.xlabel('Predict labels')
plt.ylabel('Actual labels')

plt.show()

在三分类问题上的预测结果稍微有点偏差:

The accuracy in train data:  0.9833333333333333
The accuracy in test data:  0.8666666666666667
三分类混淆矩阵

从图中能看出来,在1和2这两个类别下分别有两个预测错误。我们在之前的数据可视化中也可以看出来,橙色和绿色两个类别的分解有点模糊,这和我们之前的认识是相符合的。

总结

逻辑回归虽然叫“回归”,但实际上是一种分类算法。由线性回归经过sigmoid函数变换而来,所以预测值在0~1之间,通常用来解决二分类问题。
刚才用逻辑回归解决了二分类问题和多分类问题,这里的多分类问题是通过多项式损失函数优化来完成的,还可以将多个二分类逻辑回归模型组合来实现多分类。

END

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容