sxyhetao 2019-12-19
逻辑回归模型(LR)是判别模型,可以用于二分类或多分类,模型如下:
二分类:
$$P(Y=1 | x)=\frac{\exp\left(w \cdot x\right)}{1+ \exp \left(w \cdot x\right)}$$
$$P(Y=0 | x)=\frac{1}{1+ \exp \left(w \cdot x\right)}$$
多分类:
$$P(Y=k | x)=\frac{\exp \left(w_{k} \cdot x\right)}{1+\sum_{k=1}^{K-1} \exp \left(w_{k} \cdot x\right)}, \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\right)}$$
一个事件发生的几率,是该事件发生的概率与不发生的概率的比值,也就是样本为正例的相对可能性。在几率外面套个$log$的壳子,就变成了对数几率。对数几率可用线性函数表示,这正是线性回归模型的形式,故该模型也称为对数几率回归。$$\log\frac{P\left(Y=1|x\right)} {1-P\left(Y=1|x\right)}=w \cdot x$$
线性模型不只有直线的样子,在$w \cdot x$的外面加上单调可微的函数就可以得到各种非线性的样子,这些模型称之为广义线性模型。线性模型的求解方法为基于均方误差的最小二乘法。
逻辑回归模型的参数估计可以应用极大似然估计法,首先列出对数似然函数:
设$p=P(Y=1 | x)$,有:
$$L(w)=\sum_{i=1}^{N} \left[y_{i}log \left(p\right)+\left(1-y_{i}\right)log \left(1-p\right)\right]$$
$$=\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,这个式子又叫交叉熵损失函数。
class LogisticReressionClassifier: # 超参数有学习率和迭代轮数 def __init__(self, max_iter=200, learning_rate=0.01): self.max_iter = max_iter self.learning_rate = learning_rate # 建立sigmoid函数 def sigmoid(self, x): return 1 / (1 + exp(-x)) # 给数据第一列加一列1.0,这个就是和后面的权重w相乘时得到的那个b def data_matrix(self, X): data_mat = [] for d in X: data_mat.append([1.0, *d]) return data_mat # 建立lr模型 def fit(self, X, y): # label = np.mat(y) data_mat = self.data_matrix(X) # m*n # 权重初始化,都设置为0 self.weights = np.zeros((len(data_mat[0]), 1), dtype=np.float32) # 迭代Max_iter轮 for iter_ in range(self.max_iter): # 每轮将样本一个个计算一遍 for i in range(len(X)): # 预测值 result = self.sigmoid(np.dot(data_mat[i], self.weights)) # 误差 error = y[i] - result # 更新参数 self.weights += self.learning_rate * error * np.transpose( [data_mat[i]]) print(‘LogisticRegression Model(learning_rate={},max_iter={})‘.format( self.learning_rate, self.max_iter)) # 进行预测 def score(self, X_test, y_test): right = 0 X_test = self.data_matrix(X_test) for x, y in zip(X_test, y_test): result = np.dot(x, self.weights) if (result > 0 and y == 1) or (result < 0 and y == 0): right += 1 return right / len(X_test)
from sklearn.linear_model import LogisticRegression clf = LogisticRegression(max_iter=200) clf.fit(X_train, y_train) clf.score(X_test, y_test)
不同点:
逻辑回归处理分类问题,线性回归处理回归问题。逻辑回归的因变量是离散的,线性回归因变量是连续的。
相同点:
二者都使用了极大似然估计对训练样本进行建模。
如果一个样本只对应于一个标签时,利用softmax进行分类。
如果一个样本属于多个标签的情况,可以训练多个二分类,对第i个标签进行预测。
L1正则:
$$L(w)=\frac{1}{m} \left[ \sum_{i=1}^{m} \left[y_{i}log \left(p\right)+\left(1-y_{i}\right)log \left(1-p\right)\right] + \lambda \sum_{j=1}^{n}|w_{j}| \right]$$
L2正则:
$$L(w)=\frac{1}{m} \left[ \sum_{i=1}^{m} \left[y_{i}log \left(p\right)+\left(1-y_{i}\right)log \left(1-p\right)\right] + \lambda \sum_{j=1}^{n}w_{j}^{2} \right]$$
对于特征约束强的需求下l1合适,否则l2。
逻辑回归假设数据服从伯努利分布(二项分布)
这个问题有点难,可以从对数几率角度、sigmoid求导特性、定义域从负无穷到正无穷且值域在0到1、概率分布等角度,可以参考:
https://www.zhihu.com/question/35322351
如果使用均方差,对参数求导的时候公式中还保留着sigmoid的导数,而sigmoid的导数在头尾均接近于0,这使得参数更新的很慢(推导一下就知道了)。
而交叉熵损失函数求导后没有sigmoid的导数,只有sigmoid,且真实值与预测值差别越大,梯度越大,更新的速度也就越快,这正是我们想要的。
有放回抽样,每次概率相等(个人猜测)
若正负样本不均衡,需要上采样或下采样。下采样会有数据利用不充分问题,有一个trick:采样多次,训练多个模型,跟随机森林一样,求个平均即可
如果在损失函数最终收敛的情况下,其实就算有很多特征高度相关也不会影响分类器的效果
每一个特征都是原来特征权重值的百分之一,线性可能解释性优点也消失了
增加训练收敛的难度及耗时,有限次数下可能共线性变量无法收敛,系数估计变得不可靠
泛化能力变差,训练是两列特征可能会共线性,当线上数据加入噪声后共线性消失,效果可能变差
模型中对数据对处理一般都有一个标答是提升数据表达能力,也就是使数据含有的可分信息量更大。
工程角度:
加速收敛
提高计算效率
理论角度:
梯度下降过程稳定
使得数据在某类上更服从高斯分布,满足前提假设
离散特征的增加和减少都很容易,易于模型的快速迭代;
稀疏向量内积乘法运算速度快,计算结果方便存储,容易扩展;
离散化后的特征对异常数据有很强的鲁棒性:比如一个特征是年龄>30是1,否则0。如果特征没有离散化,一个异常数据“年龄300岁”会给模型造成很大的干扰;
逻辑回归属于广义线性模型,表达能力受限;单变量离散化为N个后,每个变量有单独的权重,相当于为模型引入了非线性,能够提升模型表达能力,加大拟合;
离散化后可以进行特征交叉,由M+N个变量变为M*N个变量,进一步引入非线性,提升表达能力;
特征离散化后,模型会更稳定,比如如果对用户年龄离散化,20-30作为一个区间,不会因为一个用户年龄长了一岁就变成一个完全不同的人。当然处于区间相邻处的样本会刚好相反,所以怎么划分区间是门学问;
特征离散化以后,起到了简化了逻辑回归模型的作用,降低了模型过拟合的风险。
李沐曾经说过:模型是使用离散特征还是连续特征,其实是一个“海量离散特征+简单模型” 同 “少量连续特征+复杂模型”的权衡。既可以离散化用线性模型,也可以用连续特征加深度学习。就看是喜欢折腾特征还是折腾模型了。通常来说,前者容易,而且可以n个人一起并行做,有成功经验;后者目前看很赞,能走多远还须拭目以待。
原来的单变量可扩展到n个离散变量,每个变量有单独的权重,相当于为模型引入了非线性,能够提升模型表达能力,加大拟合
离散后结合正则化可以进行特征筛选,更好防止过拟合
数据的鲁棒性更好,不会因为无意义的连续值变动导致异常因素的影响,(31岁和32岁的差异在哪呢?)
离散变量的计算相对于连续变量更快
优点
缺点
西瓜书
李航统计学习方法
theta = np.zeros #theta = array,构造全为零的行向量。grad[0,j] = np.sum/len #∑term / m. return value > threshol