1 介绍
线性回归与逻辑回归是机器学习中必须要掌握的算法,接下来我会用简洁的语言介绍一下算法的原理。然后是逻辑回归的代码实现,代码中加入了充分的注释以易理解。
2 原理
2.1 线性回归
线性回归的损失函数如上所示,是预测值与真实值的均方误差,越小越好。(为什么用该式作为损失函数?直观理解,该式子表达的是预测值与真实值总体的差异。也可从概率的角度解释,从极大似然估计的最大化目标,推导得到最小化该目标,这里不作解释)
简洁起见,下面的公式使用矩阵形式进行介绍。(X,Y表示的是整体的样本与标签,所以矩阵形式的公式无需累加符号)
此时的目标是:求得最优的 $\theta$ , 使得损失函数 J 的值最小。求解方法如下:
步骤:
1)先求 J 对 $\theta$ 的导数:
2)再求使得 J 最小的 $\theta$ :
有两种方法:
正规方程法:直接令 J 对 $\theta$ 的导数值为0,即(1)式等于0,求得的 $\theta$ 如下所示,此 $\theta$ 为 J 的极值点(极小值点,可自行证明),可令 J 达到局部极小。该方法有一定局限性,在 $X^{T}X$ 不可逆(非满秩矩阵)时,无法使用正规方程法。
梯度下降法:该方法通过迭代使得 $\theta$ 逐渐收敛,每次迭代 $\theta$ 从梯度方向进行更新,J 逐渐降低并最终达到局部极小。($\alpha$ 为学习率,后面式子为求得的梯度)
2.2 逻辑回归
输出的表达式P如上图,逻辑回归就是在线性回归输出时,套上一个sigmoid函数,将输出值压缩到 [0, 1] 之间作为概率值。
逻辑回归的损失函数如上式,为交叉熵损失函数,反应两个分布之间的差异。
(为什么用该式作为损失函数?交叉熵损失也可从概率的角度进行解释,从极大似然估计的最大化目标,推导得到最小化该目标,这里不作解释)
求解步骤:
1)先求 F 对 w 的导数:
(可以发现,求得的导数跟线性回归形式相同,都是真实值与预测值的误差乘上输入X)
2)梯度下降迭代求解:
(牢记该公式,代码实现中会使用到该结果)
3 代码
该代码为逻辑回归算法的实现:
class LogRegres:
def __init__(self, lr, epchos):
self.lr = lr
self.epchos = epchos
def sigmoid(self, x):
return 1 / (1 + np.exp(-x))
def train(self, X, y):
# 将输入转换成numpy的矩阵类型,防止出现运算错误
X = np.mat(X)
y = np.mat(y).reshape(-1, 1)
m, n = X.shape
# 初始化权重矩阵W与偏置b,权重个数等于特征个数n
self.W = np.zeros((n, 1))
self.b = 0
# 将偏置b融合进W,跟随W一起计算
# 输出的计算:X*W = (m,n+1)*(n+1,1) =(m, 1)
X = np.insert(np.mat(X), 0, 1, axis=1) #输入的第一列加上1,shape(m, n+1)
self.W = np.insert(self.W, 0, self.b, axis=0) #权重第一行加上b,shape(n+1, 1)
# 迭代更新W
for i in range(self.epchos):
output = self.sigmoid(X*self.W)
self.W += self.lr * X.T * (y-output) # 损失函数对w的偏导等于X*loss
return
def predict(self, X_test):
# 第一列加上1
X_test = np.insert(np.mat(X_test), 0, 1, axis=1)
return self.sigmoid(X_test * self.W)
使用:(数据集 testSet.txt)
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
train = np.loadtxt('testSet.txt') #数据集shape(100, 3),最后一列是类别标签
X, y = train[:, :2], train[:, -1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4)
model = LogRegres(lr=0.1, epchos=1000) #配置模型参数:学习率、迭代次数
model.train(X_train, y_train)
y_pre = model.predict(X_test)
y_pre = [1 if x>=0.5 else 0 for x in y_pre] #概率转成类别
print(accuracy_score(y_test, y_pre)) #0.975
print(model.W) #打印训练好的权重
希望看完此文的你,可以得到一些收获,如有问题,欢迎提出。 也可参考我在 知乎 的其他文章。