机器学习——逻辑回归(分类)编程训练

机器学习——逻辑回归(分类)编程训练

参考资料:

1.黄海广老师:吴恩达机器学习笔记github

本文是吴恩达机器学习课程中的第二个编程训练。关于逻辑回归的详细介绍可以参考吴恩达机器学习课程

编程任务:

已知一些学生的两次考试成绩和录取情况,训练一个分类器,可以根据两次考试成绩判断学生是否被录取

1.逻辑回归算法原理

逻辑回归算法的实现流程基本上同线性回归的实现流程是一样的。

  • 读取数据
  • 获取特征值
  • 获取标签值
  • 特征缩放
  • 构建特征与标签之间的函数关系(假设函数)
  • 构建代价函数
  • 求取代价函数的偏导数
  • 最小化代价函数,并获取到此时的权重
  • 根据权重得到特征与标签之间的函数关系

逻辑回归算法与线性回归算法的不同主要体现在特征与标签之间的函数关系上:

  • 线性回归算法: h θ ( x ) = θ 0 x 0 + θ 1 x 1 + θ 2 x 2 + θ 3 x 3 + . . . h_θ(x) = θ_0x_0 + θ_1x_1+θ_2x_2+θ_3x_3+... hθ(x)=θ0x0+θ1x1+θ2x2+θ3x3+...

  • 逻辑回归算法: h θ ( x ) = g ( θ 0 x 0 + θ 1 x 1 + θ 2 x 2 + θ 3 x 3 + . . . ) h_θ(x) =g(θ_0x_0 + θ_1x_1+θ_2x_2+θ_3x_3+...) hθ(x)=g(θ0x0+θ1x1+θ2x2+θ3x3+...)

    这里的函数 g ( z ) g(z) g(z)​​是sigmoid函数:
    g ( z ) = 1 1 + e − z g(z) = \frac{1}{1+e^{-z}} g(z)=1+ez1
    请添加图片描述

    上图是sigmoid函数的图像,其值在0,1之间

这里补充说明一下逻辑回归算法的假设函数为什么要这样假设。

由于逻辑回归算法准确来说是一个分类问题,标签值只有0,1两种可能。我们采用线性回归的假设是很难进行数据的分类的。而逻辑回归算法则采用概率的形式来进行分类。由于sigmoid函数的取值为(0,1),我们可以假设当sigmoid函数的值大于等于0.5时,将其分为1类,小于0.5时,将其分为0类。这样就很好的解决了一个分类问题。

2.代价函数

由于我们采用的假设函数已经与线性回归时采用的假设函数不同,因此,代价函数也会有相应的变化。
J ( θ ) = 1 m ∑ m ( y ( i ) ∗ log ⁡ ( h θ ( x ( i ) ) ) + ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) ) J(θ) = \frac{1}{m}\sum^m(y^{(i)}*\log(h_θ(x^{(i)})) +(1-y^{(i)})\log(1-h_θ(x^{(i)}))) J(θ)=m1m(y(i)log(hθ(x(i)))+(1y(i))log(1hθ(x(i))))
这里的上标 ( i ) (i) (i)表示的是第几个样本中的特征和标签​

对代价函数求取偏导:
∂ J ( θ ) ∂ θ = 1 m ∑ m ( h θ ( x ( i ) ) − y ( i ) ) x ( i ) \frac{∂J(θ)}{∂θ} =\frac{1}{m}\sum^m(h_θ(x^{(i)}) -y^{(i)})x^{(i)} θJ(θ)=m1m(hθ(x(i))y(i))x(i)

3.最小化代价函数

在线性回归过程中使用的方法为:批量梯度下降法。批量梯度下降法在逻辑回归中也同样适用,但是在本例中,笔者使用批量梯度下降法并没有能够(完全不能)解决分类问题。

在本例中使用到的是另外一种优化算法:Newton-CG,此外还有共轭梯度法(CG),变尺度法(BFGS),限制变尺度法(L-BFGS)

关于这些优化算法的具体数学原理,这里不做介绍(因为笔者也不懂)

Newton-CG的数学原理可以参考论文基于Newton法改进的BFGS迭代法与Newton-CG算法

但这都不是重点,重点是应用,如何应用这些算法来最小化代价函数

这里参考scipy模块函数使用介绍

scipy.optimize.minimize(fun, x0, args=(), method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None)
'''
fun:需要最小化的目标函数
x0:迭代的初始值,要求x0.shape为(n,)
args:传递给目标函数的额外参数
method:要采用的最小化方法
jac:计算梯度向量(即偏导数),可调用函数
'''

4.决策边界

在本例中,决策边界即: X × θ = 0 X × θ=0 X×θ=0​即: θ 0 x 0 + θ 1 x 1 + θ 2 x 2 = 0 θ_0x_0 + θ_1x_1+θ_2x_2=0 θ0x0+θ1x1+θ2x2=0

我们已知: θ 0 , x 0 = 1 , θ 1 , x 1 , θ 2 θ_0,x_0=1,θ_1,x_1,θ_2 θ0,x0=1,θ1,x1,θ2​,因此我们可以根据上式求得 x 2 x_2 x2

于是我们就得到了一条直线,这个直线就是决策边界: x 2 = − ( θ 0 θ 2 + θ 1 θ 0 x 1 ) x_2 = -(\frac{θ_0}{θ_2} + \frac{θ_1}{θ_0}x_1) x2=(θ2θ0+θ0θ1x1)

5.代码实现

数据集:自黄海广老师的GitHub仓库,具体链接

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import scipy.optimize as opt
from sklearn.metrics import classification_report  # 这个包是评价报告


def get_X(df):  # 获取特征
    ones = pd.DataFrame({'ones': np.ones(len(df))})
    data = pd.concat([ones, df], axis=1)
    return data.iloc[:, :-1].values


def get_y(df):  # 获取标签
    return np.array(df.iloc[:, -1])


def normalize_feature(df):  # 特征缩放,本例中并没有使用
    return df.apply(lambda column: (column - column.mean()) / column.std())


def sigmoid(z):  # 定义sigmoid函数
    return 1 / (1 + np.exp(-z))


def cost(theta, X, y):  # 定义代价函数,这里需要注意X,theta,y的维度
    return np.mean(-y * np.log(sigmoid(X @ theta)) - (1 - y) * np.log(1 - sigmoid(X @ theta)))
    # (100,1)*[(100,3)(3,1)]  这里并不影响计算计算结果
    # 值得一提的是,在numpy中,+,-,*,/都只是相对应元素的运算,不遵循矩阵计算规则
    # numpy中的矩阵计算需要使用@或者.dot()函数
    # 同样也可以将ndarray类型数据通过np.matrix()转换成矩阵,使用*进行计算


def gradient(theta, X, y):  # 求偏导
    return (1 / len(X)) * X.T @ (sigmoid(X @ theta) - y)  # (3,100)[(100,3)(3,1)]====>(3,1)


def predict(x, theta):  # 预测函数,用来进行验证
    prob = sigmoid(x @ theta)
    return (prob >= 0.5).astype(int)


# 读取数据,获取特征和标签,并初始化theta
data = pd.read_csv("ex2data1.txt", names=['exam1', 'exam2', 'admitted'])
X = get_X(data)  # (100, 3)
y = get_y(data)  # (100,)
theta = np.zeros(3)  # (3,)

# 使用优化算法Newton-CG来最小化代价函数
result = opt.minimize(fun=cost, x0=theta, args=(X, y), method='Newton-CG', jac=gradient)
final_theta = result.x  # 代价函数最小化后的得到的theta
y_pred = predict(X, final_theta)  # 对原有的数据特征进行预测
print(classification_report(y, y_pred))  # 真实值,预测值,进行比较,输出评价报告

# 绘制散点图
sns.set(context="notebook", style="ticks", font_scale=1.5)
sns.lmplot('exam1', 'exam2', hue='admitted', data=data,
           height=6,
           fit_reg=False,
           scatter_kws={"s": 25}
           )

# 绘制决策边界
coefficient = -(result.x / result.x[2])   # 已知权重,x_0 = 1,则可以将x_1视为x,将x_2视为y,根据θx = 0 来求解y
x = np.arange(130, step=0.1)   # 这里的x就是x_1
y = coefficient[0] + coefficient[1] * x  # 这里的y就是用x_1 表示的x_2
plt.plot(x, y, 'grey')
plt.xlim(0, 130)
plt.ylim(0, 130)
plt.title('Decision Boundary')
plt.show()

6.运行结果

              precision    recall  f1-score   support

           0       0.87      0.85      0.86        40
           1       0.90      0.92      0.91        60

    accuracy                           0.89       100
   macro avg       0.89      0.88      0.88       100
weighted avg       0.89      0.89      0.89       100

从评价报告中可以看出,分类的正确率达到了89%。
下图是数据的散点图和决策边界。
请添加图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值