目录
1.简介
1.1 介绍
逻辑回归是一种常用的统计学习方法,用于处理分类问题。尽管其名字中包含“回归”一词,但逻辑回归实际上是一种分类算法。分类任务的目标是引入一个函数,将观测值映射到与之相关联的类或标签。逻辑回归主要解决二分类问题,通常称为正向类和负向类。被解释变量描述了结果是正向情况的概率,如果该概率等于或大于一个用来区分的阈值(通常是0.5),则被预测为正向类,否则被预测为负向类。
1.2 线性回归函数
其中是自变量,是因变量,的值域为(-∞,∞),是常数项,是待求系数,不同的权重反映了自变量对因变量不同的贡献程度。
上述公式转化为向量表达式:
1.3 最小二乘法
最小二乘法是一种用于估计未知参数的方法,它通过最小化数据点与拟合曲线之间的平方和来找到最佳的拟合模型
通过分别对w和b求偏导,最终可以得到:
1.4 sigomd函数
sigomd函数,也称为 Logistic 函数,是一个常用的激活函数,用于将输入映射到一个取值范围在0和1之间的输出。
公式:
图像:
从图中可以看出,当趋于-∞,趋于0,当趋于∞,趋于1,且函数的值阈为(0,1)。原理是当趋于-∞,趋于∞,趋于0,当趋于∞,趋于0,趋于1。同时可以发现当趋于5时,的值已经到0.99附近,越大,越趋于1。
sigmoid函数,会把线性回归的结果映射到【0,1】之间,假设0.5为阈值,默认会把小于0.5的为反例,大于0.5的为正例
1.5 损失函数
为求出好的逻辑回归,引出损失函数 :
- 损失函数是体现“预测值”和“真实值”,相似程度的函数
- 损失函数越小,模型越好
损失函数公式:
其中,代表真实结果,或者表示的是逻辑回归结果(也是预测值),将值带入即可得到。
1.6方法
1.6.1梯度下降
每次迭代遍历数据集时,保存每组训练数据对应的梯度增量。遍历结束后,计算数据集的梯度增量之和,最后调整所有模型参数
- m为训练数据集规模、α为学习率、w为待优化参数、Δw为参数w的梯度增量。
用通俗的话来讲:沿着函数下降的方向找,最后就能找到山谷的最低点,然后更新W值,其实就是就是不断的缩小自身的值,最后找到最低点。
1.6.2梯度上升
梯度上升算法到达每个点后都会重新估计移动方向。我们通过迭代的方法来逼近函数的极大值。
1.6.3 牛顿法
牛顿法就是先对目标函数在某一点泰勒展开。忽略次数较高的项,直接对式子两边求梯度得到梯度向量。使梯度向量为0,就可以求得下一个点的位置。不断进行这个迭代,直到梯度的模趋于于0,或者函数值下降小于指定阈值。
公式:
- 表示在迭代 𝑡+1时的参数向量。
- 表示在迭代 𝑡t 时的参数向量。
- 表示Hessian矩阵的逆矩阵(二阶导数矩阵的逆)。
- 表示关于参数 𝜃的梯度(一阶导数),这里 J 通常表示损失函数
2.实现
2.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)
结果:
特征值:
标签值
2.2 Sigmoid函数
将值映射到0~1,将输出映射到概率值
def sigmoid(inx):
return 1.0 / (1 + np.exp(-inx))# 计算Sigmoid函数的值
2.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
2.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
2.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
2.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
2.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()
2.8分类预测
通过权值和特征向量和阈值来预测类别,1是正例,0是负例
def predict(x,weights,threshold=0.5):
prob = sigmoid(sum(x*weights)) # 计算预测概率
if prob > threshold:
return 1
else:
return 0
(1)梯度下降法预测
weights = graddescent(mat1,mat2)[0]#计算权值
plotBestFit(weights,'graddescent',mat1,mat2)#绘制图像
data= [1.0, 97.0, 15.0]
print(predict(np.mat(data), weights))#输出预测结果
损失的结果:
绘图结果 :
预测结果:
(2)梯度上升法预测
weights2 = gradAscent(mat1,mat2)[0]#计算权值
plotBestFit(weights,'gradAscent',mat1,mat2)#绘制图像
print(predict(np.mat(data), weights))#输出预测结果
损失的结果:
绘图结果:
预测结果:
(3)牛顿法预测
weights3 = Newton_method(mat1,mat2)#计算权值
plotBestFit(weights,'Newton',mat1,mat2)#绘制图像
print(predict(np.mat(data), weights))#输出预测结果
损失结果:
绘图结果:
预测结果
3.总结
在理论中,回顾了逻辑回归的一系列知识,如最小二乘法、线性回归等,对逻辑回归的知识更加熟悉,在实验中,数据的预处理十分的重要,如果没有归一化,那么在计算sigmoid函数,会出现指数溢出,避免这种情况,最重要的是数据处理 。在实现逻辑回归的梯度下降,梯度上升,牛顿法的过程中,更加理解了逻辑回归的原理。逻辑回归算法简单且易于实现,计算代价较小。适用于处理线性可分或近似线性可分的问题。然而也存在着容易欠拟合,分类精度不高。数据特征有缺失或者特征空间很大时表现效果并不好。