【实验目的】掌握逻辑回归算法
【实验内容】处理样本,使用逻辑回归算法进行参数估计,并画出分类边界
【实验要求】写明实验步骤,必要时补充截图
1、参照"2.1梯度下降法实现线性逻辑回归.ipynb"和"2.2 sklearn实现线性逻辑回归.ipynb",在Jupyter Notebook中新建Python运行环境,以单元格为单位运行代码,在实验报告中解释每行代码的含义,分析运行结果,把运行结果截图保存到实验报告中,并比较两种实现方式的优劣。
2.1:
python
import numpy as np # 导入numpy库,用于数值计算
import matplotlib.pyplot as plt # 导入matplotlib库,用于绘图
# 读取数据
data = np.genfromtxt("C:/Users/a1830/Desktop/实验5-逻辑回归/实验素材/LR-testSet.txt", delimiter=",")
data # 打印读取的数据
# 特征:选择前两列
x_data = data[:,:-1]
# 标签:y
y_data = data[:,-1]
# 定义sigmoid函数 x=θ^T*X
def sigmoid_(x):
return 1/(1+np.exp(-x)) # 返回sigmoid函数值
# 定义损失函数 xMat:x_data矩阵 yMat:y_data矩阵 ws:参数向量的转置
def cost_(xMat,yMat,ws):
# 进行相乘
left = np.multiply(yMat,np.log(sigmoid_(xMat*ws))) # 计算左半部分
right = np.multiply(1-yMat,np.log(1-sigmoid_(xMat*ws))) # 计算右半部分
# 进行求和 除以样本的个数
return np.sum(left+right)/-(len(xMat)) # 返回损失值
# 定义梯度下降求解θ
def gradAscent(xArr,yArr):
# 将ndarry类型转为矩阵
xMat = np.mat(xArr)
yMat = np.mat(yArr)
# 初始化学习率
lr = 0.001
# 初始化迭代次数
epochs = 10000
# 取出 样本个数m 以及 特征个数n
m,n = np.shape(xMat)
# 初始化的θ --> θ^T*xMat θ0*x0+θ1*x1+θ2*x2
ws = np.mat(np.ones((n,1)))
# 初始化损失列表
costList = []
# 迭代
for i in range(epochs+1):
# 求导
# 1.h(x) 100*3 3*1 --> 100*1 -->每个样本都有一个h(x)
h = sigmoid_(xMat*ws)
# print(f"xMat shape:{np.shape(xMat)}")
# print(f"ws shape:{np.shape(ws)}")
# 矩阵乘法:n*m m*1 --> n*1 -->
# xMat:m*n 3*100 m*1 1*100
# h-->预测值 (m*1)
# yMat-->真实值 (m*1)
ws_grad = xMat.T*(h - yMat.T)/m
# print(f"xmat.T shape{np.shape(xMat.T)}")
# print(f"yMat shape{np.shape(h - yMat.T)}")
# print(np.shape(ws_grad))
# 更新ws-->theta向量
ws = ws - lr*ws_grad
if i%50 == 0:
costList.append(cost_(xMat,yMat,ws)) # 每50次迭代记录一次损失值
# 返回theta向量ws,以及损失列表
return ws,costList
# 训练模型
ws,costList = gradAscent(x_data,y_data)
print(ws) # 打印训练得到的权重向量
"""
可视化
- 横轴:x1
- 纵轴:x2
x1*theta1+x2*theta2+theta0=0
x2 = -(x1*theta1+theta0)/theta2
"""
"""
可视化
- y_data为0是一个类别,圆
- y_data为1是一个类型,叉
实现:构建x1,x2
"""
def plot_logi():
# 初始化列表
x_0 = []
y_0 = []
x_1 = []
y_1 = []
# 切分不同类别的数据
for i in range(len(x_data)):
# 取类别为0的数据
if y_data[i] == 0:
# 将特征1添加到x_0中
x_0.append(x_data[i,0])
# 将特征2添加到y_0中
y_0.append(x_data[i,1])
else:
# 将特征1添加到x_1中
x_1.append(x_data[i,0])
# 将特征2添加到y_1中
y_1.append(x_data[i,1])
# 画图
plt.scatter(x_0,y_0,c="skyblue",marker="o",label="class0")
plt.scatter(x_1,y_1,c="red",marker="x",label="class1")
plt.legend()
# 绘制点
plot_logi()
# 初始化测试集的数据
x_test = [[-4],[3]]
# 计算分类函数
y_test = -(x_test*ws[1]+ws[0])/ws[2]
# 可视化
plt.plot(x_test,y_test)
plt.show()
# 绘制loss曲线
# 生成0,10000
x = np.linspace(0,10000,201)
plt.plot(x,costList)
plt.xlabel("epochs")
plt.ylabel("Cost")
plt.show()
plot_logi()
plt.show()
# 特征:选择前两列
x_data = data[:,:-1]
# 标签:y
y_data = data[:,-1]
# θ^T*X 给X添加一列全为1的数据
X_data = np.concatenate((np.ones((len(x_data),1)),x_data),axis=1)
# 定义sigmoid函数,输入为x=θ^T*X
def sigmoid_(x):
return 1/(1+np.exp(-x))
# 定义损失函数,输入为xMat:x_data矩阵, yMat:y_data矩阵, ws:参数向量的转置
def cost_(xMat,yMat,ws):
# 进行相乘
left = np.multiply(yMat,np.log(sigmoid_(xMat*ws)))
right = np.multiply(1-yMat,np.log(1-sigmoid_(xMat*ws)))
# 进行求和并除以样本的个数
return np.sum(left+right)/-(len(xMat))
# 定义梯度下降求解θ
def gradAscent(xArr,yArr):
# 将ndarry类型转为矩阵
xMat = np.mat(xArr)
yMat = np.mat(yArr)
# 初始化学习率
lr = 0.001
# 初始化迭代次数
epochs = 10000
# 取出样本个数m以及特征个数n
m,n = np.shape(xMat)
# 初始化的θ --> θ^T*xMat θ0*x0+θ1*x1+θ2*x2
ws = np.mat(np.ones((n,1)))
# 初始化损失列表
costList = []
# 迭代
for i in range(epochs+1):
# 求导
# 1.h(x) 100*3 3*1 --> 100*1 -->每个样本都有一个h(x)
h = sigmoid_(xMat*ws)
# 矩阵乘法:n*m m*1 --> n*1 -->
# xMat:m*n 3*100 m*1 1*100
# h-->预测值 (m*1)
# yMat-->真实值 (m*1)
ws_grad = xMat.T*(h - yMat.T)/m
# 更新ws-->theta向量
ws = ws - lr*ws_grad
if i%50 == 0:
costList.append(cost_(xMat,yMat,ws))
# 返回theta向量ws,以及损失列表
return ws,costList
# 训练模型
ws,costList = gradAscent(X_data, y_data)
print(ws)
"""
可视化部分
- 横轴:x1
- 纵轴:x2
x1*theta1+x2*theta2+theta0=0
x2 = -(x1*theta1+theta0)/theta2
"""
# 绘制点
plot_logi()
# 初始化测试集的数据
x_test = [[-4],[3]]
# 计算分类函数
y_test = -(x_test*ws[1]+ws[0])/ws[2]
# 可视化
plt.plot(x_test,y_test)
plt.show()
# 绘制loss曲线
# 生成0,10000
x = np.linspace(0,10000,201)
plt.plot(x,costList)
plt.xlabel("epochs")
plt.ylabel("Cost")
plt.show()
运行结果




2.2:
python
import numpy as np # 导入numpy库,用于数值计算
import matplotlib.pyplot as plt # 导入matplotlib库中的pyplot模块,用于绘图
# 读取数据
data = np.genfromtxt("C:/Users/a1830/Desktop/人工智能 实验5-逻辑回归/实验素材/LR-testSet.txt", delimiter=",") # 从指定路径读取数据文件,使用逗号作为分隔符
data # 打印读取的数据
# 特征:选择前两列
x_data = data[:,:-1] # 提取数据的前两列作为特征
# 标签:y
y_data = data[:,-1] # 提取数据的最后一列作为标签
def plot_logi():
# 初始化列表
x_0 = [] # 存储类别为0的特征1
y_0 = [] # 存储类别为0的特征2
x_1 = [] # 存储类别为1的特征1
y_1 = [] # 存储类别为1的特征2
# 切分不同类别的数据
for i in range(len(x_data)): # 遍历所有数据点
# 取类别为0的数据
if y_data[i] == 0: # 如果当前数据点的标签为0
# 将特征1添加到x_0中
x_0.append(x_data[i,0]) # 添加特征1到x_0列表
# 将特征2添加到y_0中
y_0.append(x_data[i,1]) # 添加特征2到y_0列表
else: # 如果当前数据点的标签不为0(即为1)
# 将特征1添加到x_1中
x_1.append(x_data[i,0]) # 添加特征1到x_1列表
# 将特征2添加到y_1中
y_1.append(x_data[i,1]) # 添加特征2到y_1列表
# 画图
plt.scatter(x_0,y_0,c="skyblue",marker="o",label="class0") # 绘制类别为0的散点图,颜色为天蓝色,标记为圆圈
plt.scatter(x_1,y_1,c="red",marker="x",label="class1") # 绘制类别为1的散点图,颜色为红色,标记为叉号
plt.legend() # 显示图例
plot_logi() # 调用函数绘制初始散点图
# 训练模型
from sklearn.linear_model import LogisticRegression # 导入LogisticRegression类
logistic = LogisticRegression() # 创建LogisticRegression对象
logistic.fit(x_data,y_data) # 使用数据拟合模型
# 截距
print(logistic.intercept_) # 打印模型的截距项
# theta1 theta2
print(logistic.coef_) # 打印模型的系数(权重)
# x2 = -(x1*theta1+theta0)/theta2
# 画出散点
plot_logi() # 再次调用函数绘制散点图
# 画出决策边界
x_test = np.array([[-4],[3]]) # 定义测试数据,用于绘制决策边界
y_test = -(x_test*logistic.coef_[0,0]+logistic.intercept_)/logistic.coef_[0,1] # 根据模型参数计算决策边界的y值
plt.plot(x_test,y_test) # 绘制决策边界
plt.show() # 显示图形
print(logistic.score(x_data,y_data)) # 打印模型在训练数据上的准确率
运行结果



梯度下降法实现线性逻辑回归
优势:
- 完全控制:你可以完全控制优化过程,包括学习率、批量大小、正则化方法等。
- 灵活性:可以自定义损失函数和正则化项,适用于各种复杂的模型。
- 适用性广:不仅限于逻辑回归,还可以应用于其他类型的机器学习模型。
- 性能优化:可以根据具体需求进行优化,例如使用动量法、AdaGrad、RMSProp等高级优化算法。
- 并行计算:可以更容易地实现多线程或GPU加速,提高训练速度。
劣势:
- 实现复杂:需要编写更多的代码来实现梯度下降法,包括前向传播、损失计算、梯度计算和参数更新。
- 调试困难:由于涉及多个步骤和超参数,调试和优化可能更加困难。
- 易出错:手动实现容易引入错误,特别是在处理大规模数据时。
- 开发时间:相比sklearn,手动实现可能需要更多的开发时间。
sklearn实现线性逻辑回归
- 优势:
- 易用性:提供简洁的API,易于使用和集成。
- 功能丰富:除了基本的逻辑回归,还支持多种正则化方法、多分类问题等。
- 性能优化:sklearn中的实现经过了优化,通常比手动实现更高效。
- 社区支持:有大量的文档和社区资源,便于解决问题和学习。
- 扩展性:可以与其他机器学习算法或深度学习框架结合使用。
- 劣势:
- 灵活性不足:只支持标准的交叉熵损失和L2正则化(岭回归),无法自定义损失函数或正则化方法。
- 优化算法的选择有限:默认使用liblinear或lbfgs等优化算法,这些算法可能不适合所有问题。
- 内存消耗:在处理非常大的数据集时,可能会遇到内存限制。
- 并行计算:不支持多线程或GPU加速,这在处理大型数据集时可能会成为瓶颈。
- 解释性差:提供的模型接口相对简单,缺乏对模型内部机制的深入解释和可视化工具。
梯度下降法实现线性逻辑回归适合需要高度定制化和控制的场景,但实现复杂且调试困难。
sklearn实现线性逻辑回归适合快速原型设计和生产环境,易于使用和集成,但在灵活性和控制力方面有所欠缺。
2、读取ex2data1.txt中的数据,建立样本集,使用逻辑回归算法得到参数估计值。并在坐标图中画出分界图。
提示:参考"成绩分类版本1.ipynb"
估计值为0.89







结合自己的知识背景及兴趣,选做以下题目:
3、读取"简单分类数据.txt"中的数据,建立样本集,使用逻辑回归算法得到参数值,并在坐标图中画出分界线
4、逻辑回归算法可以看成是只有一个神经元的神经网络,打开"链式逻辑回归.ipynb"文档,参考第四章简单逻辑回归ppt32-34页将其填充完整。读取"链式逻辑回归.txt"中的数据,建立样本集,使用神经网络式逻辑回归算法得到参数估计值。并在坐标图中画出分界图




5、打开"链式逻辑回归分类猫.ipynb"文档,参考第一题中的算法生成可以分类图片的模型,用测试集获得正确率,然后用任意图片测试模型是否能正确判断是否有猫






判断结果:


