用逻辑回归分类Iris数据集-线性数据篇
前言
逻辑斯蒂回归是一种广泛使用的分类方法,它是基于条件概率密度函数的最大似然估计的。它的主要思想是将输入空间划分为多个子空间,每个子空间对应一个类别。在每个子空间内部,我们假设输入变量的取值与类别标签的概率成正比。
在逻辑斯蒂回归中,我们首先通过数据进行线性回归,得到的结果再通过sigmoid函数转化为概率,这样就可以得到每个类别的概率。然后,我们可以通过设置一个阈值,如果概率大于阈值,我们就认为这个样本属于这个类别,否则就属于其他类别。这就是逻辑斯蒂回归的基本原理。
逻辑斯蒂回归在现实生活中有很多应用,比如垃圾邮件分类、疾病诊断等。它可以处理非线性关系,而且它的预测结果是概率,这对于处理分类问题非常有用。
在深度学习中,逻辑斯蒂回归的作用主要体现在两个方面:一是作为一种基础的分类方法,它可以用于二分类问题,比如判断一个邮件是否为垃圾邮件;二是作为一种特征提取方法,它可以用于提取输入数据的特征,这些特征可以被其他深度学习模型使用。
本文介绍了逻辑回归算法的其中一种应用场景-对线性的多分类数据集进行分类,后续还将总结逻辑回归在非线性数据集中的应用方法。
本文首先使用基础python和numpy进行基础代码实现,然后引入一个科学计算库
from scipy.optimize import minimize
来优化梯度下降过程,并且比较前后的准确率差异
名词解释
回归
很多初学(复习)统计学或者深度学习算法的同学(包括我),对“回归”这个名词可能感觉有点疑惑,因为它既熟悉又陌生,熟悉是因为它在现实生活中也很常见,比如香港回归,澳门回归。。。,陌生的是当它跟统计学名词联系在一起,又会让人有点摸不着头脑,什么线性回归,逻辑斯蒂回归。。。,为此,我专门查找了相关资料,总结如下:
在统计学和深度学习中,“回归”这个术语的含义主要是关于预测一个连续的目标变量。这个目标变量可以是任何可以连续变化的东西,比如销售额、房价、股票价格等。在这种情况下,“回归”的意思是“倒推”或者“预测”。
在统计学中,我们使用回归分析来研究一个或多个自变量(即影响因素)与一个因变量(即我们想要预测的结果)之间的关系。例如,我们可能会使用回归分析来研究房价与房屋面积、位置、年份等因素的关系。在这种情况下,我们的目标是找到一个函数,这个函数可以根据这些因素预测房价。这就是“回归”的含义:我们是在“倒推”或者“预测”房价。
在深度学习中,我们也使用回归模型,但是这里的“回归”更多的是指预测一个连续的目标变量。例如,我们可能会使用深度学习的回归模型来预测一个物品的评分,或者预测一个人的年龄。在这种情况下,我们的目标是找到一个函数,这个函数可以根据一些输入特征预测这个连续的目标变量。这也是“回归”的含义:我们是在“倒推”或者“预测”这个连续的目标变量。
总的来说,无论是在统计学还是在深度学习中,“回归”的含义都是“倒推”或者“预测”一个连续的目标变量。这个目标变量可以是任何可以连续变化的东西,比如销售额、房价、股票价格、评分、年龄等。我们的目标是找到一个函数,这个函数可以根据一些输入特征预测这个连续的目标变量。
逻辑斯蒂回归和线性回归的异同点
逻辑斯蒂回归和线性回归都是回归分析的一种,但它们的主要区别在于处理的问题类型和输出结果的形式。
相同点:
-
回归分析:逻辑斯蒂回归和线性回归都是回归分析的一种,它们都试图找到一个或多个自变量(即影响因素)与一个因变量(即我们想要预测的结果)之间的关系。
-
预测连续变量:逻辑斯蒂回归和线性回归都是用来预测连续变量的。在逻辑斯蒂回归中,我们通过sigmoid函数将线性回归的结果转化为概率,从而得到每个类别的概率。
不同点:
-
处理问题类型:线性回归主要用于处理连续的目标变量,而逻辑斯蒂回归主要用于处理分类问题。
-
输出结果的形式:线性回归的输出结果是一个连续的值,而逻辑斯蒂回归的输出结果是一个概率值,通常用于二分类问题。
-
处理非线性关系:线性回归只能处理线性关系,而逻辑斯蒂回归可以处理非线性关系。
实现
工具函数
Sigmoid
Sigmoid函数是一种常用的激活函数,它将任意实数映射到0和1之间。Sigmoid函数的定义如下:
σ ( x ) = 1 1 + e − x \sigma(x) = \frac{1}{1 + e^{-x}} σ(x)=1+e−x1
其中, x x x是输入, σ ( x ) \sigma(x) σ(x)是输出。
Sigmoid函数的图像如下(不平滑因为是我自己生成的。。。):
Sigmoid函数的主要特性包括:
-
单调递增:对于所有的 x x x, σ ( x ) \sigma(x) σ(x)都是单调递增的。
-
输出范围在0和1之间:对于所有的 x x x, 0 ≤ σ ( x ) ≤ 1 0 \leq \sigma(x) \leq 1 0≤σ(x)≤1。
-
可微:Sigmoid函数是可微的,这使得它可以用于神经网络的反向传播算法。
def sigmoid(data):
return 1 / (1+np.exp(-data))
逻辑斯蒂回归类
以下代码在名为"LogisticRegression"的类中
初始化
将传入的数据集和标签记录下来以便进一步处理,同时初始化权重矩阵
def __init__(self, data,labels) -> None:
self.data = data
self.labels = labels
self.unique_labels = np.unique(labels) #取标签中的类的名称的集合
self.num_examples = self.data.shape[0] #取数据集中样本的数量
self.num_features = self.data.shape[1] #取数据集中的特征个数
num_unique_labels = self.unique_labels.shape[0] #取标签中类的个数
self.theta = np.zeros((num_unique_labels,self.num_features)) #初始化权重向量,因为我们是多分类,所以权重是 “分类数量 x 特征个数”的矩阵
训练函数
对每个可能的分类执行训练过程,因为逻辑斯蒂回归通常用于处理二分类问题,所以每次都将当前分类的标签置为“1”,其他分类的标签置为“0”
def train(self, lr = 0.01, max_iter = 1000):
cost_histories = [] #记录损失历史记录,以便可视化
for label_index, unique_label in enumerate(self.unique_labels): #对所有可能的分类进行遍历
current_initial_theta = np.copy(self.theta[label_index].reshape(self.num_features, 1)) #复制对应的权重向量,以避免直接修改
current_labels = (self.labels == unique_label).astype(float) #等于当前标签的置为1,否则为0
(current_theta, cost_history) = LogisticRegression.gradient_descent(self.data, current_labels, current_initial_theta, max_iter) #执行梯度下降过程
self.theta[label_index] = current_theta.T #记录当前分类最终的权重向量
cost_histories.append(cost_history) #记录当前分类最终的损失历史记录
return cost_histories, self.theta
梯度下降过程
在规定的迭代次数里执行梯度下降,每次权重向量都减去学习率乘以当前梯度,通过迭代优化模型的参数(也就是权重向量 θ \theta θ),使得模型的预测结果与真实标签之间的差异(也就是损失函数)最小。
gradient_descent
方法的主要任务是执行梯度下降的迭代过程。它接收五个参数:数据集 data
、标签 labels
、当前的初始权重向量 current_initial_theta
、学习率 lr
和最大迭代次数 max_iter
。在每次迭代中,它会调用 gradient_step
方法计算梯度,然后根据梯度更新权重向量。同时,它还会记录每次迭代后的损失值,以便于后续的可视化或者调试。
gradient_step
方法的主要任务是计算梯度。它接收三个参数:数据集 data
、标签 labels
和当前的权重向量 theta
。首先,它会计算预测值 predictions
,然后计算预测值与真实标签之间的差异 label_diff
。最后,它会计算梯度 gradients
,并返回梯度的平均值。
在这里,梯度的计算公式为:
∇ θ J ( θ ) = 1 N ∑ i = 1 N ( h θ ( x ( i ) ) − y ( i ) ) x ( i ) \nabla_\theta J(\theta) = \frac{1}{N} \sum_{i=1}^{N} (h_\theta(x^{(i)}) - y^{(i)})x^{(i)} ∇θJ(θ)=N1i=1∑N(hθ(x(i))−y(i))x(i)
其中, N N N 是数据集的大小, h θ ( x ( i ) ) h_\theta(x^{(i)}) hθ(x(i)) 是预测值, y ( i ) y^{(i)} y(i) 是真实标签, x (