机器学习分类算法之逻辑回归
一、概念
逻辑回归(Logistic Regression,LR)是一种广义的线性回归分析模型,属于监督学习算法,需要打标数据,可以用在回归、二分类和多分类等问题上,最常用的是二分类。
线性回归就是通过一条曲线区分不同的数据集,在二分类问题上会有一条直线对其进行区分,如下:
逻辑回归需要每组数据都是都是数值型的,因为需要对其进行运算,得到直线系数,打标数据一般是0和1。
二、计算
逻辑回归的输出是一组特征系数,使用了 y=wx+b这种函数来进行线性拟合,这个问题的y值不是0,就是1。使用上述函数很难快速逼近0-1。为了解决这个问题,我们给出一个激活函数Sigmoid函数:
他在z趋向于无穷小时,逼近于0 ,在t趋向于无穷大时逼近于1。
让 ,函数就变为了:
而,这样,W的存在就将原本的数据集转换为了一组值在0-1之间的数,我们通过调整W的值,尽可能让数据集的值贴近目标值,即0和1。
由上面介绍可知,y=0.5时刚好是x=0;
y越趋近于0,x越小,且为负数,到负无穷时为0;
反之,y越趋近于1,x越大,且为正数,到正无穷时为1。
逻辑回归会算出一组系数,使样本的值向目标值0或1趋近,越接近目标值越好,预测就会越准确。
这里用梯度下降法来实现逻辑回归。
梯度下降法(Gradient Descent)就是每一次迭代都向目标结果接近一点,直到计算收敛。
梯度下降法的基本思想可以类比为一个下山的过程,以当前的所处的位置为基准,寻找这个位置最陡峭的地方,然后朝着山的高度下降的地方走,同理,如果我们的目标是上山,也就是爬到山顶,那么此时应该是朝着最陡峭的方向往上走。然后每走一段距离,都反复采用同一个方法,最后就能成功的抵达山谷。
梯度下降公式为:
其中是权重系数每次需要调整的值,
alpha被称之为步长,也叫乘积系数,是为了限制每次调整的大小,调整太大会错过关键信息,调整太小会迭代次数过多,所以要反复调整,
error被称之为梯度,error = sigmoid(XW) - Y,Y是目标列,
我们一般会指定一个初始特征系数,一般设为全是1,即 W=(1,1,1.....,1),
常数项我们作为增广向量添加到数据集中,增广向量我们全部设为1,同样的,目标列也增加一个1,
最后我们还有设置一个阈值,来作为预测结果的依据,根据上面的描述,梯度下降法可选用sigmoid(XW)和0.5的比较来判断,因为小于0.5,x为负,趋近于0,大于0.5,x为正,趋近于1。
三、实现
# !/usr/bin/env python # -*- coding: utf-8 -*- import numpy as np import matplotlib.pyplot as plt def sigmoid(x): return 1.0 / (1 + np.exp(-x)) def grad_ascent(data_mat, class_label, alpha): data_matrix = np.mat(data_mat) label_mat = np.mat(class_label).transpose() m, n = np.shape(data_matrix) data_matrix = augment(data_matrix) # 增广 n += 1 weight = np.ones((n, 1)) while True: error = sigmoid(data_matrix * weight) - label_mat cha = alpha * data_matrix.transpose() * error if np.abs(np.sum(cha)) < 0.0001: break weight = weight - cha return weight def create_sample(): np.random.seed(10) # 随机数种子,保证随机数生成的顺序一样 n_dim = 2 num = 100 a = 3 + 5 * np.random.randn(num, n_dim) b = 18 + 4 * np.random.randn(num, n_dim) data_mat = np.concatenate((a, b)) ay = np.zeros(num) by = np.ones(num) label = np.concatenate((ay, by)) return {'data_mat': data_mat, 'label': label} def plot_data(samples, plot_type='o'): data_mat = samples['data_mat'] label = samples['label'] n = data_mat.shape[0] cs = ['r', 'g'] dd = np.arange(n) for i in range(2): index = label == i xx = data_mat[dd[index]] plt.plot(xx[:, 0], xx[:, 1], plot_type, markerfacecolor=cs[i], markersize=14) def augment(data_matrix): n, n_dim = data_matrix.shape a = np.mat(np.ones((n, 1))) return np.concatenate((data_matrix, a), axis=1) def classify(data_mat, weight): data_matrix = np.mat(data_mat) data_matrix = augment(data_matrix) d = sigmoid(data_matrix * weight) print(d) r = np.zeros((data_matrix.shape[0], 1)) r[d > 0.5] = 1 return r def plot(weight, data): lx = [0, -weight[2] / weight[0]] ly = [-weight[2] / weight[1], 0] plot_data(data) plt.plot(lx, ly) plt.show() def main(): data = create_sample() final_weight = grad_ascent(data['data_mat'], data['label'], 0.001) print(final_weight) plot(final_weight, data) pred = classify(data['data_mat'], final_weight) label = np.mat(data['label']).T diff = np.sum(pred != label) print(diff, len(label), 1.0 * diff / len(label)) if __name__ == '__main__': main()
四、结果:
weight:
[[ 0.3236568 ]
[ 0.30234029]
[-7.00232679]]
图形:
准确率:
预测不一致:4个
总数:200个
错误率:2%
调整迭代跳出条件为np.abs(np.sum(cha)) < 0.00001,则:
weight:
[[ 1.52741071]
[ 1.08976556]
[-32.00925101]]
图形:
准确率:
预测不一致:3个
总数:200个
错误率:1.5%