欢迎大家来到IT世界,在知识的湖畔探索吧!
一、逻辑回归:数据科学界的 “万能钥匙”
在 2023 年 Kaggle 最新行业报告中,一个看似简单的算法震惊了整个数据科学圈 ——逻辑回归以 63.5% 的使用率登顶行业榜首,成为除军事安全领域外,金融、医疗、电商等全行业的 “标配”。这个结果让深度学习(CNN 仅 18.9%、RNN 12.3%)都望尘莫及,甚至比决策树(49.9%)高出近 14 个百分点!
欢迎大家来到IT世界,在知识的湖畔探索吧!
为什么简单算法反而更吃香?
- 数据门槛低:无需规模庞大的标注数据,即便是小型数据集,亦能实现精准建模。
- 解释性王者:特征权重能够直观地体现影响程度,乃金融风控之必备。
- 计算成本低:相较于神经网络,仅单机便能迅速完成训练。
真实场景应用:
- 医疗领域:通过肿瘤大小、血糖等指标预测恶性概率(1 = 恶性,0 = 良性)
- 金融行业:基于消费记录、信用评分计算信用卡违约风险
- 电商场景:根据浏览时长、点击行为判断用户购买意向
二、揭开逻辑回归的神秘面纱:从线性回归到分类神器
1. 算法本质:用概率说话的 “跨界选手”
在多元线性回归中,我们知道: 通过向量化的表示方法将 到
整理成一个向量 θ,同时将 X 矩阵的每一行添加一个虚拟的第零个特征值为 1。这样可以将预测值表示为:
,其中
是预测值向量。而在逻辑回归中,虽然名称含”回归”,但实际即可解决回归问题,又可解决分类问题,尤其是二分类问题,通过预测概率值间接实现分类。针对二分类问题,它的预测机制是模型输出的预测值(
)表示事件发生概率p,当时p>=0.5时,预测结果为1类,p<0.5时,预测结果为0类。
逻辑回归算法的的值域是处于负无穷到正无穷区间的,而概率的值域为[0,1],因此两者需要进行转换,如下图所示:
为了能将线性方程的结果转换为概率值域区间内的数值,需要求出
的值,并将其作为一个特征传递一个新的函数,即Sigmoid函数。这是逻辑回归模型用于预测概率的公式 。具体解释如下:
:代表预测的概率值,取值范围在0到1之间 ,表示样本属于正类的概率。
:是逻辑函数(Logistic function),也叫Sigmoid函数,公式为:
,其作用是将任意实数映射到(0, 1)区间,用于将线性组合的结果转化为概率。
:是模型的参数向量,包含了模型学习到的各个特征的权重。
:是参数向量
的装置 ,用于矩阵乘法运算。
:是添加了额外特征(一般是值为1的截距项)的特征向量,目的是将线性模型扩展为可以包含截距项的形式。通过这样的运算,将特征向量
与参数相量
的线性组合结果输入到Sigmoid函数中得到预测为正类的概率
。截图中展示了逻辑回归用于预测概率的公式
,其中是
预测概率,
是Sigmoid函数,
是
参数向量的转置,
是添加了截距项的特征向量。
截图中Sigmoid函数的表达式 ,其中-t 为函数输入值。该明确指出Sigmoid函数的作用是将线性回归的结果
映射到 (0,1) 区间 ,这使得输出可以被解释为概率值。该公式的数学特性如下所示:
- 当 t 趋于负无穷(t→−∞t→−∞ )时 ,σ(t)σ(t) 趋于 0。
- 当 t 趋于正无穷(t→+∞t→+∞ )时 ,σ(t)σ(t) 趋于 1 。
- 当 t = 0 时 ,σ(0)=0.5σ(0)=0.5 。这些特性体现了Sigmoid函数的取值变化趋势,是理解其在逻辑回归中如何将线性输出转化为概率值的关键。
2. Sigmoid 函数:把直线掰弯的 “魔法曲线”
为了让大家理解线性回归切换到逻辑回归,现在用Python绘制Sigmoid曲线,以图象的形式让大家有个直观的感受。编写代码如下所示:
import matplotlib.pyplot as plt import numpy as np def sigmoid(t): return 1 / (1 + np.exp(-t)) x = np.linspace(-10, 10, 500) y = sigmoid(x) plt.plot(x, y) plt.title("Sigmoid函数:0-1概率的完美映射") plt.show()
欢迎大家来到IT世界,在知识的湖畔探索吧!
该代码执行的结果如下图所示:
- 图像特征:值域 (0,1),当 t=0时
,形成决策临界点。
- 数学特性:
时,
(强正类倾向)
时,
(强负类倾向)
- 当t=0,σ(t)=0.5(决策临界点)
- 形象比喻:像一个 “智能门槛”,自动将线性结果转化为概率判断
3. 如何求解sigmoid函数中的
如何求解 θ 值是模型训练过程中最为重要的事情,现在请大家看如下图所示公式和问题,请稍作思考后,我将给出一个简单的求解样例代码和预测值。
- 简单代码实现
欢迎大家来到IT世界,在知识的湖畔探索吧!import numpy as np def sigmoid(z): """ 定义Sigmoid函数 """ return 1 / (1 + np.exp(-z)) def predict_probability(theta, x_b): """ 预测概率 """ z = np.dot(theta.T, x_b) return sigmoid(z) # 示例数据 theta = np.array([0.5, 0.3, 0.2]) # 参数向量 x_b = np.array([1, 2, 3]) # 添加了截距项的特征向量 # 预测概率 p_hat = predict_probability(theta, x_b) print(f"预测概率: {p_hat}")预测概率: 0.64652其中,sigmoid 函数的实现方式于代码中得以呈现,所涉之 sigmoid(z)函数,其核心代码为:1 / (1 + np.exp(-z))
4. sigmoid函数的损失函数
类似于线性回归中借助 MSE、RMSE、MAE 等指标来评判损失函数结果的优劣,在逻辑回归中同样是运用损失函数来予以评估。如下图所示表达了和
两者之间的关系:
公式
截图中说明了损失与预测概率和真实标签y 的关系:
- 当真实标签 y = 1 时,预测概率p^ 越小,损失(cost)越大 。因为希望预测概率 p^ 尽可能接近1 , 若p^ 小,说明预测偏离真实情况较多,损失就大。
- 当真实标签 y = 0 时,预测概率 p^ 越大,损失(cost)越大 。此时期望预测概率 p^ 接近0 ,若p^ 大,预测与真实情况不符,损失增大。
- 使用什么函数来表达这个cost呢?使用如下图所示的惩罚函数来表达cost损失函数
为了便于理解cost中的log函数,以图像的形式理解:
首先,看下log(p)函数的图形,如下所示:
其次,-log(p_hat)函数的图形,如下所示:
由于 的值是在(0,1)之间的,因此小于0的部分是没有意义的,图形变化成如下:
再来看下log(1-p_hat)函数的图形:
由于 -log(-x) 函数的图像呈现如下:
而-log(1-x)的图像是向右移动一个单位,得到如下所示:
由于 p^ 的值是在(0,1)之间的,因此小于0的部分是没有意义的,图形变化成如下:
图片右侧展示了两个函数图像:
- \(y = -\log(x)\):对应 \(y = 1\) 时的损失函数情况(当 \(\hat{p}\) 作为 x 轴变量),该函数在 \((0,1]\) 区间,x 越接近 1,y 值越小。
- \(y = -\log(1-x)\):对应 \(y = 0\) 时的损失函数情况,在 \([0,1)\) 区间,x 越接近 0,y 值越小。
因此,可得出结论:
为了编程方便,将cost损失函数公式进行变换,如下图所示:
针对多个样本时,公式可以变换成如下:
逻辑归回最终的损失函数如下所示:
由于该函数没有解析解,因此只能使用梯度下降法进行求解。求解逻辑回归损失函数的梯度,具体如下:
- 对J($\theta$)函数的 $\theta$ 各个维度进行求导
- 先对sigmoid函数进行求导
- 再对log函数进行求导
进一步简化:
- 最后的导数
- 最终求得用于编程的梯度
三、 代码实现自己的逻辑回归算法
根据上述相关公式,使用Python来封装一个属于自己的逻辑回归算法,代码及其执行结果如下所示:
- 引入相关依赖库和数据集并可视化
欢迎大家来到IT世界,在知识的湖畔探索吧!import numpy as np import matplotlib.pyplot as plt from sklearn import datasets iris = datasets.load_iris() X = iris.data y = iris.target # 鸢尾花有三种类型,这里取出0,1两种,每个取出前两个特征 X = X[y<2, :2] y = y[y<2] # 绘制散点图 # 这行代码绘制了标签为 0 的样本的散点图。X[y == 0,0]表示标签为 0 的样本的第一列特征,X[y==0,1]表示标签为 0 的样本的第二列特征。color='red'指定了散点的颜色为红色。 plt.scatter(X[y == 0,0], X[y==0,1],color='red') # 这行代码绘制了标签为 1 的样本的散点图。X[y == 1,0]表示标签为 1 的样本的第一列特征,X[y==1,1]表示标签为 1 的样本的第二列特征。color='blue'指定了散点的颜色为蓝色。 plt.scatter(X[y == 1,0], X[y==1,1],color='blue') plt.show()
- 编写训练集和测试集的划分函数
import numpy as np def train_test_split(X, y, test_ratio=0.2, seed=None): """ 将输入的特征矩阵 X 和标签向量 y 按照指定的测试集比例 test_ratio 划分为训练集和测试集。 Args: X (numpy.ndarray): 特征矩阵,形状为 (n_samples, n_features),表示输入的数据特征。 y (numpy.ndarray): 标签向量,形状为 (n_samples,),表示每个样本对应的标签。 test_ratio (float, optional): 测试集占总数据集的比例,取值范围为 [0.0, 1.0]。默认值为 0.2。 seed (int, optional): 随机数种子,用于确保多次运行该函数时生成的随机结果一致。默认值为 None。 Returns: tuple: 包含四个元素的元组,分别为: - X_train (numpy.ndarray): 训练集的特征矩阵。 - y_train (numpy.ndarray): 训练集的标签向量。 - X_test (numpy.ndarray): 测试集的特征矩阵。 - y_test (numpy.ndarray): 测试集的标签向量。 Raises: AssertionError: 如果 X 和 y 的样本数量不一致,或者 test_ratio 不在 [0.0, 1.0] 范围内,会抛出此异常。 """ # 确保输入的特征矩阵 X 和标签向量 y 的样本数量一致 assert X.shape[0] == y.shape[0], \ "特征矩阵 X 的样本数量必须与标签向量 y 的样本数量相等。" # 确保测试集比例 test_ratio 在有效范围内 assert 0.0 <= test_ratio <= 1.0, \ "测试集比例 test_ratio 必须在 [0.0, 1.0] 范围内。" # 如果指定了随机数种子 seed,则设置 NumPy 的随机数生成器的种子,以保证结果的可重复性 if seed: np.random.seed(seed) # 生成一个长度为样本数量的随机排列的索引数组,用于打乱样本顺序 shuffle_indexes = np.random.permutation(len(X)) # 计算测试集的样本数量 test_size = int(len(X) * test_ratio) # 从打乱的索引数组中选取前 test_size 个索引作为测试集的索引 test_indexes = shuffle_indexes[:test_size] # 从打乱的索引数组中选取剩余的索引作为训练集的索引 train_indexes = shuffle_indexes[test_size:] # 根据训练集的索引从特征矩阵 X 和标签向量 y 中提取训练集数据 X_train = X[train_indexes] y_train = y[train_indexes] # 根据测试集的索引从特征矩阵 X 和标签向量 y 中提取测试集数据 X_test = X[test_indexes] y_test = y[test_indexes] # 返回划分好的训练集和测试集的特征矩阵与标签向量 return X_train, y_train, X_test, y_test- 编写逻辑回归函数
欢迎大家来到IT世界,在知识的湖畔探索吧!import numpy as np from metrics import accuracy_score class LogisticRegression: # 构造函数 def __init__(self): """初始化Logistic Regression模型""" self.intercept_ = None # 定义截距 self.coef_ = None # 定义系数 self._theta = None # 定义内部参数 def _sigmoid(self, t): return 1. / (1 + np.exp(-t)) def fit(self, X_train, y_train, eta=0.01, n_iters=1e4): """根据训练数据集X_train, y_train,使用批量梯度下降法训练Logistic Regression模型""" assert X_train.shape[0] == y_train.shape[0], \ "the size of X_train must be equal to the size of y_train" def J(theta, X_b, y): """逻辑回归损失函数""" y_hat = self._sigmoid(X_b.dot(theta)) try: return -np.sum(y * np.log(y_hat) + (1 - y) * np.log(1 - y_hat)) / len(y) except: return float('inf') def dJ(theta, X_b, y): """梯度下降法求损失函数大的梯度""" return X_b.T.dot(self._sigmoid(X_b.dot(theta)) - y) / len(X_b) def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8): theta = initial_theta i_iter = 0 while i_iter < n_iters: gradient = dJ(theta, X_b, y) last_theta = theta # 迭代更新theta参数 theta = theta - eta * gradient if abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon: break i_iter += 1 return theta X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) initial_theta = np.zeros(X_b.shape[1]) self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters) self.intercept_ = self._theta[0] self.coef_ = self._theta[1:] return self def predict_proba(self, X_predict): """给定待预测数据集X_predict,返回表示X_predict的结果概率向量""" assert self.intercept_ is not None and self.coef_ is not None, \ "must fit before predict!" assert X_predict.shape[1] == len(self.coef_), \ "the feature number of X_predict must be equal to X_train" X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict]) return self._sigmoid(X_b.dot(self._theta)) def predict(self, X_predict): """给定待预测数据集X_predict,返回表示X_predict的结果向量""" assert self.intercept_ is not None and self.coef_ is not None, \ "must fit before predict!" assert X_predict.shape[1] == len(self.coef_), \ "the feature number of X_predict must be equal to X_train" proba = self.predict_proba(X_predict) return np.array(proba >= 0.5, dtype='int') def score(self, X_test, y_test): """根据测试数据集 X_test 和 y_test 确定当前模型的准确度""" y_predict = self.predict(X_test) return accuracy_score(y_test, y_predict) def __repr__(self): return "LogisticRegression()" - 在Jupyter中进行调用
from model_selection import train_test_split from LogisticRegressionModel import LogisticRegression X_train, y_train, X_test, y_test = train_test_split(X,y,seed=666) logistic_reg = LogisticRegression() logistic_reg.fit(X_train,y_train) logistic_reg.score(X_test,y_test)准确度:1.0
四、扩展知识:逻辑回归的 “进阶玩法”
- 决策边界:线性模型的分类分界线
- 方程:
- 示例:线性决策边界
,将平面分为正负两类区域。使用多项式特征,绘制出逻辑回归中的决策边界,如下图所示:
- 多项式特征:让线性模型拟合非线性数据
- 原理:通过添加 (
,xy,
) 等多项式特征,将线性决策边界升级为曲线(如二次曲线、三次曲线)。
- 应用场景:当数据分布呈现非线性模式时(如环形分布),提升模型拟合能力。
五、结语:简单背后的力量
当人们沉迷于深度学习的”炫酷”时,逻辑回归用数据证明:在真实世界里,简单、高效、可解释的算法永远有它的生存空间。无论是刚入行的新手,还是资深数据科学家,掌握逻辑回归的底层逻辑,都能让你在数据分析的战场上事半功倍。
互动话题:你在工作中用过逻辑回归吗?遇到过哪些有趣的应用场景?欢迎在评论区分享你的故事!
本文亮点总结:
✅ 行业数据可视化:用图表数据强化说服力
✅ 公式标准化:采用TeX格式精确表达数学逻辑
✅ 代码实战化:提供完整可运行的Python实现代码
✅ 场景落地化:覆盖医疗、金融、电商等多行业案例
✅ 争议点探讨:对比深度学习,客观分析逻辑回归的优缺点
关注我,后续将推出机器学习更多内容,带你解锁更多实战技巧!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/129610.html