跳到主要内容

逻辑回归

简介

logistic回归又称logistic回归分析,是一种广义的线性回归分析模型,常用于数据挖掘,疾病自动诊断,经济预测等领域。例如,探讨引发疾病的危险因素,并根据危险因素预测疾病发生的概率等。以胃癌病情分析为例,选择两组人群,一组是胃癌组,一组是非胃癌组,两组人群必定具有不同的体征与生活方式等。因此因变量就为是否胃癌,值为“是”或“否”,自变量就可以包括很多了,如年龄、性别、饮食习惯、幽门螺杆菌感染等。自变量既可以是连续的,也可以是分类的。然后通过logistic回归分析,可以得到自变量的权重,从而可以大致了解到底哪些因素是胃癌的危险因素。同时根据该权值可以根据危险因素预测一个人患癌症的可能性。(摘自百度百科“Logistic回归”词条)

主要用途

  1. 寻找导致某种情况的主要因素,比如寻找导致肺癌的主要致癌因素;
  2. 预测,例如根据logistic回归模型预测在不同自变量的情况下,判断导致肺癌的概率有多大;
  3. 判别,类似预测,例如判断在不同自变量下,判断一个人有多大可能性属于肺癌。

优缺点

优点

计算代价不高,易于理解和实现。

缺点

容易欠拟合,分类精度可能不高。

相关概念

  • 海维赛德阶跃函数
  • Sigmoid函数

为了实现Logistic回归分类器,我们可以在每个特征上都乘以一个回归系数,然后把所有的结果值相加,将这个总和代入Sigmoid函数中,进而得到一个范围在0~1之间的数值。任何大于0.5的数据被分为1类,小于0.5的数据被分为0类。

确定了分类器的函数形式后,现在的问题就变成了如何求解最佳回归系数。

基于最优化方法的最佳回归系数确定

梯度上升法

基本思想:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。

梯度的定义:梯度是一个表示某一函数在某点处的方向导数沿着该方向取最大值的向量,函数在该点处沿着该方向(即梯度的方向)变化最快,变化率最大。

与梯度上升算法相应的还有梯度下降算法,梯度上升用来求函数的最大值,而梯度下降用来求函数的最小值。

梯度上升算法的伪代码如下:

每个回归系数初始化为1
重复R次:
计算整个数据集的梯度
使用步长 * 梯度更新回归系数的向量
返回回归系数

编写梯度上升法的代码:

from numpy import *

def loadDataSet():
'''
加载testSet.txt中的数据
'''
dataMat = []
labelMat = []
fr = open('testSet.txt')
for line in fr.readlines():
lineArr = line.strip().split()
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat,labelMat

loadSet()函数的功能是打开文本testSet.txt并逐行读取,每行前两个值分别是X1和X2,第三个值是数据对应的类别标签。

def sigmoid(inX):
'''
定义sigmoid函数
'''
return 1.0/(1+exp(-inX))

# 梯度上升算法
def gradAscent(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn) #转换为numpy矩阵数据类型
labelMat = mat(classLabels).transpose() #转换为numpy矩阵数据类型
m,n = shape(dataMatrix)
alpha = 0.001 # alpha是向目标移动的步长
maxCycles = 500 # maxcycles是迭代次数
weights = ones((n,1)) # 初始化回归系数
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights) # 矩阵相乘
error = (labelMat - h) # 向量减法
weights = weights + alpha * dataMatrix.transpose()* error # 矩阵相乘
return weights

测试算法:

dataArr,labelMat = loadDataSet()
print(gradAscent(dataArr,labelMat))
# 打印回归系数
matrix([[ 4.12414349],
[ 0.48007329],
[-0.6168482 ]])

随机梯度上升法

梯度上升法在每次更新回归系数时都需要遍历整个数据集,随着样本数和特征数的增长,梯度上升法的复杂度会变得很高,一种改进方法是一次仅用一个样本点来更新回归系数,该方法称为随机梯度上升算法。

随机梯度上升算法的伪代码如下:

所有回归系数初始化为1
对数据集中每个样本
计算该样本的梯度
使用 步长 * 梯度更新回归系数值
返回回归系数值

接下来对随机梯度上升算法做一个简单实现:

def stocGradAscent0(dataMatrix, classLabels):
'''
随机梯度上升算法的简单实现
'''
m,n = shape(dataMatrix)
alpha = 0.01
weights = ones(n) #初始化所有回归系数为1
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h # h和error都是标量
weights = weights + alpha * error * dataMatrix[i]
return weights

上面对随机梯度上升算法做了一个简单的实现,可以看出,随机梯度上升算法和梯度上升法很相像,但随机梯度上升算法的变量h和error都是数值,不是向量,而且随机梯度上升算法中没有矩阵的转换过程。

优化算法的优劣主要看其是否收敛,而上面的简单实现需要大量迭代才会使得回归系数收敛,为此,接下来做个改进:

def stocGradAscent1(dataMatrix, classLabels, numIter=150):
'''
随机梯度上升算法改进版
'''
m,n = shape(dataMatrix)
weights = ones(n) #initialize to all ones
for j in range(numIter):
dataIndex = range(m)
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001 #步长在每次迭代时都会调整
randIndex = int(random.uniform(0,len(dataIndex))) #随机选取样本来更新回归系数
h = sigmoid(sum(dataMatrix[randIndex]*weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights

改进版中主要有两个地方改进:

  1. 步长在每次迭代时都会调整,避免数据波动或高频波动;
  2. 随机选取样本来更新回归系数,减少周期性的波动。

用Logistic回归进行分类

使用Logistic回归进行分类的方法就是把测试集上每个特征向量乘以最优化算法得来的回归系数,再将该乘积结果求和代入Sigmoid函数中即可,大于0.5就预测类别标签为1,否则为0.

scikit-learn中的逻辑回归

from sklearn.linear_model import LogisticRegression

注意事项:

  • 建模数据量不能太少。
  • 要注意排除自变量中的共线性问题。
  • 异常值会给模型带来很大干扰,应该删除。
  • 逻辑回归模型本身不能处理缺失值。