一、逻辑回归算法简介
逻辑回归算法是一种用于解决二分类问题的统计方法,它通过拟合一个逻辑函数(通常是Sigmoid函数)来预测某个事件发生的概率。逻辑回归虽然名字中包含“回归”,但实际上它是一种分类方法,特别是用于处理二分类问题,即结果只有两种可能的情况。
二、算法原理
2.1 线性回归
线性回归模型是一种用于预测连续变量的统计方法,它通过构建一个线性方程来拟合数据点。这个线性方程可以表示为:
其中,w和b都是通过学习得到的,最常用的方法就是最小二乘法。在线性回归中,最小二乘法就是试图找到一条直线,使得所有样本到直线上的欧氏距离之和最小。我们只需要将函数求导并令导数为0即可求解出w和b的最优解。
2.2 sigmoid函数
Sigmoid函数是一种在生物学、统计学及深度学习中广泛使用的激活函数,以其能够将输入映射到0和1之间的概率值而闻名。Sigmoid函数的基本形式为 。这个表达式说明Sigmoid函数接收任意实数作为输入,输出则被限制在0到1之间。这种特性使得Sigmoid函数非常适合用于表示概率,或者在任何需要将变量压缩到0和1区间的场景中使用。其函数图像如下图所示:
2.3 逻辑回归具体算法
逻辑回归模型是统计学中用于解决分类问题的一种方法,特别是在因变量(目标变量)是二元的情况下。该模型源自线性回归,并通过引入Sigmoid函数来实现将预测值转化为概率。
对于线性回归中, ,这里f(x)的范围为[ − ∞ , + ∞ ],说明通过线性回归中我们可以求得任意的一个值。对于逻辑回归来说就是概率,这个概率取值需要在区间[0,1]内,所以我们将线性回归进行修改:
此时,我们希望概率p的取值仅在区间[0,1]内。通常我们使用Sigmoid函数表示 。我们将线性回归问题转化为:
则
f=1, p>=0.5;f=0, p<0.5
所以,我们现在需要做的就是找到给定样本集的最优的参数w和b。
2.4 损失函数
逻辑回归中使用的损失函数是交叉熵损失函数,它衡量的是真实标签与预测标签之间的差距。交叉熵损失越小,模型的预测越准确。它的公式为:
其中 y 是真实标签,p 是模型预测为正类的概率。在逻辑回归中,对于一个样本集,我们需要将所有的损失函数加起来得到
其中,
为了方便计算,重新定义
则
所以,对于逻辑回归问题,我们就是要找到最优的w和b,使得损失函数J(w)最小,在这里,我们使用梯度下降法来求解。
2.5 梯度下降法
为了最小化损失函数,逻辑回归通常采用梯度下降法来优化模型参数。该方法通过迭代更新参数,使得损失函数逐渐减小,直至收敛到一个局部最小值。
梯度下降算法分为下面几步
- 初始化权重w
- 进行若干轮训练
- 计算预测值
- 使用激活函数将预测值压缩到(0,1)中
- 计算损失值:这里采用了每隔100轮输出一次损失的方法
- 更新权重
- 保存训练结果
2.6 线性回归与逻辑回归的区别
尽管逻辑回归与线性回归在形式上类似,但它们解决的问题类型和输出类型不同。线性回归用于预测连续值,是解决回归问题,而逻辑回归用于预测离散的概率值,是解决分类问题。
三、实验及实验结果分析
3.1 数据集
本次实验的数据集如下:
-0.017612 14.053064 0
-1.395634 4.662541 1
-0.752157 6.538620 0
-1.322371 7.152853 0
0.423363 11.054677 0
0.406704 7.067335 1
0.667394 12.741452 0
-2.460150 6.866805 1
0.569411 9.548755 0
-0.026632 10.427743 0
0.850433 6.920334 1
1.347183 13.175500 0
1.176813 3.167020 1
-1.781871 9.097953 0
-0.566606 5.749003 1
0.931635 1.589505 1
-0.024205 6.151823 1
-0.036453 2.690988 1
-0.196949 0.444165 1
1.014459 5.754399 1
1.985298 3.230619 1
-1.693453 -0.557540 1
-0.576525 11.778922 0
-0.346811 -1.678730 1
-2.124484 2.672471 1
1.217916 9.597015 0
-0.733928 9.098687 0
-3.642001 -1.618087 1
0.315985 3.523953 1
1.416614 9.619232 0
-0.386323 3.989286 1
0.556921 8.294984 1
1.224863 11.587360 0
-1.347803 -2.406051 1
1.196604 4.951851 1
0.275221 9.543647 0
0.470575 9.332488 0
-1.889567 9.542662 0
-1.527893 12.150579 0
-1.185247 11.309318 0
-0.445678 3.297303 1
1.042222 6.105155 1
-0.618787 10.320986 0
1.152083 0.548467 1
0.828534 2.676045 1
-1.237728 10.549033 0
-0.683565 -2.166125 1
0.229456 5.921938 1
-0.959885 11.555336 0
0.492911 10.993324 0
0.184992 8.721488 0
-0.355715 10.325976 0
-0.397822 8.058397 0
0.824839 13.730343 0
1.507278 5.027866 1
0.099671 6.835839 1
-0.344008 10.717485 0
1.785928 7.718645 1
-0.918801 11.560217 0
-0.364009 4.747300 1
-0.841722 4.119083 1
0.490426 1.960539 1
-0.007194 9.075792 0
0.356107 12.447863 0
0.342578 12.281162 0
-0.810823 -1.466018 1
2.530777 6.476801 1
1.296683 11.607559 0
0.475487 12.040035 0
-0.783277 11.009725 0
0.074798 11.023650 0
-1.337472 0.468339 1
-0.102781 13.763651 0
-0.147324 2.874846 1
0.518389 9.887035 0
1.015399 7.571882 0
-1.658086 -0.027255 1
1.319944 2.171228 1
2.056216 5.019981 1
-0.851633 4.375691 1
-1.510047 6.061992 0
-1.076637 -3.181888 1
1.821096 10.283990 0
3.010150 8.401766 1
-1.099458 1.688274 1
-0.834872 -1.733869 1
-0.846637 3.849075 1
1.400102 12.628781 0
1.752842 5.468166 1
0.078557 0.059736 1
0.089392 -0.715300 1
1.825662 12.693808 0
0.197445 9.744638 0
0.126117 0.922311 1
-0.679797 1.220530 1
0.677983 2.556666 1
0.761349 10.693862 0
-2.168791 0.143632 1
1.388610 9.341997 0
0.317029 14.739025 0
前两列是属性列,也是我们需要输入的数据,最后一列是分类label。
3.2 实验代码
# 导入numpy库
from numpy import *
import matplotlib.pyplot as plt
# 定义数据集的文件名
filename = 'D:\ML\data\logistic_text.txt'
# 定义函数用于加载数据集
def loadDataSet():
# 创建空列表用于存储数据和标签
data = []
label = []
# 打开文件
fr = open(filename)
# 逐行读取文件内容
for line in fr.readlines():
# 去除空白符并按空格切分每一行
lineArray = line.strip().split()
# 将数据添加到data列表中,确保第一个元素为1.0(偏置项)
data.append([1.0, float(lineArray[0]), float(lineArray[1])])
# 将标签转换为整数并添加到label列表中
label.append(int(lineArray[2]))
# 返回数据和标签
return data, label
# 定义sigmoid函数,用于逻辑回归模型
def sigmoid(X):
# 计算sigmoid值
return 1.0 / (1 + exp(-X))
# 设置学习率
alpha = 0.001
# 定义函数用于计算梯度
def gradient(weights, data, label):
# 将数据转换为矩阵形式
dataMatrix = mat(data)
# 将标签转换为矩阵形式,并进行转置
classLabels = mat(label).transpose()
# 计算预测值
h = sigmoid(dataMatrix * weights)
# 计算误差
error = (classLabels - h)
# 计算梯度
q = -dataMatrix.transpose() * error
# 返回梯度
return q
# 定义梯度下降算法函数
def gradient_Accent(data, label):
# 获取数据的形状
m, n = shape(data)
# 初始化权重向量
weights = ones((n, 1))
# 初始化梯度
q = gradient(weights, data, label)
# 当梯度的绝对值大于阈值时,继续迭代更新权重
while not all(absolute(q) <= 2e-5):
weights = weights - alpha * q
q = gradient(weights, data, label)
# 返回最终的权重向量
return weights
# 定义函数用于绘制最终分类结果的图形
def plotBestFit(weights):
# 加载数据和标签
dataMat, labelMat = loadDataSet()
# 将数据转换为数组形式
dataArr = array(dataMat)
# 获取数据的数量
n = shape(dataArr)[0]
# 分别存储类别1和类别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)
# 绘制类别1的数据点(红色圆圈)
ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
# 绘制类别0的数据点(绿色圆圈)
ax.scatter(xcord2, ycord2, s=30, c='green')
# 创建一个从-3到3的等差数列,用于绘制决策边界
x = arange(-3.0, 3.0, 0.1)
# 计算对应的y值
y = (-weights[0] - weights[1] * x) / weights[2]
# 在图上绘制决策边界(蓝色线)
ax.plot(x, y)
# 设置x轴和y轴的标签
plt.xlabel('X1')
plt.ylabel('X2')
# 显示图形
plt.show()
# 定义主函数
def main():
# 加载数据和标签
dataMat, labelMat = loadDataSet()
# 使用梯度下降算法训练模型并获取权重向量
weights = gradient_Accent(dataMat, labelMat).getA()
# 调用函数绘制最终分类结果的图形
plotBestFit(weights)
# 如果当前脚本是主程序,则执行main函数
if __name__ == '__main__':
main()
3.3 实验结果及分析
由上图可知,本次实验的实验结果很好,只错分了3个点。
四、总结
综上所述,逻辑回归模型通过引入Sigmoid函数,将线性回归的输出转化为概率值,从而实现对二元分类问题的预测。其算法简单且有效,广泛应用于医学、生物统计学、市场营销等领域。尽管面临一些挑战,如对异常值的敏感性和对数据集的特定要求,但通过适当的数据处理和模型调优,逻辑回归仍然是一个非常有力的工具。在未来,随着机器学习和数据科学的发展,逻辑回归及其变种将继续在解决实际问题中发挥重要作用。