目录
[3. API 介绍](#3. API 介绍)
本章节我们来学习线性分类问题,在有监督学习中,最主要的两种学习任务是 回归(regression) 和 分类(classification),而其中线性回归 和线性分类最为常见。线性回归是预测某一个具体的值,而线性分类是数据所属类别进行预测。这里,我们主要关注线性分类问题。
一般来说,几乎 80% 机器学习任务可以看作是某种分类问题。分类,即给定一个输入的集合,分类器致力于预测每一个类别的概率。类别标记(也被称为应变量或依赖变量)是一个离散的值,表示某个类别。
-
如果数据中的 Label 只有两个类别,那么就属于二分类问题,相应的分类器被称为二分类器。
-
多分类器解决 Label 种类多于两种类别的分类问题。
譬如,预测顾客是否会进行二次购买便是一个典型的二分类问题。而识别图片中出现动物则是属于多分类问题,因为实际情况中动物有很多种。
1.算法介绍
对于二分类问题,这里就不得不介绍逻辑回归算法 (Logistic Regression)。它虽然叫回归,却是一个强力的分类算法。其基本思路还是回归的那一套,换句话说,逻辑回归是用与回归类似的思路解决了分类问题。
那么什么是逻辑回归呢?
逻辑回归在某些书中也被称为对数几率回归 ,常用于二分类问题,因其简单、可并行化、可解释性强,深受工业界喜爱。Logistic 回归的本质其实是:假设数据服从这个分布,然后使用极大似然估计做参数的估计。
2.算法原理
线性分类器,是一种假设特征与分类结果存在线性关系的模型。这个模型通过累加计算每个维度的特征与各自权重的乘积来帮助类别决策。
假设我们输入数据的特征定义为 来代表n维特征列向量,用 来代表对应的权重,或者叫做系数,同时为了避免其过坐标原点这种硬性假设,增加一个截距 b。由此这种线性关系可以表示为:
我们要处理最简单的二分类问题,就需要把一个函数值映射到(0,1)之间,所以我们就希望有一个函数能帮我们完成这个转化,于是便找到了逻辑函数 Sigmoid(max重要) 来替代。
对式子变形得到:
设 y 视为 x 为正例的概率,则 1-y 为 x 为其反例的概率,两者的比值称为几率(odds) ,指该事件发生于不发生的概览比值,若时间发生的概览为 P,则:
也就是说,输出 Y=1 的对数几率是由输入 x 的线性函数 表示的模型,这就是逻辑回归模型。
当的值越接近正无穷,P(Y=1∣x) 概览值也就越接近1。因此逻辑回归的思路是,先拟合决策边界(不局限于线性,还可以是多项式),再建立这个边界与分类的概率联系,从而得到了二分类情况下的概率。
之后我们选择一个阈值,当我们选阈值为0.5, 可以把0到0.49之间的值分到0类,从0.5到1之间的值分到1类。但是在实际工作中并不一定是0.5,阈值的设定往往是根据实际情况来判断的。本小节我们只举例让大家理解为什么不完全是0.5,并不会有一个万能的答案,都是根据实际工作情况来定的。
现在我们知道了逻辑回归的派别函数,接下来要做的就是求解逻辑回归,找出全都预测正确大的概率最大的 w。
在统计学中,常常使用极大似然估计来求解,即找到一组参数,使得在这组参数下,我们的数据的似然度(概率)最大。
设:
似然函数为:
为了更方便求解,我们对函数两边同时取对数,写成对数似然函数,结果为:
如果取整个数据集上的平均对数似然损失 ,我们就得到损失函数:
即在逻辑回归模型中,我们最大化似然函数 和最小化损失函数实际上是等价的。
至于求解的过程,我们还是使用梯度下降的方式。
注:什么是梯度下降我们将在后面的章节介绍,这里知道就行。
平均对数似然损失(Mean Log-Likelihood Loss),在统计学和机器学习中,是一种衡量模型预测概率分布与实际观测数据之间差异的指标。这种损失函数常用于分类问题,尤其是当类别是多项分布的时候。
对于给定的数据集,平均对数似然损失可以定义为:
L = -1/n * Σ [y_i * log(p(y_i))]
其中:
- L 是平均对数似然损失。
- n 是数据集中的样本数量。
- y_i 是真实标签,对于分类问题,它通常是一个one-hot编码的向量,即真实类别对应的索引位置为1,其余为0。
- p(y_i) 是模型预测的概率分布中,真实类别y_i的概率。
- Σ 表示对所有样本求和。
这个损失函数的含义是,对于每个样本,我们取模型预测该样本真实类别标签的概率的对数,然后取负值(因为我们要最小化损失),最后对所有样本的损失求平均。
3. API 介绍
sklearn 逻辑回归函数:
1sklearn.linear_model.LogisticRegression(penalty='l2', C=1.0)
- penalty: {'l1', 'l2', 'elasticnet', 'none'}, 默认为 l2 正则化。
- coef_: 回归系数。
更加详细的 API 描述可以查阅官方文档 逻辑回归
算法优点:
(1)训练速度较快,分类的时候,计算量仅仅只和特征的数目相关;
(2)简单易理解,模型的可解释性非常好,从特征的权重可以看到不同的特征对最后结果的影响;
(3)适合二分类问题,不需要缩放输入特征;
(4)内存资源占用小,因为只需要存储各个维度的特征值;
算法缺点:
(1)不能用 Logistic 回归去解决非线性问题,因为 Logistic 的决策面试线性的;
(2)对多重共线性数据较为敏感;
(3)很难处理数据不平衡的问题;
(4)准确率并不是很高,因为形式非常的简单(非常类似线性模型),很难去拟合数据的真实分布;
(5)逻辑回归本身无法筛选特征,有时会用 gbdt 来筛选特征,然后再上逻辑回归
4.代码示例
数据集:testSet.txt
cpp
-0.017612 14.053064 0
-1.395634 4.662541 1
-0.752157 6.538620 0
-1.322371 7.152853 0
0.423363 11.054677 0
0.406704 7.067335 1
0.667394 12.741452 0
-2.460150 6.866805 1
0.569411 9.548755 0
-0.026632 10.427743 0
0.850433 6.920334 1
1.347183 13.175500 0
1.176813 3.167020 1
-1.781871 9.097953 0
-0.566606 5.749003 1
0.931635 1.589505 1
-0.024205 6.151823 1
-0.036453 2.690988 1
-0.196949 0.444165 1
1.014459 5.754399 1
1.985298 3.230619 1
-1.693453 -0.557540 1
-0.576525 11.778922 0
-0.346811 -1.678730 1
-2.124484 2.672471 1
1.217916 9.597015 0
-0.733928 9.098687 0
-3.642001 -1.618087 1
0.315985 3.523953 1
1.416614 9.619232 0
-0.386323 3.989286 1
0.556921 8.294984 1
1.224863 11.587360 0
-1.347803 -2.406051 1
1.196604 4.951851 1
0.275221 9.543647 0
0.470575 9.332488 0
-1.889567 9.542662 0
-1.527893 12.150579 0
-1.185247 11.309318 0
-0.445678 3.297303 1
1.042222 6.105155 1
-0.618787 10.320986 0
1.152083 0.548467 1
0.828534 2.676045 1
-1.237728 10.549033 0
-0.683565 -2.166125 1
0.229456 5.921938 1
-0.959885 11.555336 0
0.492911 10.993324 0
0.184992 8.721488 0
-0.355715 10.325976 0
-0.397822 8.058397 0
0.824839 13.730343 0
1.507278 5.027866 1
0.099671 6.835839 1
-0.344008 10.717485 0
1.785928 7.718645 1
-0.918801 11.560217 0
-0.364009 4.747300 1
-0.841722 4.119083 1
0.490426 1.960539 1
-0.007194 9.075792 0
0.356107 12.447863 0
0.342578 12.281162 0
-0.810823 -1.466018 1
2.530777 6.476801 1
1.296683 11.607559 0
0.475487 12.040035 0
-0.783277 11.009725 0
0.074798 11.023650 0
-1.337472 0.468339 1
-0.102781 13.763651 0
-0.147324 2.874846 1
0.518389 9.887035 0
1.015399 7.571882 0
-1.658086 -0.027255 1
1.319944 2.171228 1
2.056216 5.019981 1
-0.851633 4.375691 1
-1.510047 6.061992 0
-1.076637 -3.181888 1
1.821096 10.283990 0
3.010150 8.401766 1
-1.099458 1.688274 1
-0.834872 -1.733869 1
-0.846637 3.849075 1
1.400102 12.628781 0
1.752842 5.468166 1
0.078557 0.059736 1
0.089392 -0.715300 1
1.825662 12.693808 0
0.197445 9.744638 0
0.126117 0.922311 1
-0.679797 1.220530 1
0.677983 2.556666 1
0.761349 10.693862 0
-2.168791 0.143632 1
1.388610 9.341997 0
0.317029 14.739025 0
代码:
python
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可:
# Also add the following code, so that every time the environment (kernel) starts, just run the following code:
import sys
import numpy as np
#当你调用matplotlib.pyplot的绘图函数plot()进行绘图的时候,或者生成一个figure画布的时候,可以直接在你的python console里面生成图像。
import matplotlib as mpl
import matplotlib.pyplot as plt
# Logistic 回归梯度上升优化算法
def load_data_set():
# 创建两个列表
data_mat = []
label_mat = []
fr = open('C:\\pythonProject\\机器学习\\分类算法\\逻辑回归\\testSet.txt')
for line in fr.readlines():
# 对当前行去除首尾空格,并按空格进行分离
line_arr = line.strip().split()
data_mat.append([1.0, float(line_arr[0]), float(line_arr[1])])
label_mat.append(int(line_arr[2]))
return data_mat, label_mat
def sigmoid(inx):
return 1.0 / (1 + np.exp(-inx))
# return 0.5 * (1 + np.tanh(0.5 * inx))
# sigmoid函数
def grad_ascent(data_mat_in, class_labels):
# 将输入的数据转换为NumPy矩阵
data_matrix = np.mat(data_mat_in)
# 将类别标签转换为NumPy矩阵,并进行转置,使其成为列向量
label_mat = np.mat(class_labels).transpose()
# 获取数据矩阵的行数和列数
m, n = np.shape(data_matrix)#100 3
# 设置学习率
alpha = 0.001
# 设置最大迭代次数
max_cycles = 500
# 初始化权重为n行1列的矩阵,元素全部为1
weights = np.ones((n, 1))
#[1,1,1]
# 进行最大迭代次数的循环
for k in range(max_cycles):
# 计算当前权重下的预测值,使用sigmoid函数
h = sigmoid(data_matrix * weights)
# 计算预测值与实际值之间的误差
error = (label_mat - h)
# 更新权重:权重+学习率*数据矩阵的转置*误差
weights = weights + alpha * data_matrix.transpose() * error
# 返回训练好的权重
return weights
# 画出数据集和Logistic回归最佳拟合直线的函数
def plot_best_fit(weights):
# 导入matplotlib.pyplot模块用于绘图
import matplotlib.pyplot as plt
# 加载数据集,这里假设存在一个名为load_data_set的函数,它返回数据矩阵和标签矩阵
data_mat, label_mat = load_data_set()
# 将数据矩阵转换为NumPy数组
data_arr = np.array(data_mat)
# 获取数据点的数量
n = np.shape(data_arr)[0]
# 初始化两个列表,分别用于存储正类和负类的x坐标和y坐标
xcord1 = []
ycord1 = []
xcord2 = []
ycord2 = []
# 遍历所有数据点,将它们分类到正类或负类
for i in range(n):
if int(label_mat[i]) == 1:
# 如果标签为1,则将数据点的x和y坐标分别添加到正类的列表中
xcord1.append(data_arr[i, 1])
ycord1.append(data_arr[i, 2])
else:
# 如果标签不为1,则将数据点的x和y坐标分别添加到负类的列表中
xcord2.append(data_arr[i, 1])
ycord2.append(data_arr[i, 2])
# 创建一个新图形
fig = plt.figure()
# 在图形中添加一个子图
ax = fig.add_subplot(111)
# 在子图中绘制正类数据点的散点图,使用红色方块标记
ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
# 在子图中绘制负类数据点的散点图,使用绿色标记
ax.scatter(xcord2, ycord2, s=30, c='green')
# 创建一个x值的范围,用于绘制最佳拟合直线
x = np.arange(-3.0, 3.0, 0.1)
# 根据权重计算对应的y值,这里假设weights是一个包含三个元素的数组或列表,分别对应逻辑回归模型的常数项、x1的系数和x2的系数
y = (-weights[0] - weights[1] * x) / weights[2]
# 在子图中绘制最佳拟合直线
ax.plot(x, y)
# 设置x轴标签
plt.xlabel('X1')
# 设置y轴标签
plt.ylabel('X2')
# 显示图形
plt.show()
dataMat, labelMat = load_data_set()
weights = grad_ascent(dataMat, labelMat)
plot_best_fit(weights.getA())
效果图: