一、概述
逻辑回归是一种基于概率的分类算法,它通过将特征与类别之间的关系建模,从而对新的样本进行分类预测。虽然它的名字中带有“回归”,但实际上它是一种分类算法。
二、原理
逻辑回归是一种二分类算法,它的原理基于线性模型和概率论。其基本原理如下:
2.1 线性模型的使用
逻辑回归使用线性模型来对输入特征进行加权和求和,得到一个线性函数。这个线性函数的输出并不直接给出分类结果,而是作为逻辑回归模型的输入。
线性回归函数:
其中𝑥𝑖是自变量,𝑓(𝑥)是因变量,𝑓(𝑥)的值域为(-∞,∞),𝑏是常数项,是待求系数,不同的权重反映了自变量对因变量不同的贡献程度。
上述公式转化为向量表达式:
2.2 最小二乘法与参数求解
最小二乘法是一种常用的线性回归参数求解方法。它的核心思想是通过最小化预测值与真实值之间的误差平方和,来得到最优的回归系数。
通过分别对w和b求偏导,最终可以得到:
2.3 Sigmoid函数的转换
为了将线性函数的输出映射到0和1之间的概率值,逻辑回归使用了Sigmoid函数。Sigmoid函数能够将任意实数映射到(0, 1)区间,其表达式为f(x) = 1 / (1 + e^(-x))。这个概率值表示了样本属于正类的概率。
公式:
从图中可以看出,当x 趋于-∞,𝑦 趋于0,当x趋于∞,𝑦 趋于1,且函数的值阈为(0,1)。
2.4 方法
2.4 .1 梯度上升法
梯度上升法是一种优化算法,用于最大化一个函数的取值。它的基本思想是通过迭代的方式,不断调整参数以使得目标函数值增加最快。
梯度上升法的核心就是利用目标函数的梯度(或者导数)来指导参数的更新过程。梯度上升法的更新规则可以表示为:
其中, 表示待优化的参数,是学习率,用于控制参数更新的步长,表示目标函数 ( f ) 关于参数 的梯度。
梯度上升法的具体步骤如下:
- 初始化参数:设置初始的参数值 。
- 计算目标函数的梯度:计算目标函数关于参数的梯度 。
- 更新参数:按照上面的更新规则,通过将参数沿着梯度方向更新一小步。
- 重复步骤2和3:重复进行梯度计算和参数更新,直至达到停止条件(比如达到最大迭代次数、梯度接近于0等)。
梯度上升法通常用于求解凸优化问题中的最大化问题,并且应用广泛,如在机器学习中的逻辑回归、支持向量机等算法中。需要注意的是,梯度上升法对于目标函数必须是凸函数,以便能够找到全局最优解。
2.4.2 梯度下降法
梯度下降法是一种常用的优化算法,用于最小化一个函数,通常是一种凸函数在机器学习中,梯度下降法被广泛应用于训练模型,如线性回归、逻辑回归和神经网络等。
梯度下降法的基本思想是通过迭代的方式不断调整模型参数,使目标函数的值逐渐减小,直到达到最小值或者收敛。梯度下降法的更新规则可以表示为:
其中, 表示待优化的参数,是目标函数 关于参数 \theta 的梯度, 是学习率,用来控制每次迭代更新的步长。
梯度下降法有不同的变种,包括批量梯度下降(Batch Gradient Descent)、随机梯度下降(Stochastic Gradient Descent)和小批量梯度下降(Mini-batch Gradient Descent)。它在计算梯度的方式、更新参数的频率等方面有所不同。
梯度下降法的优点是简单易理解、易实现,并且在大部分情况下能够有效找到局部最小值。然而,需要注意的是,梯度下降法可能陷入局部最小值、学习率的选取会影响性能、计算代价较大等问题。因此,在实际应用中,梯度下降法的变和改进方法也得到了广泛的研究和应用。
2.4.3 牛顿法
牛顿法是一种用于优化凸函数的迭代算法。在逻辑回归中,牛法可以用于最大化似然函数,从而求解模型参数。
牛顿法通过利用目标函数的二阶导数信息来逼近目标函数的局部极小值点。在逻辑回归中,牛顿法用于求解最大化似然函数时,它的更新规则可以表示为:
其中,表示待优化的参数,是似然函数关于参数 的梯度,H 是似然函数 关于参数 的黑塞矩阵。
牛顿法相比梯度上升法有更快的收敛速度,因为它利用了二阶导数信息。然而,牛顿法也有一些问题,例如计算黑塞矩阵的逆矩阵可能非常昂贵,特别是在高维问题中。
总之,牛顿法作为一种优化算法,在逻辑回归中被广泛应用,它能够高效地找到似然函数的最大值,从而得到逻辑回归模型的最佳参数。
三、代码实现
3.1加载数据集,并数据归一化
函数 loadDataSet 用于从文件中加载数据集,并将其转换为特征值列表和标签。函数 normalizedata 则是用于对数据进行归一化处理
# -*- coding:utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
def loadDataSet():
dataMat = [] # 存储特征值
labelMat = [] # 用于标签
txt = open("C:\\Users\\lenovo\\Desktop\\t.txt")
for line in txt.readlines(): # 逐行读取数据文件
lineArr = line.strip().split() # 将每行数据按空格分割并去除首尾空格
# 将二维特征扩展到三维
dataMat.append([1.0, float(lineArr[0]), float(lineArr[2])])
labelMat.append(int(lineArr[3])) # 将标签值加入到labelMat列表中
return dataMat, labelMat # 返回特征值列表和标签
mat1,mat2=loadDataSet()
def normalizedata(data):
data = np.array(data)
new_data=data[:,1:]
# 计算每列的最大最小值
min_vals = new_data.min(0)
max_vals = new_data.max(0)
ranges = max_vals - min_vals
# 归一化数据
normalized_data = (new_data - min_vals) / ranges
normalized_data = np.insert(normalized_data, 0, 1, axis=1)
return normalized_data
mat1 = normalizedata(mat1)
print(mat1)
print(mat2)
3.2 Sigmoid函数
将值映射到0~1,将输出映射到概率值
def sigmoid(inx):
return 1.0 / (1 + np.exp(-inx))# 计算Sigmoid函数的值
3.3 损失函数
计算逻辑回归模型的损失值
def error_rate(h, label):
label = label.reshape(-1, 1) # 更改标签维度为n*1
m = np.shape(h)[0] # 预测值的个数
sum_err = 0.0 # 初始化错误率
for i in range(m): # m个预测值迭代
if h[i, 0] > 0 and (1 - h[i, 0]) > 0: # 预测值切片
sum_err -= (label[i, 0] * np.log(h[i, 0]) + (1 - label[i, 0]) * np.log(1 - h[i, 0])) # 损失函数公式计算
else:
sum_err -= 0
return sum_err / m
3.4梯度下降
运用梯度下降法计算权重
#梯度下降
def graddescent(datamat, classlabels):
datamatrix = np.mat(datamat)
labelmat = np.mat(classlabels).transpose()
m, n = np.shape(datamatrix)
alpha = 0.001# 学习率
max = 5000 # 最大迭代次数
weights = np.ones((n, 1))# 初始化为全1
for k in range(max):
h = sigmoid(datamatrix * weights) # 计算预测值
error = h- labelmat# 计算误差
loss = error_rate(h, labelmat)#计算损失率
if k % 100 == 0: # 没迭代一百次进行一次
print('\t--------迭代次数 = ' + str(k) + ',训练错误率 = ' + str(loss))
weights = weights - alpha * datamatrix.transpose() * error # 更新权重
return weights.getA(),weights
3.5梯度上升
运用梯度上升法计算权重
#梯度上升
def gradAscent(datamat, classlabels):
datamatrix = np.mat(datamat)
labelmat = np.mat(classlabels).transpose()
m, n = np.shape(datamatrix)
alpha = 0.001# 学习率
max = 5000# 最大迭代次数
weights = np.ones((n, 1))
loss_array = []
for k in range(max):
h = sigmoid(datamatrix * weights)# 计算预测值
error = (labelmat - h)# 计算误差
loss = error_rate(h, labelmat)#计算损失率
if k % 100 == 0: # 没迭代一百次进行一次
print('\t--------迭代次数 = ' + str(k) + ',训练错误率 = ' + str(loss))
weights = weights + alpha * datamatrix.transpose() * error # 更新权重
return weights.getA(),weights
3.6牛顿法
运用牛顿法计算权重
def Newton_method(datamat, classlabels):
datamatrix = np.mat(datamat)
labelmat = np.mat(classlabels).transpose()
m, n = np.shape(datamatrix)
max = 100 # 最大迭代次数
weights = np.ones((n, 1))#权值
for i in range(max):
H = sigmoid(datamatrix*weights)
J = np.dot(datamatrix.transpose(),(H - labelmat)) # 计算梯度
#Hessian = np.dot(data_matrix.T, np.dot(np.diag(H * (1.0 - H)), data_matrix)) / m
Hessian = np.dot(H.transpose(), datamatrix).dot(datamatrix.transpose()).dot((1.0 - H)) / m # 计算Hessian矩阵
try:
Hessian = np.mat(Hessian).I.tolist() # 对Hessian矩阵进行逆运算
except:
continue
loss = error_rate(H, labelmat) # 计算损失率
if i % 10 == 0: # 没迭代次进行一次
print('\t--------迭代次数 = ' + str(i) + ',训练错误率 = ' + str(loss))
weights -= np.dot(J, Hessian) # 更新权重
return weights
3.7绘制图像
绘制逻辑回归的最佳拟合直线
def plotBestFit( weights,title,dataMat, labelMat):
dataArr = np.array(dataMat)
n = np.shape(dataArr)[0]
x1 = []
y1 = []
x2 = []
y2 = []
# 将数据集按类别进行划分
for i in range(n):
if int(labelMat[i])== 1:
x1.append(dataArr[i,1])
y1.append(dataArr[i,2])
else:
x2.append(dataArr[i,1])
y2.append(dataArr[i,2])
fig = plt.figure()
ax = fig.add_subplot(111)
plt.title(title)
ax.scatter(x1, y1, s=30, c='red', marker='s') # 绘制类别1的数据点
ax.scatter(x2, y2, s=30, c='green')# 绘制类别2的数据点
x = np.arange(0, 9, 0.1)
y = (-weights[0]-weights[1]*x)/weights[2] # 根据权重参数计算决策边界
ax.plot(x, y)
plt.xlim(0, 1) # 设置x轴显示范围
plt.ylim(0, 1) # 设置y轴显示范围
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
3.8分类预测
通过权值和特征向量和阈值来预测类别,1是正例,0是负例
def predict(x,weights,threshold=0.5):
prob = sigmoid(sum(x*weights)) # 计算预测概率
if prob > threshold:
return 1
else:
return 0
3.8.1 梯度下降法预测
weights = graddescent(mat1,mat2)[0]#计算权值
plotBestFit(weights,'graddescent',mat1,mat2)#绘制图像
data= [1.0, 97.0, 15.0]
print(predict(np.mat(data), weights))#输出预测结果
3.8.2 梯度上升法预测
weights2 = gradAscent(mat1,mat2)[0]#计算权值
plotBestFit(weights,'gradAscent',mat1,mat2)#绘制图像
print(predict(np.mat(data), weights))#输出预测结果
3.8.3 牛顿法预测
weights3 = Newton_method(mat1,mat2)#计算权值
plotBestFit(weights,'Newton',mat1,mat2)#绘制图像
print(predict(np.mat(data), weights))#输出预测结果
四、总结:
- 逻辑回归使用Sigmoid函数将输入的线性组合映射到 [0, 1] 区间,输出概率值表征样本属于某类的可能性。
- 逻辑回归模型的参数可通过最大似然估计或梯度下降等方法进行优化。
- 常用于解决二分类问题,也可扩展至多分类问题。
4.1 优点:
- 实现简单,计算代价低,适用于大规模数据集。
- 输出结果具有概率解释性,可以直观地理解样本分类的可能性。
- 逻辑回归模型不会被离群值影响,对数据的干净和准确性要求较低。
- 在特征维度较高,与其他特征相关性不强时表现良好。
4.2 缺点:
- 仅能解决线性可分问题,对于复杂非线性问题表现一般。
- 对特征间的相关性敏感,容易受到共线性影响。
- 无法处理多分类问题(需要通过One-vs-Rest或One-vs-One等方法进行扩展)。
- 容易受到噪声数据和异常值的干扰,模型容易出现欠拟合或过拟合问题。
综上所述,逻辑回归是一种简单而高效的分类方法,适用于许多应用场景,但也有其应用限制,特别是当面对复杂非线性问题时,可能需要考虑其他更复杂的模型。