看了几位大神写的博客,对逻辑回归有了更深刻的理解,因此在这里简单记录一下自己的一些看法,当作笔记
1、逻辑回归
优势:
1、逻辑回归对线性关系的拟合效果很好
2、逻辑回归计算快
3、逻辑回归返回概率,很适合于金融的信用评分,可以依据概率来给出对应的评分
4、逻辑回归抗噪能力强
缺点:
1、不适用于于非线性模型
详细介绍:
逻辑回归一般用于分类问题,而且多用于二分类问题,为什么逻辑回归要是分类方法却叫回归呢?我认为主要原因是因为逻辑回归首先建立了一个线性回归模型,然后又用的sigmoid函数将其转化成了二分类问题。对于分类问题,我的理解是损失函数一般为交叉熵,交叉熵的形式是
其中yi是实际值,pi为预测值的概率,一般在逻辑回归中我们设定的阈值为0.5,如果给定一条数据(x1,x2..xn,y),其中y=1。在用模型预测时,我们预测其为1那一类的概率为0.8,预测其为0那一类的概率为0.2,所以该数据应该划分到1那一类。虽然我们将该值划分到1那一类中了,但是我们预测概率为0.8,而实际上我们已经知道这类数据为1那一类,概率应该是100%,所以这里就有了一个概率上的损失,1-0.8=0.2。因此我们求解的模型应该是概率损失最小的,则可以进一步转化为熵最小,即不确定性最低,因此我们可以用上面的公式作为损失函数。
这里有听起来有点晕,举个简单的例子,如果我们现在有两个模型A和B,已知一条数据m=(x1,x2,x3,...,xn,y),其中y=1(y为类别划分,包括1和0两个,这里m为1那一类),但是模型A预测m为1的概率为0.8,模型B预测m为1的概率为0.9,虽然两个模型同时把m划分到了1那一类中,但从概率上看,我们会选择模型B,因为其概率损失小。
上面是我对分类问题损失函数的简单理解,望补充。
交叉熵是怎么回事呢?首先得说到熵这个东西,熵是混乱度、不确定性的代表,如果事件N发生的概率为p,那么N的熵为
p越大,Q越小,可以理解为事件N发生的概率越大,其不确定性越小。
已经知道在逻辑斯蒂回归中,损失函数为对数损失。这里要用到极大似然估计
,
其中为sigmoid函数,我们的目的是求使得G最大时的模型参数。因为连乘不太容易求,所以对公式两边取对数转化为连加,得到如下公式
可以发现这里和上面的交叉熵很像了,其中L(w)>0。此时我们将该公式作为逻辑回归的损失函数,该函数是一个凸函数,要求其最小值可以直接采用求导的方式。
2、梯度下降法
梯度下降法是一种模型参数的求解方法,假如我们有一堆数据,然后这组数据可以拟合成一个方程,比如线性方程,那么要求方程中的参数,则可以采用梯度下降法。
接下来举个简单的例子。由于我没有训练数据,所以在这里我首先写了一段生成一堆数据的代码,然后依据这组数去训练一个模型。如果你有训练数据,当然就不用这样生成了。
import numpy as np
import matplotlib.pyplot as plt
x=4* np.random.rand(100,1) #生成100行1列的随机数,随机数的范围[0,1)
y=5+6*x+np.random.randn(100,1) #生成100行1列的随机数,随机数范围[0,1),随机数符合正太分布
#这里是给y=5+6x这个直线加了一些随机数,然后生成的一堆数据,作为我们的训练集,如果效果拟合的好,那么结果就应该接近这条直线
x_b=np.c_[np.ones((100)),x]
data=np.c_[y,x] #训练数据,要把根据这些数据,拟合出一个y=w0+w1x
##将数据以图的形式展示
plt.figure(figsize=(10,5))#设置画布的尺寸
plt.xlabel(u'y',fontsize=14)#设置x轴,并设定字号大小
plt.ylabel(u'x',fontsize=14)#设置y轴,并设定字号大小
plt.scatter(data[:,1],data[:,0], s=70,c='',edgecolors='black', alpha=1,marker='o')
plt.show()
下图是上面代码生成的一组数据,可以发现这组数比较接近一条直线,接下来我们将用这组数去拟合一条直线,方法当然是采用梯度下降法。
下面列出梯度下降法的代码
#用梯度下降法进行求解
l_rate=0.1 ##学习率
cnt=500 ##迭代次数
m=100 ##这是上面生成的数据的数量,上面生成了100组数据,因为下面要迭代过程中要取均值
def train(t):
return t0/(t+t1)
theta =np.random.randn(2,1) #初始化w0,w1
for dai in range(cnt):
gradients=1/m*x_b.T.dot(x_b.dot(theta)-y) #这是采用对数损失函数推出来的,下面我们将做一些解释
theta=theta-l_rate*gradients #沿着梯度方向对参数进行迭代更新
print('w0=',theta[0][0],'w1=',theta[1][0]) #打印参数
gradients=1/m*x_b.T.dot(x_b.dot(theta)-y)是怎么得到的呢?
这句代码可以解释为,这个公式看起来云里雾里,我们说一下推导的过程
已经知道最小二乘法的公式为
其中为预测值,上面公式可以转换为
,此外我们还可以发现是一个二次方程,所以该函数是一个凸函数。
这时候,我们的目的是求使得最小的,所以对用对求导数,并令导数为0。
(这里需要注意的是上面说了,所以是一个向量,所以应该理解的内涵是我们对求导,其实是对逐个求偏导数,当然我们在公式推导时,可以忽略)
我们继续对上面的公式进行转换得到
如此,这就是梯度下降法里的核心函数的来源。加上是为了去除样本数量多少对函数造成的影响。
上面解释了梯度下降法的核心函数的由来,下面我们接着说代码运算得到的结果,我们上面预测的结果是w0=5,w1=6,结果有偏差,和我设置的迭代次数有关,如果多迭代几次可能就更接近了
下面我们再画一张图,来展示我们求出来的结果所代表的直线,画图的代码如下
#汇出直线图
y_=np.array([[1,0],[1,4]]).dot(theta) #这里是选择x=0和x=4的两个点取画直线的
plt.figure(figsize=(10,5))#设置画布的尺寸
plt.xlabel(u'x',fontsize=14)#设置x轴,并设定字号大小
plt.ylabel(u'y',fontsize=14)#设置y轴,并设定字号大小
plt.scatter(data[:,1],data[:,0], s=70,c='',edgecolors='black', alpha=1,marker='o')
plt.plot([0,4],y_)
plt.show()
画出的图如下,其中蓝色的线就是我们拟合得到的结果
把上面的所有代码复制下来放在一起可以直接运行~~~