逻辑回归(1)

题目:

构建模型预测某个学生是否能被大学录取,你有之前申请学生的两次考试成绩和最终录取的结果,需要你构建一个评估录取的分类模型。

首先准备数据,绘出散点图

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 读取数据
path = 'ex2data1.txt'
data = pd.read_csv(path, header=None, names=['Exam1', 'Exam2', 'Admitted'])
data.head()
data.describe() # 更详细的数据

positive = data[data['Admitted'].isin([1])]
negative = data[data['Admitted'].isin([0])]

fig, ax = plt.subplots(figsize=(12, 8))
ax.scatter(positive['Exam1'], positive['Exam2'], s=50, c='b', marker='o', label='Admitted')# s=50设置了数据点的大小
ax.scatter(negative['Exam1'], negative['Exam2'], s=50, c='r', marker='x', label='Not Admitted')
ax.legend()
ax.set_xlabel('Exam1 Score')
ax.set_ylabel('Exam2 Score')
plt.show()
  • isin()是Pandas中的一个函数,用于过滤数据框的行,只保留那些指定列中的值在给定列表中的行。在这里,它筛选出'Admitted'列中值为1的行。
  • 散点图如下:

 使用sigmoid函数,将模型的输出转换为概率值

  • Sigmoid函数可以将任何实数映射到0和1之间
  • 当输入值非常大或非常小时,输出值会趋近于0或1。

从而可以被解释为概率。例如,在逻辑回归中,Sigmoid函数常常被用作输出层,将线性回归模型的输出转换为概率值。

  •  下面是使用NumPy库中的exp函数计算e的-z次幂
  •  这个表达式是Sigmoid函数的标准形式,用于将任何实数z映射到0和1之间的一个值。
  • Sigmoid函数通常用作激活函数,将模型的输出转换为概率值。
  • 例如,在二分类问题中,模型的输出可以被解释为属于正类的概率。
def sigmoid(z):
    return 1 / (1 + np.exp(-z)) # 将输入z映射到0和1之间的一个值。
# Sigmoid函数经常用于将模型的 输出 转换为 概率值

nums = np.arange(-10, 10, step=0.5)

fig, ax = plt.subplots(figsize=(12, 8))
ax.plot(nums, sigmoid(nums), 'r')
plt.show()

所绘图形如下:👇 

使用代价函数 

1. 首先对data进行预处理

# 对输入(特征)做扩展
data.insert(0, 'Ones', 1)

data.head()

 也就是添加了一行

q

2. 使用代价函数,算出初始的代价 

 

 !!!公式代码理解:
  • 定义一个 cost 的函数,它接受三个参数:theta(模型的参数),X(输入数据),和 Y(真实标签)
  • 第一部分:
  • first = Y * np.log(sigmoid(X@theta.T))
  • `X@theta.T`:这是矩阵乘法操作,其中 `X` 是输入数据矩阵,`theta.T` 是参数向量 `theta` 的转置。这个操作计算了所有样本的预测概率。
  • `sigmoid(X@theta.T)`:将预测概率通过 Sigmoid 函数转换为介于 0 和 1 之间的值。
  •  `Y * np.log(sigmoid(X@theta.T))`:对于每个样本,如果其真实标签 `Y` 为 1,则计算 `np.log(sigmoid(X@theta.T))`;如果 `Y` 为 0,则计算 `0 * np.log(sigmoid(X@theta.T))`,即计算 0。这实际上只关心那些真实标签为 1 的样本的预测概率。
  • 第二部分:
  • second = (1 - Y) * np.log(1 - sigmoid(X@theta.T))
  • `1 - Y`:对于每个样本,如果其真实标签 `Y` 为 1,则 `1 - Y` 为 0;如果 `Y` 为 0,则 `1 - Y` 为 1。
  • 第二部分同理
  • 然后计算损失:return -1 * np.mean(first + second)
  • `first + second`:将第一部分和第二部分相加,得到每个样本的损失。
  • `np.mean(first + second)`:计算所有样本的平均损失。
  • `-1 * np.mean(first + second)`:由于对数损失通常定义为负数(因为我们希望最大化对数似然,这等价于最小化负对数似然),所以这里取平均损失的负值作为最终的损失。
def cost(theta, X, Y):
    first = Y * np.log(sigmoid(X@theta.T))
    second = (1 - Y) * np.log(1 - sigmoid(X@theta.T))
    return -1 * np.mean(first + second)

X用作特征输入,而Y用作标签或目标输出 

X和y是一个NumPy数组,包含了data中除了最后一列之外的所有数据。

X = data.iloc[:, 0: -1].values # 左闭右开
Y = data.iloc[:, -1].values # .values是将其转化为numpy数组
theta = np.zeros(3)


theta
# array([0., 0., 0.])

X.shape, Y.shape, theta.shape
#((100, 3), (100,), (3,))

# 计算初始的代价(theta=0),为0.6931471805599453
cost(theta, X, Y)

将梯度下降运用到正则化代价函数中 

 

# 计算步长
# gradient只是计算了梯度下降 θ更新的步长,使用Scipy.optimize.fmin_tnc拟合最优的 θ
def gradient(theta, X, Y):
    return (1/len(X) * X.T @ (sigmoid(X @ theta.T) - Y)) # X转置相当于后面这部分与求和了

gradient(theta, X, Y)
# array([ -0.1       , -12.00921659, -11.26284221])

拟合参数 

import scipy.optimize as opt

# func=cost,就是传的损失函数;x0初始点;args是传样本的输入和输出;jac传的梯度
res = opt.minimize(fun=cost, x0=np.array(theta), args=(X, np.array(Y)), method='Newton-CG', jac=gradient)
res
  fun: 0.20349770451259855
     jac: array([1.62947970e-05, 1.11339134e-03, 1.07609314e-03])
 message: 'Optimization terminated successfully.'
    nfev: 71
    nhev: 0
     nit: 28
    njev: 242
  status: 0
 success: True
       x: array([-25.16576744,   0.20626712,   0.20150754])
cost(res.x, X, Y)
# 0.20349770451259855

 此时通过使用Scipy.optimize.minimize拟合出了最优的θ(与上面0.6形成对比)

 用训练集预测和验证

# theta就是我们刚刚训练出来的theta
def predict(theta, X):
    probability = sigmoid(X @ theta.T)
    return [1 if x >= 0.5 else 0 for x in probability]

 然后使用了一个方法:

final_theta = res.x
y_pred = predict(final_theta,X)

# support标签中出现的次数
# precision查准率,recall召回率,f1-score调和平均数
from sklearn.metrics import classification_report
print(classification_report(y,y_pred))
    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
真实类别
01
预测0TN(真反例)FN(假反例)
类别1FP(假正例)TP(真正例)

precision=tp / tp+fp  查准率 意思是:在所有正例中真正的正例占比,也就是准确率

recall=tp / tp+fn   召回率 意思是:你这个算法可以从真实的类别中回收回来多少正例

f1-score=2pr / p+r 调和平均数

这就是决策边界:coef = -res.x / res.x[2]

 最后画出决策边界

 

print(res.x)# theta
# [-25.16576744   0.20626712   0.20150754]

coef = -res.x / res.x[2]
coef
# array([124.88747248,  -1.02361985,  -1.        ])

coef[0]
# 124.88747248

coef[1]
# -1.0236198475377516

 上面代码理解如下图👇

然后在图上画出来: 

x = np.arange(30, 100, 0.5)
y = coef[0] + coef[1] * x # y就是算出来的决策边界

fig, ax = plt.subplots(figsize=(12, 8))
ax.scatter(positive['Exam1'], positive['Exam2'], s=50, c='b', marker='o', label='Admitted')
ax.scatter(negative['Exam1'], negative['Exam2'], s=50, c='r', marker='x', label='Not Admitted')
ax.plot(x, y, label='Decision Boundary', c='grey')
ax.legend()
ax.set_xlabel('Exam1 Score')
ax.set_ylabel('Exam2 Score')
plt.show()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值