用逻辑回归分类-非线性数据篇
前言
逻辑斯蒂回归是一种广泛使用的分类方法,它是基于条件概率密度函数的最大似然估计的。它的主要思想是将输入空间划分为多个子空间,每个子空间对应一个类别。在每个子空间内部,我们假设输入变量的取值与类别标签的概率成正比。
在逻辑斯蒂回归中,我们首先通过数据进行线性回归,得到的结果再通过sigmoid函数转化为概率,这样就可以得到每个类别的概率。然后,我们可以通过设置一个阈值,如果概率大于阈值,我们就认为这个样本属于这个类别,否则就属于其他类别。这就是逻辑斯蒂回归的基本原理。
逻辑斯蒂回归在现实生活中有很多应用,比如垃圾邮件分类、疾病诊断等。它可以处理非线性关系,而且它的预测结果是概率,这对于处理分类问题非常有用。
在深度学习中,逻辑斯蒂回归的作用主要体现在两个方面:一是作为一种基础的分类方法,它可以用于二分类问题,比如判断一个邮件是否为垃圾邮件;二是作为一种特征提取方法,它可以用于提取输入数据的特征,这些特征可以被其他深度学习模型使用。
本文重点总结逻辑斯蒂回归在非线性数据集上的应用方法,对线性数据分类还有疑惑的跳转
逻辑斯蒂回归多分类-线性数据篇
名词解释
回归
很多初学(复习)统计学或者深度学习算法的同学(包括我),对“回归”这个名词可能感觉有点疑惑,因为它既熟悉又陌生,熟悉是因为它在现实生活中也很常见,比如香港回归,澳门回归。。。,陌生的是当它跟统计学名词联系在一起,又会让人有点摸不着头脑,什么线性回归,逻辑斯蒂回归。。。,为此,我专门查找了相关资料,总结如下:
在统计学和深度学习中,“回归”这个术语的含义主要是关于预测一个连续的目标变量。这个目标变量可以是任何可以连续变化的东西,比如销售额、房价、股票价格等。在这种情况下,“回归”的意思是“倒推”或者“预测”。
在统计学中,我们使用回归分析来研究一个或多个自变量(即影响因素)与一个因变量(即我们想要预测的结果)之间的关系。例如,我们可能会使用回归分析来研究房价与房屋面积、位置、年份等因素的关系。在这种情况下,我们的目标是找到一个函数,这个函数可以根据这些因素预测房价。这就是“回归”的含义:我们是在“倒推”或者“预测”房价。
在深度学习中,我们也使用回归模型,但是这里的“回归”更多的是指预测一个连续的目标变量。例如,我们可能会使用深度学习的回归模型来预测一个物品的评分,或者预测一个人的年龄。在这种情况下,我们的目标是找到一个函数,这个函数可以根据一些输入特征预测这个连续的目标变量。这也是“回归”的含义:我们是在“倒推”或者“预测”这个连续的目标变量。
总的来说,无论是在统计学还是在深度学习中,“回归”的含义都是“倒推”或者“预测”一个连续的目标变量。这个目标变量可以是任何可以连续变化的东西,比如销售额、房价、股票价格、评分、年龄等。我们的目标是找到一个函数,这个函数可以根据一些输入特征预测这个连续的目标变量。
使用逻辑斯蒂回归对线性数据和非线性数据进行训练和预测有什么异同
逻辑斯蒂回归是一种广义的线性模型,可以用于二分类问题。它本质上是线性回归模型,但在输出层使用了sigmoid函数,将线性回归的输出映射到(0,1)区间,表示概率。
在处理线性数据时,逻辑斯蒂回归的表现与普通线性回归类似。训练过程主要是通过最小化预测概率与实际标签之间的损失函数来进行的。在预测阶段,给定新的输入数据,模型会输出每个类别的概率。
然而,当处理非线性数据时,逻辑斯蒂回归仍然保持其线性特性。这并不意味着它不能处理非线性问题,而是说它通过引入非线性映射函数(如sigmoid函数)来处理数据内在的非线性关系。这种处理方式允许逻辑斯蒂回归在非线性数据上表现出色,而无需改变其作为线性回归模型的内在机制。
总结来说,逻辑斯蒂回归在处理非线性数据时,其训练和预测过程与处理线性数据时的主要区别在于如何解释和使用模型的输出。在任何情况下,它都保持了其作为线性模型的特性,只是在更高层次上(即通过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))
数据预处理函数
对数据进行标准化和多项式变换,本文将分别比较“不使用多项式变换”、“不同角度的多项式变换”对准确率和拟合、泛化的影响
def prepare_data(data, normalize_data=False, polynomial_transform_degree=-1):
assert isinstance(data, np.ndarray), "Data must be a numpy array"
# 标准化特征矩阵
if normalize_data:
features_mean = np.mean(data, axis=0) #特征的平均值
features_dev = np.std(data, axis=0) #特征的标准偏差
features = (data - features_mean) / features_dev #标准化数据
else:
features_mean = None
features_dev = None
features = data
# 多项式特征变换
if (polynomial_transform_degree != -1):
degree = polynomial_transform_degree
new_features = []
for i in range(degree + 1):
new_features.append(np.power(features, i))
features = np.column_stack(new_features)
data_processed = features
# 返回处理后的数据
return data_processed, features_mean, features_dev
非线性数据模拟生成函数
定义了一个名为moon2Data
的函数,用于生成模拟数据,这些数据类似于月亮的形状
函数名为moon2Data
,它接受两个参数:datanum
和show
。datanum
表示要生成的点的数量,show
是一个布尔值,决定是否显示生成的点。函数的返回类型是np.ndarray
,即NumPy数组。
生成月亮形状的第一部分(代表类0的数据)。
x1 = np.linspace(-3, 3, datanum)
noise = np.random.randn(datanum) * 0.15
y1 = -np.square(x1) / 3 + 4.5 + noise
x1是在-3到3之间的均匀分布的
datanum`个值。然后添加了高斯噪声。对于y1,它是x1的负平方除以3再加4.5后再加上噪声。
这部分代码将x1和y1重新整形为列向量,并添加一个全为0的列,用于代表分类标签(这里使用0表示类0)。
class0 = np.concatenate((x1.reshape(datanum,1), y1.reshape(datanum,1), np.zeros((datanum, 1))), axis=1)
生成月亮形状的第二部分(代表类1的数据)。
x2 = np.linspace(0, 6, datanum)
noise = np.random.randn(datanum) * 0.15
y2 = np.square(x2 - 3) / 3 + 0.5 + noise
x2是在0到6之间的均匀分布的
datanum`个值。然后添加了高斯噪声。对于y2,它是x2减去3后的平方除以3再加0.5后再加上噪声。
与生成类0的数据类似,但是添加了一个全为1的列作为分类标签。
class1 = np.concatenate((x2.reshape(datanum,1), y2.reshape(datanum,1), np.ones((datanum, 1))), axis=1)
将类0和类1的数据合并为一个大的NumPy数组。
ret = np.concatenate((class0, class1), axis=0)
如果show
参数为True,则使用matplotlib显示生成的点。这主要用于可视化目的。
if (show):
plt.clf() # 清除当前图形
plt.axis([-3.5, 6.5, -.5, 5.5]) # 设置轴的范围
plt.scatter(x1, y1, s=10) # 绘制类0的点
plt.scatter(x2, y2, s=10) # 绘制类1的点
plt.draw() # 更新图形显示
plt.pause(.1) # 暂停0.1秒,以便查看图形
plt.show() # 显示图形
最后,函数返回合并后的数据。
return ret
def moon2Data(datanum, show = False) -> np.ndarray:
x1 = np.linspace(-3, 3, datanum)
noise = np.random.randn(datanum) * 0.15
y1 = -np.square(x1) / 3 + 4.5 + noise
class0 = np.concatenate((x1.reshape(datanum,1), y1.reshape(datanum,1), np.zeros((datanum, 1))), axis=1)
x2 = np.linspace(0, 6, datanum)
noise = np.random.randn(datanum) * 0.15
y2 = np.square(x2 - 3) / 3 + 0.5 + noise
class1 = np.concatenate((x2.reshape(datanum,1), y2.reshape(datanum,1), np.ones((datanum, 1))), axis=1)
ret = np.concatenate((class0, class1), axis=0)
if (show):
plt.clf()
plt.axis([-3.5, 6.5, -.5, 5.5])
plt.scatter(x1, y1, s=10)
plt.scatter(x2, y2, s=10)
plt.draw