zoukankan      html  css  js  c++  java
  • 逻辑回归


    逻辑回归

    原理

    逻辑回归模型

    逻辑回归模型(LR)是判别模型,可以用于二分类或多分类,模型如下:

    二分类:

    $$P(Y=1 | x)=frac{expleft(w cdot x ight)}{1+ exp left(w cdot x ight)}$$

    $$P(Y=0 | x)=frac{1}{1+ exp left(w cdot x ight)}$$

    多分类:

    $$P(Y=k | x)=frac{exp left(w_{k} cdot x ight)}{1+sum_{k=1}^{K-1} exp left(w_{k} cdot x ight)}, quad k=1,2, cdots, K-1$$

    $$P(Y=K | x)=frac{1}{1+sum_{k=1}^{K-1} exp left(w_{k} cdot x ight)}$$

    对数几率

    一个事件发生的几率,是该事件发生的概率与不发生的概率的比值,也就是样本为正例的相对可能性。在几率外面套个$log$的壳子,就变成了对数几率。对数几率可用线性函数表示,这正是线性回归模型的形式,故该模型也称为对数几率回归。$$logfrac{Pleft(Y=1|x ight)} {1-Pleft(Y=1|x ight)}=w cdot x$$

    线性模型

    线性模型不只有直线的样子,在$w cdot x$的外面加上单调可微的函数就可以得到各种非线性的样子,这些模型称之为广义线性模型。线性模型的求解方法为基于均方误差的最小二乘法。

    求解方法 

    逻辑回归模型的参数估计可以应用极大似然估计法,首先列出对数似然函数:

    设$p=P(Y=1 | x)$,有:

    $$L(w)=sum_{i=1}^{N} left[y_{i}log left(p ight)+left(1-y_{i} ight)log left(1-p ight) ight]$$

    $$=sum_{i=1}^{N} [y_{i}(w cdot x)-log(1+exp(w cdot x))]$$

     

    采用梯度下降法估计$L(w)$的极值,对上式求导:

    $$frac{dL}{dw}=(y_{i}-frac{1}{1+exp(w cdot x)}) cdot x$$

    这就是梯度的方向,在每一轮迭代的时候沿着梯度下降的方向更新参数w,这个式子又叫交叉熵损失函数。

    代码实现

     手动实现

     1 class LogisticReressionClassifier:
     2     
     3     # 超参数有学习率和迭代轮数
     4     def __init__(self, max_iter=200, learning_rate=0.01):
     5         self.max_iter = max_iter
     6         self.learning_rate = learning_rate
     7 
     8     # 建立sigmoid函数
     9     def sigmoid(self, x):
    10         return 1 / (1 + exp(-x))
    11     
    12     # 给数据第一列加一列1.0,这个就是和后面的权重w相乘时得到的那个b
    13     def data_matrix(self, X):
    14         data_mat = []
    15         for d in X:
    16             data_mat.append([1.0, *d])
    17         return data_mat
    18 
    19     # 建立lr模型
    20     def fit(self, X, y):
    21         # label = np.mat(y)
    22         data_mat = self.data_matrix(X)  # m*n
    23         # 权重初始化,都设置为0
    24         self.weights = np.zeros((len(data_mat[0]), 1), dtype=np.float32)
    25 
    26         # 迭代Max_iter轮
    27         for iter_ in range(self.max_iter):
    28             # 每轮将样本一个个计算一遍
    29             for i in range(len(X)):
    30                 # 预测值
    31                 result = self.sigmoid(np.dot(data_mat[i], self.weights))
    32                 # 误差
    33                 error = y[i] - result
    34                 # 更新参数
    35                 self.weights += self.learning_rate * error * np.transpose(
    36                     [data_mat[i]])
    37         print('LogisticRegression Model(learning_rate={},max_iter={})'.format(
    38             self.learning_rate, self.max_iter))
    39 
    40     # 进行预测
    41     def score(self, X_test, y_test):
    42         right = 0
    43         X_test = self.data_matrix(X_test)
    44         for x, y in zip(X_test, y_test):
    45             result = np.dot(x, self.weights)
    46             if (result > 0 and y == 1) or (result < 0 and y == 0):
    47                 right += 1
    48         return right / len(X_test)

    工具实现

    1 from sklearn.linear_model import LogisticRegression
    2 
    3 clf = LogisticRegression(max_iter=200)
    4 clf.fit(X_train, y_train)
    5 clf.score(X_test, y_test)

    面试问题

    逻辑回归相比于线性回归,有何异同?

    不同点:

    逻辑回归处理分类问题,线性回归处理回归问题。逻辑回归的因变量是离散的,线性回归因变量是连续的。

    相同点:

    二者都使用了极大似然估计对训练样本进行建模。

     

    当使用逻辑回归处理多分类问题时,有哪些常见做法,分别应用于哪些场景,它们之间又有怎样的关系?

    如果一个样本只对应于一个标签时,利用softmax进行分类。

    如果一个样本属于多个标签的情况,可以训练多个二分类,对第i个标签进行预测。

     

    写一下LR的损失函数,加上L1/L2正则化;然后解释原理,分析不同点,怎么用

    L1正则:

    $$L(w)=frac{1}{m} left[ sum_{i=1}^{m} left[y_{i}log left(p ight)+left(1-y_{i} ight)log left(1-p ight) ight] + lambda sum_{j=1}^{n}|w_{j}| ight]$$

    L2正则:

    $$L(w)=frac{1}{m} left[ sum_{i=1}^{m} left[y_{i}log left(p ight)+left(1-y_{i} ight)log left(1-p ight) ight] + lambda sum_{j=1}^{n}w_{j}^{2} ight]$$

    对于特征约束强的需求下l1合适,否则l2。

     

    LR是什么假设

    逻辑回归假设数据服从伯努利分布(二项分布)

     

    LR为什么要使用sigmoid

    这个问题有点难,可以从对数几率角度、sigmoid求导特性、定义域从负无穷到正无穷且值域在0到1、概率分布等角度,可以参考:

    https://www.zhihu.com/question/35322351

     

    LR为什么用交叉熵作为损失函数而不用均方差?

    如果使用均方差,对参数求导的时候公式中还保留着sigmoid的导数,而sigmoid的导数在头尾均接近于0,这使得参数更新的很慢(推导一下就知道了)。

    而交叉熵损失函数求导后没有sigmoid的导数,只有sigmoid,且真实值与预测值差别越大,梯度越大,更新的速度也就越快,这正是我们想要的。

     

    LR采用什么方式抽样?有放回还是无放回?为什么?

    有放回抽样,每次概率相等(个人猜测)

     

    假设有正负两类样本,用LR去划分有什么缺陷?

    若正负样本不均衡,需要上采样或下采样。下采样会有数据利用不充分问题,有一个trick:采样多次,训练多个模型,跟随机森林一样,求个平均即可

     

    如果有很多的特征高度相关或者说有一个特征重复了100遍,会造成怎样的影响?为什么要避免共线性?

    如果在损失函数最终收敛的情况下,其实就算有很多特征高度相关也不会影响分类器的效果
    每一个特征都是原来特征权重值的百分之一,线性可能解释性优点也消失了
    增加训练收敛的难度及耗时,有限次数下可能共线性变量无法收敛,系数估计变得不可靠
    泛化能力变差,训练是两列特征可能会共线性,当线上数据加入噪声后共线性消失,效果可能变差

    为什么LR需要归一化或者取对数?

    模型中对数据对处理一般都有一个标答是提升数据表达能力,也就是使数据含有的可分信息量更大。

    工程角度:
    加速收敛
    提高计算效率
    理论角度:
    梯度下降过程稳定
    使得数据在某类上更服从高斯分布,满足前提假设

    在工业界,LR通常将连续值变为离散值输入,为什么?

    离散特征的增加和减少都很容易,易于模型的快速迭代;

    稀疏向量内积乘法运算速度快,计算结果方便存储,容易扩展;

    离散化后的特征对异常数据有很强的鲁棒性:比如一个特征是年龄>30是1,否则0。如果特征没有离散化,一个异常数据“年龄300岁”会给模型造成很大的干扰;

    逻辑回归属于广义线性模型,表达能力受限;单变量离散化为N个后,每个变量有单独的权重,相当于为模型引入了非线性,能够提升模型表达能力,加大拟合;

    离散化后可以进行特征交叉,由M+N个变量变为M*N个变量,进一步引入非线性,提升表达能力;

    特征离散化后,模型会更稳定,比如如果对用户年龄离散化,20-30作为一个区间,不会因为一个用户年龄长了一岁就变成一个完全不同的人。当然处于区间相邻处的样本会刚好相反,所以怎么划分区间是门学问;

    特征离散化以后,起到了简化了逻辑回归模型的作用,降低了模型过拟合的风险。
    李沐曾经说过:模型是使用离散特征还是连续特征,其实是一个“海量离散特征+简单模型” 同 “少量连续特征+复杂模型”的权衡。既可以离散化用线性模型,也可以用连续特征加深度学习。就看是喜欢折腾特征还是折腾模型了。通常来说,前者容易,而且可以n个人一起并行做,有成功经验;后者目前看很赞,能走多远还须拭目以待。

    原来的单变量可扩展到n个离散变量,每个变量有单独的权重,相当于为模型引入了非线性,能够提升模型表达能力,加大拟合
    离散后结合正则化可以进行特征筛选,更好防止过拟合
    数据的鲁棒性更好,不会因为无意义的连续值变动导致异常因素的影响,(31岁和32岁的差异在哪呢?)
    离散变量的计算相对于连续变量更快

     

    LR的优缺点?

    优点

    • 简单,易部署,训练速度快
    • 模型下限较高
    • 可解释性强

    缺点

     

    参考

    西瓜书

    李航统计学习方法

    https://blog.csdn.net/slade_sha/article/details/103427059

    https://mp.weixin.qq.com/s/71w0IN3gAYWxrKVM_lcYrQ

  • 相关阅读:
    ThinkPHP 3.2.2 实现持久登录 ( 记住我 )
    Java实现 LeetCode 20 有效的括号
    Java实现 LeetCode 20 有效的括号
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 19删除链表的倒数第N个节点
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 18 四数之和
    Java实现 LeetCode 17 电话号码的字母组合
  • 原文地址:https://www.cnblogs.com/4PrivetDrive/p/12029588.html
Copyright © 2011-2022 走看看