简单来说, 逻辑回归(Logistic Regression)是一种用于解决二分类(0 or 1)问题的机器学习方法,用于估计某种事物的可能性。比如某用户购买某商品的可能性,某病人患有某种疾病的可能性,以及某广告被用户点击的可能性等。 注意,这里用的是“可能性”,而非数学上的“概率”。logisitc回归的结果并非数学定义中的概率值,不可以直接当做概率值来用。该结果往往用于和其他特征值加权求和,而非直接相乘。通过给定的n组数据(训练集)来训练模型,并在训练结束后对给定的一组或多组数据(测试集)进行分类。其中每一组数据都是由p 个指标构成。
这里举一个例子来说明Logistic回归处理数据并对其进行二分类的过程。
我们给出一个人的 [身高,体重] 这两个指标,然后判断这个人是属于”胖“还是”瘦“这一类。对于这个问题,我们可以先测量n个人的身高、体重以及对应的指标”胖“,"瘦”,把胖和瘦分别用0和1来表示,把这n组数据输入模型进行训练。训练之后再把待分类的一个人的身高、体重输入模型中,看这个人是属于“胖”还是“瘦”。
如果数据是有两个指标,可以用平面的点来表示数据,其中一个指标为x轴,另一个为y轴;如果数据有三个指标,可以用空间中的点表示数据;如果是p维的话(p>3),就是p维空间中的点。
从本质上来说,逻辑回归训练后的模型是平面的一条直线(p=2),或是平面(p=3),超平面(p>3)。并且这条线或平面把空间中的散点分成两半,属于同一类的数据大多数分布在曲线或平面的同一侧。
如上图所示,其中点的个数是样本个数,两种颜色代表两种指标。这个直线可以看成经这些样本训练后得出的划分样本的直线。那么对于之后的样本的p1与p2的值,就可以根据这条直线来判断它属于哪一类了。
首先,我们处理二分类问题。由于分成两类,我们便让其中一类标签为0,另一类为1。我们需要一个函数,对于输入的每一组数据,都能映射成0~1之间的数。并且如果函数值大于0.5,就判定属于1,否则属于0。而且函数中需要待定参数,通过利用样本训练,使得这个参数能够对训练集中的数据有很准确的预测。
这个函数就是Sigmoid函数,形式为。其函数曲线如下:
从上图可以看到sigmoid函数是一个s形的曲线,它的取值在[0, 1]之间,在远离0的地方函数的值会很快接近0或者1。它的这个特性对于解决二分类问题十分重要。
Sigmoid函数的输入记为z,z=x+b,其中向量x是分类器的输入数据,向量w也就是我们要找到的最佳系数,b为常数。代入Sigmoid函数中得到。
至此我们便可以输入数据代入z中再由Sigmoid函数映射到0~1之间,得到一个这样的数值之后就可以进行分类,大于0.5的分入1类,反之分入0类。
现在的问题就在于最佳回归系数是多少?即w和b。
确定最佳回归系数的最优化方法有梯度下降法与梯度上升法等。这里我们重点介绍梯度上升法。
梯度上升法基于的思想是:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。如果梯度记为,则函数f(x,y)的梯度由下式表示:
这个梯度意味着要沿x的方向移动∂ f ( x , y ) /∂ x,沿y的方向移动∂ f ( x , y ) /∂ y。其中,函数f(x,y)必须要在待计算的点上有定义并且可微。如下图:
上图展示的,梯度上升算法到达每个点后都会重新估计移动的方向。从 P0 开始,计算完该点的梯度,函数就根据梯度移动到下一点 P1。在 P1 点,梯度再次被重新计算,并沿着新的梯度方向移动到 P2 。如此循环迭代,直到满足停止条件。迭代过程中,梯度算子总是保证我们能选取到最佳的移动方向。
上图中的梯度上升算法沿梯度方向移动了一步。可以看到,梯度算子总是指向函数值增长最快的方向。这里所说的是移动方向,而未提到移动量的大小。该量值称为步长,记作 α 。用向量来表示的话,梯度上升算法的迭代公式如下:w:=w+α▽wf(w)。
以下用一个跟简单的例子说明梯度上升的含义:
设函数f(x)=-x^2+4x,函数图如下。则f'(x)=-2x+4,令导数为0,可求出x=2即取得函数f(x)的极大值。极大值等于f(2)=4。
但是真实环境中的函数不会像上面这么简单,就算求出了函数的导数,也很难精确计算出函数的极值。此时我们就可以用迭代的方法来做。就像爬坡一样,一点一点逼近极值。这种寻找最佳拟合参数的方法,就是最优化算法。爬坡这个动作用数学公式表达即为:
其中,α为步长,也就是学习速率,控制更新的幅度。效果如下图所示:
比如从(0,0)开始,迭代路径就是1->2->3->4->…->n,直到求出的x为函数极大值的近似值,停止迭代。
下动图为模拟梯度下降法,将其反转后即为梯度上升法。
python代码实现梯度下降法:
数据集结构如下:
代码如下:
import matplotlib.pyplot as plt
from numpy import *
import math
#加载数据集
def loadDataSet():
'''数据集的前两个值分别为X1和X2,第三个值是数据对应的类别标签,为了方便计算,把X0的值设置成了1.0'''
dataMat = []
labelMat = []
fr = open('D:/系统默认/桌面/深度学习/testSet.txt') #打开logistics regression 数据集).txt文件
# 一定要输入正确的数据集文件所在的地址目录
for line in fr.readlines(): #逐行读取
lineArr = line.strip().split()
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) #因为线性回归化式为 H(x) = W0 + W1*X1 + W2*X2即为 (W0, W1, W2)*(1, X1, X2),
# 其中 (W0, W1, W2) 即为所求回归系数 W。 为了方便计算, 读出 X1, X2 后要在前面补上一个 1.0
labelMat.append(int(lineArr[2]))
return dataMat, labelMat
#分类器的分类(转换)函数
def sigmoid(inX):
return 1.0 / (1 + exp(-inX)) ##计算 sigmoid 函数
#梯度上升算法,用来计算出最佳回归系数
def gradAscent(dataMatIn, classLabels):
'''第一个参数是2维数组,每列代表每个不同特征,每行代表每个训练样本
第二个参数是类别标签,1*100的行向量,为便于计算,将其转换为列向量,即进行转置,并赋值给labelMat
'''
dataMatrix = mat(dataMatIn) # convert to NumPy matrix 获得输入数据并将其转换为Numpy矩阵数据类型
labelMat = mat(classLabels).transpose() # convert to NumPy matrix 获得输入数据并将其转换为Numpy矩阵数据类型
m, n = shape(dataMatrix) #shape函数是numpy.core.fromnumeric中的函数,它的功能是查看矩阵或者数组的维数
alpha = 0.001 #步长,向函数增长最快的方向的移动量,即学习率
maxCycles = 500 #迭代次数
weights = ones((n, 1)) #生成n行一列的元素为1的矩阵赋给weihts,即回归系数初始化为1
#循环 maxCycles次, 每次都沿梯度向真实值 labelMat 靠拢
for k in range(maxCycles): # heavy on matrix operations
h = sigmoid(dataMatrix * weights) # matrix multiplication 矩阵相乘 包含了300次的乘积
error = (labelMat - h) # vector subtraction 向量减法,计算真实类别与预测类别的差值,h是一个列向量,列向量的元素个数等于样本数,即为100
weights = weights + alpha * dataMatrix.transpose() * error # matrix multiplication 矩阵相乘,dataMatrix.transpose()* error 就是梯度f(w),按照该差值的方向调整回归系数
return weights
#输出运用梯度上升优化算法后得到的最理想的回归系数的值
def GetResult():
dataMat, labelMat = loadDataSet()
weights = gradAscent(dataMat, labelMat)
print(weights)
plotBestFit(weights)
#画出数据集和Logistic回归最佳拟合直线
def plotBestFit(weights):
#画点
dataMat, labelMat = loadDataSet()
dataArr = array(dataMat)
n = shape(dataArr)[0]
xcord1 = []
ycord1 = []
xcord2 = []
ycord2 = []
for i in range(n):
if int(labelMat[i]) == 1:
xcord1.append(dataArr[i, 1])
ycord1.append(dataArr[i, 2])
else:
xcord2.append(dataArr[i, 1])
ycord2.append(dataArr[i, 2])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
ax.scatter(xcord2, ycord2, s=30, c='green')
# 画线
x = arange(-3.0, 3.0, 0.1)
y = (0.48 * x + 4.12414) / (0.616)
# y = (-weights[0]-weights[1]*x)/weights[2]
ax.plot(x, y)
plt.xlabel('X1')
plt.ylabel('X2')
plt.show() #显示
GetResult()
可以看出分类效果还是不错的。
下面我们通过训练鸢尾花数据集对Logistic回归模型进行简单的评估。(鸢尾花数据集介绍)
因为我们只讨论二分类问题故只选择数据集中类别为0和1的样本。
## 基础函数库
import numpy as np
import pandas as pd
## 绘图函数库
import matplotlib.pyplot as plt
import seaborn as sns
## 我们利用 sklearn 中自带的 iris 数据作为数据载入,并利用Pandas转化为DataFrame格式
from sklearn.datasets import load_iris
data = load_iris() #得到数据特征
iris_target = data.target #得到数据对应的标签
iris_features = pd.DataFrame(data=data.data, columns=data.feature_names) #利用Pandas转化为DataFrame格式
## 为了正确评估模型性能,将数据划分为训练集和测试集,并在训练集上训练模型,在测试集上验证模型性能。
from sklearn.model_selection import train_test_split
## 选择其类别为0和1的样本 (不包括类别为2的样本)
iris_features_part = iris_features.iloc[:100]
iris_target_part = iris_target[:100]
## 测试集大小为20%, 80%/20%分
x_train, x_test, y_train, y_test = train_test_split(iris_features_part, iris_target_part, test_size = 0.2, random_state = 2020)
## 从sklearn中导入逻辑回归模型
from sklearn.linear_model import LogisticRegression
## 定义 逻辑回归模型
clf = LogisticRegression(random_state=0, solver='lbfgs')
# 在训练集上训练逻辑回归模型
clf.fit(x_train, y_train)
## 查看其对应的w
print('the weight of Logistic Regression:',clf.coef_)
## 查看其对应的w0
print('the intercept(w0) of Logistic Regression:',clf.intercept_)
## 在训练集和测试集上分布利用训练好的模型进行预测
train_predict = clf.predict(x_train)
test_predict = clf.predict(x_test)
from sklearn import metrics
## 利用accuracy(准确度)【预测正确的样本数目占总预测样本数目的比例】评估模型效果
print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_train,train_predict))
print('The accuracy of the Logistic Regression is:',metrics.accuracy_score(y_test,test_predict))
## 查看混淆矩阵 (预测值A和真实值的各类情况统计矩阵)
confusion_matrix_result = metrics.confusion_matrix(test_predict,y_test)
print('The confusion matrix result:\n',confusion_matrix_result)
输出准确率与混淆矩阵:
可以看出准确率为1,这说明训练集与测试集中的数据均预测成功,Logistic回归模型对于该数据集的二分类效果良好。
优点:
(1)对率函数任意阶可导,具有很好的数学性质,许多现有的数值优化算法都可以用来求最优解,训练速度快;
(2)简单易理解,模型的可解释性非常好,从特征的权重可以看到不同的特征对最后结果的影响;
(3)适合二分类问题,不需要缩放输入特征;
(4)内存资源占用小,因为只需要存储各个维度的特征值;
(5)直接对分类可能性进行建模,无需事先假设数据分布,避免了假设分布不准确所带来的问题
(6)以概率的形式输出,而非知识0.1判定,对许多利用概率辅助决策的任务很有用
缺点:
(1)不能用逻辑回归去解决非线性问题,因为Logistic的决策面试线性的;
(2)对多重共线性数据较为敏感;
(3)很难处理数据不平衡的问题;
(4)准确率并不是很高,因为形式非常的简单(非常类似线性模型),很难去拟合数据的真实分布;
(5)逻辑回归本身无法筛选特征,有时会用gbdt来筛选特征,然后再上逻辑回归。