图文实例教会你逻辑回归

金融与技术学习兴趣小组

编译整理 | 一只小绿怪兽

逻辑回归(Logistic regression),虽然名字中带有回归两个字,但其实它解决的并不是回归问题,而是分类问题。先来看一下它的定义:

在统计学中,逻辑回归是用来对某一类别或事件发生的概率进行建模的模型,比如,通过/失败、赢/输、存活/死亡,健康/生病。它也可以应用于多分类的问题,比如,判断一个图片中是否包含猫、狗、狮子等等。每一个在图像中被检测的物体都会被赋予一个概率,这个概率的取值范围在0到1之间,且总和为1。

我们在之前的文章中介绍过KNN算法,该算法同样可用于解决分类问题,它的分类依据是距离,即如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。

对比来看的话,从定义中可以看出,逻辑回归是基于概率对事件进行分类的,也就是说,逻辑回归解决的是分类问题,并且分类的依据是概率。明白了这一点,下面我们就来看一下,它到底是怎么用概率进行分类的。

逻辑回归 vs 线性回归

逻辑回归和线性回归在原理上有很多相似之处,所以对比来看的话会更加清晰。

首先,回顾一下线性回归。假设有一组数据,包含两列,重量和尺寸,现在想看一下二者之间的关系,然后建立一个线性回归模型,用重量预测尺寸,具体步骤如下:

① 获取数据,包含重量和尺寸。

② 建立模型,拟合出一条直线。

在确定这条直线的时候,运用的方法是最小二乘法,它的思路是,计算每个点到拟合直线的距离(残差),先平方再求和,然后通过最小化残差平方和,确定直线的斜率和截距。

③ 预测。

利用重量和尺寸之间的线性关系,如果知道了重量的值,就可以预测对应的尺寸的值。

下面来看一下逻辑回归。和上面用线性回归预测连续值不同,逻辑回归用来预测分类问题,比如二分类的是/不是。如下图中,用重量来判断是否肥胖。

① 获取数据,包含重量和它所属的类别,即是否肥胖。

② 建立模型,拟合出一条S曲线。

与线性回归不同,逻辑回归拟合的是一条S曲线,并且曲线在纵轴的取值范围是0到1,代表的是以重量衡量时,属于肥胖的概率。

比如,对于B的重量,它属于肥胖的概率比较大,大约在0.9以上,对于A的重量,它属于肥胖的概率比较小,大约在0.5左右。

可以看出,相比于线性回归能够根据拟合直线预测出一个具体的值,逻辑回归则是根据拟合曲线预测出一个概率,然后再根据这个概率来判断它应该属于哪个类别。比如,设置一个临界值为0.5,如果得出的概率大于0.5,则归类为是肥胖,否则就归类为不是肥胖。

前面提到,在确定拟合直线时,线性回归用到的是最小二乘法,通过最小化残差平方和,得到直线的斜率和截距。而在逻辑回归中,没有残差的概念,所以也就不能用最小二乘法来确定拟合曲线,而是用最大似然估计。

最大似然估计

在线性回归中,为了估计直线的斜率和截距这两个参数,使用的方法是最小二乘法,即最小化残差平方和,而在逻辑回归中,为了估计参数,使用的方法是最大似然估计即最大化一个似然函数,概念“似然”对应的是“可能性likelihood”,所以也可以理解为最大化一个可能性函数,定义如下。

根据定义,如果想要估计参数,首先得有一个似然函数,然后通过最大化这个似然函数,得到参数的估计值。

在逻辑回归中,我们需要借助一个函数来构建似然函数,这个函数就是sigmoid函数,也叫Logistic函数。先来看看它长什么样子,如下图。

从上图可以看出,sigmoid函数的形状像一个S,自变量的取值范围是负无穷到正无穷,因变量的取值范围在0到1之间,而且,当自变量大于0时,因变量的值大于0.5,当自变量小于0时,因变量的值小于0.5。

在二分类问题中,因变量y的值只能是0或者1,利用sigmoid函数的特征,如果把临界值设置为0.5,则当自变量大于0,因变量的取值范围在0.5和1之间时,让y等于1,相反,当自变量小于0,因变量的取值范围在0和0.5之间时,让y等于0。

因此,借助sigmoid函数的上述特性,我们可以解决分类问题。明白了这一点,下面就来看一下具体的公式。

首先,在最开始,有自变量x和因变量h(θx),因变量的取值与自变量x和参数θ的取值有关,此时因变量h(θx)的取值范围没有限制,可以是从负无穷到正无穷,如上图例子,其中,θ是要估计的参数。

接下来,为了让h(θx)的取值范围压缩到0和1之间,需要借助sigmoid函数转换一下,最终得到公式(2)中的函数,又因为逻辑函数计算的是概率,因此,最终在等式的右边是一个概率值,含义是在给定自变量x和参数θ的条件下,y=1的概率。

整个分类过程的转换思路如上图所示,下面就来看一下具体的例子。

在上图的例子中,直线将平面分成两个区域,当其大于等于0时,y=1,即直线右侧包含星星的区域,小于0时,y=0,即直线左侧包含圆圈的区域。也就是说,通过这条直线,我们把y=1和y=0的值分开了,这条线叫做决策边界(Decision boundary)

同样,在这个例子中,曲线将平面分成两个区域,当其大于等于0时,y=1,即曲线外侧包含星星的区域,小于0时,y=0,即曲线内部包含圆圈的区域,这条曲线是决策边界。

在上面给出的两个例子中,为了让大家更直观地观察图形效果,我们直接对参数θ进行了赋值,但其实这个参数θ是需要根据数据集估计的,下面,就回到最开始的问题,如何用最大似然估计的方法得到参数θ。

由于原始式子(2)中的公式比较复杂,所以这里我们借助logit函数,把原式转换成带有log的函数。

由定义可知,logit函数把原来取值范围在0到1之间的概率,转换成了负无穷到正无穷的范围,如下图。

此时,如果按照线性回归的思路,用最小二乘法,由于这里点到直线的距离可以是无穷大,没法求最小值,所以不能用该方法,而应该用最大似然估计。

第一步,计算这些点对应的log(odds)的值。

第二步,根据p和log(odds)之间的对应关系,求出p值。比如,看A点,计算出它的log(odds)等于-2.1,然后再带入p等式右侧,求出p值等于0.1。当把所有的点都按照上述方式对应到左侧之后,就能够拟合出一条S曲线。

第三步,计算该拟合曲线的可能性,将各样本点所代表的概率值相乘即可。这里需要注意的是,某一个点属于蓝色还是橙色的概率和为1,其中蓝色代表的是y=1,橙色代表的是y=0。因此,如果蓝色点的概率用p表示,则橙色点的概率则等于1-p。

在计算可能性likelihood的时候,通常习惯先取对数,然后拆分成加法计算,这里可以理解为,求likelihood的最大值和求log(likelihood)的最大值是一样的。

然后旋转第一步中右侧曲线的位置,重复执行上述操作,可以得到很多个不同的可能性likelihood的取值,最终,可能性最大的那条曲线拟合出的结果就是我们想要的预测曲线。

上面提到,我们要不断旋转第一步中右侧曲线的位置来计算可能性likelihood,然后取最大的那一个,但是旋转曲线的结果有无穷多个,如果没有一个规则的话,会经历很多次没必要的计算,浪费资源,也浪费感情。

因此,为了解决上述问题,需要介绍另外两个概念,损失函数(loss function)梯度下降(gradient descent)。

损失函数(loss function)的概念,在之前介绍线性回归的文章中有介绍过,可以把它理解为真实值和根据模型预测得出的预测值之间的差异。

梯度下降(gradient descent)是一种优化算法,它的目的是找到一个函数的局部最小值。

因此,我们可以利用梯度下降的方法,去求损失函数的最小值。当损失函数取最小值时,预测值和真实值之间的差距最小,此时得出的拟合曲线和估计出的参数是我们想要得到的最优结果。

首先,看一下在逻辑回归中,损失函数的表达式长什么样子。

如上图中的推导,将可能性likelihood按照y=1和y=0分成两个部分,分别求最大值,然后在各自前面添加一个负号,就转换成求最小值,从而可以推导出右侧的损失函数J(θ)。注意,在二分类问题中,y的值只能是1或者0。

有了损失函数J(θ),接下来,就可以用梯度下降的方法,去求损失函数J(θ)的最小值了,当J(θ)取最小值时的参数θ,就是通过最大似然估计得到的最优参数。

本文暂时不对梯度下降的具体原理和公式做过多介绍,大家只要先知道它是求最小值的一个优化算法就可以啦,下面直接看一下逻辑回归在Python中是如何调用的。

Python 实例

我们可以导入sklearn.linear_model模块中LogisticRegression类实现该算法,先利用训练集数据构建模型,再用测试集数据进行预测。

逻辑回归算法的实现步骤和KNN算法类似:

① 先导入相应的模块

② 划分训练集和测试集

③ 创建一个分类器

④ 放入训练集数据进行学习,得到预测模型

⑤ 在测试集数据上进行预测

【工具】Python 3

【数据】tushare.pro 

【注】本文注重的是方法的讲解,请大家灵活掌握。

import tushare as ts
import pandas as pd
pd.set_option("expand_frame_repr", False)       # 当列太多时不换行
# 设置token
ts.set_token('your token')
pro = ts.pro_api()
# 导入000002.SZ前复权日线行情数据,保留收盘价列
df = ts.pro_bar(ts_code='000002.SZ', adj='qfq', start_date='20190101', end_date='20191231')
df.sort_values('trade_date', inplace=True)
df['trade_date'] = pd.to_datetime(df['trade_date'])
df.set_index('trade_date', inplace=True)
df = df[['close']]
# 计算当前、未来1-day涨跌幅
df['1d_future_close'] = df['close'].shift(-1)
df['1d_close_future_pct'] = df['1d_future_close'].pct_change(1)
df['1d_close_pct'] = df['close'].pct_change(1)
df.dropna(inplace=True)
# ====1代表上涨,0代表下跌
df.loc[df['1d_close_future_pct'] > 0, '未来1d涨跌幅方向'] = 1
df.loc[df['1d_close_future_pct'] df = df[['1d_close_pct', '未来1d涨跌幅方向']]
df.rename(columns={'1d_close_pct': '当前1d涨跌幅'}, inplace=True)
print(df.head())
             当前1d涨跌幅  未来1d涨跌幅方向
trade_date                     
2019-01-03  0.007112        1.0
2019-01-04  0.035728        1.0
2019-01-07  0.004815        0.0
2019-01-08 -0.001997        1.0
2019-01-09  0.013203        0.0
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
# 创建特征 X 和标签 y
y = df['未来1d涨跌幅方向'].values
X = df.drop('未来1d涨跌幅方向', axis=1).values
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=42)
# 创建一个逻辑回归分类器
logreg = LogisticRegression(solver='liblinear')
# 放入训练集数据进行学习
logreg.fit(X_train, y_train)
# 在测试集数据上进行预测
new_prediction = logreg.predict(X_test)
print("Prediction: {}".format(new_prediction))
# 测算模型的表现:预测对的个数 / 总个数
print(logreg.score(X_test, y_test))
Prediction: [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. 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.4948453608247423

需要获取可运行的Python程序脚本文件,请在本公众号私信关键字“回归”获取下载链接。

总结

本文介绍了机器学习算法中的逻辑回归,包括它的定义、原理、整个推导的过程,涉及到的概念有最大似然估计、simoid函数、决策边界、logit函数、损失函数、梯度下降,并且在最后用Python实现了逻辑回归算法。

希望本文能够对大家学习逻辑回归有帮助。

【推荐阅读】

数据科学必备基础之线性回归

机器学习算法入门之监督学习(I)

机器学习必备技能之“统计思维2.0”

机器学习必备技能之“统计思维1.0”

机器学习必备技能之“数据预处理”

最简洁的Python时间序列可视化实现

END

更多内容请关注“挖地兔”公众号。

【参考链接】

网页链接【1】

网页链接【2】

网页链接【3】

网页链接【4】

网页链接【5】

Logistic Regression [Andrew Ng]【6】

Logistic Regression [StatQuest]【7】

雪球转发:0回复:3喜欢:3

全部评论

秦如亦04-06 09:46

那我用后复权数据,然后提取最新的复权因子,除过去就和行情软件一致了吧?

Tushare挖地兔04-06 09:23

在Tushare数据接口里,不管是旧版的一些接口还是Pro版的行情接口,都是以用户设定的end_date开始往前复权,跟所有行情软件或者财经网站上看到的前复权可能存在差异,因为所有这些都是以最近一个交易日开始往前复权的。比如今天是2018年10月26日,您想查2018年1月5日~2018年9月28日的前复权数据,Tushare是先查找9月28日的复权因子,从28日开始复权,而行情软件是从10月26日这天开始复权的。

秦如亦04-01 23:57

ts.pro_bar(ts_code='600276.SH', adj='qfq', start_date='20100104', end_date='20100104')大佬,参数是2010年恒瑞医药的前复权价格,为啥得到的是不复权的价格呢?600276.SH 20100104 52.01