[Machine Learning] 线性回归与逻辑回归(含代码)

线性回归与逻辑回归

    • 1 线性回归与逻辑回归的区别与联系
      • 1.1 决策边界
      • 1.2 代价函数
      • 1.3 梯度下降法
    • 2 线性回归的代码实现
      • 2.1 单变量线性回归
      • 2.2 多变量线性回归
      • 2.3 sklearn
    • 3 逻辑回归的代码实现
      • 3.1 逻辑回归
      • 3.2 sklearn
    • 参考资料

1 线性回归与逻辑回归的区别与联系

线性回归和逻辑回归都是广义上的线性回归。但两者又有不同。

方法自变量(特征)因变量(结果)关系应用
线性回归(Linear Regression)连续或离散连续实数线性回归
逻辑回归(Logistic Regression)连续或离散(0,1)之间连续值非线性分类

1.1 决策边界

线性回归 是利用数理统计中的回归分析,来确定两种或两种以上变量间相互依赖的定量关系的一种统计分析方法。表达形式为y = θx + e,其中e为误差服从均值为0的正态分布。适用于有监督学习的预测。

  • 单变量线性回归:hθ(x)=θ0+θ1x,只包含一个自变量x和一个因变量hθ(x),且二者的关系可以用一条直线近似表示;
  • 多变量线性回归:hθ(x)=θ0+θ1x1+…+θnxn,包括两个或两个以上的自变量(x1、x2 …),并且因变量和自变量是线性关系。

逻辑回归 首先通过sigmoid函数将样本映射到[0,1]之间的数值。sigmoid函数可以把任何连续的值映射到[0,1]之间,在这里插入图片描述
决策边界:对多变量线性回归方程求sigmoid函数,
在这里插入图片描述
线性回归在整个实数域范围内进行预测,敏感度一致,而分类范围需要在[0,1]。逻辑回归是在线性回归的基础上,多一步sigmoid非线性映射。即减小预测范围,将预测值限定为[0,1]间的一种回归模型。所以线性回归模型对异常值敏感,而逻辑回归通过非线性变换减弱分离平面较远的点的影响,鲁棒性比线性回归的要好。

1.2 代价函数

代价函数是将随机事件或其有关随机变量的取值映射为非负实数以表示该随机事件的“风险”或“损失”的函数。用来评价模型的预测值和真实值不一样的程度,通常代价函数越小,模型的性能越好。

线性回归

  • 单变量线性回归:
    在这里插入图片描述

  • 多变量线性回归:

    其中,

  • m:训练样本的个数;

  • hθ(x):用参数θ和x预测出来的y值;

  • y:原训练样本中的y值,也就是标准答案;

  • 上角标(i):第i个样本。

逻辑回归
对于线性回归,使用MSE得到的J(θ)为凸函数,但是对于logistic回归,由于进行了sigmoid非线性映射,在寻优时容易陷入局部最优的问题,所以考虑把sigmoid作log,得到的J(θ)。
在这里插入图片描述
在这里插入图片描述
J(θ)对θ求二阶导,得到其二阶导大于0,说明J(θ)为凸函数,使用梯度下降法寻优时,可以保证找到全局最小。

1.3 梯度下降法

使用梯度下降算法来求得能使代价函数最小的参数。

线性回归
在这里插入图片描述

逻辑回归
加粗样式
经梯度下降算法后线性回归与逻辑回归的公式形式看上去是一致的,但实际上两者是完全不同的,因为假设函数是不同的。
注:线性回归可使用正规方程求使代价函数最小的θ,但逻辑回归无法使用正规方程。

2 线性回归的代码实现

2.1 单变量线性回归

import numpy as np
import pandas as pd

# 读取数据
data = pd.read_csv(path, header=None, names=['x', 'y'])

# 代价函数
def computeCost(X, y, theta):
    inner = np.power(((X * theta.T) - y), 2)
    return np.sum(inner) / (2 * len(X))

# 处理数据及初始化
data.insert(0, 'Ones', 1) #在训练集中添加一列,以便可以使用向量化的解决方案来计算代价和梯度
cols = data.shape[1] #获取矩阵的列数
X = data.iloc[:,0:cols-1] #X是所有行,去掉最后一列
y = data.iloc[:,cols-1:cols] #y是所有行,最后一列

X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix(np.array([0,0]))

computeCost(X, y, theta)

# 批量梯度下降算法
def gradientDescent(X, y, theta, alpha, iters):
    temp = np.matrix(np.zeros(theta.shape))
    parameters = int(theta.ravel().shape[1])
    cost = np.zeros(iters)
    
    for i in range(iters):
        error = (X * theta.T) - y
        
        for j in range(parameters):
            term = np.multiply(error, X[:,j])
            temp[0,j] = theta[0,j] - ((alpha / len(X)) * np.sum(term))
            
        theta = temp
        cost[i] = computeCost(X, y, theta)
        
    return theta, cost

alpha = 0.01 #设置学习率α
iters = 2000 #设置迭代次数

g, cost = gradientDescent(X, y, theta, alpha, iters) # 运行梯度下降算法来将我们的参数θ适合于训练集
computeCost(X, y, g) #使用我们拟合的参数计算训练模型的代价函数

可视化结果

# 绘制线性模型
import matplotlib.pyplot as plt

x = np.linspace(data.x.min(), data.x.max(), 100)
f = g[0, 0] + (g[0, 1] * x)

fig, ax = plt.subplots(figsize=(12,8))
ax.plot(x, f, 'r', label='Prediction')
ax.scatter(data.x, data.y, label='Traning Data')
ax.legend(loc=2)
ax.set_xlabel('xxx')
ax.set_ylabel('xxx')
ax.set_title('xxx')
plt.show()
# 绘制每个迭代次数与代价cost的关系图
fig, ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(iters), cost, 'r')
ax.set_xlabel('Iterations')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()

2.2 多变量线性回归

import pandas as pd

data = pd.read_csv(path, header=None, names=['x1', 'x2', 'y'])

# 特征归一化
data = (data - data.mean()) / data.std()

# 第一列添加ones
data.insert(0, 'Ones', 1)

cols = data.shape[1]
X = data.iloc[:,0:cols-1]
y = data.iloc[:,cols-1]

X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix(np.array([0,0,0]))

# 调用梯度下降算法
g, cost = gradientDescent(X, y, theta, alpha, iters)

computeCost(X, y, g2)

除了调用梯度下降算法外,也可使用正规方程得到theta。

# 正规方程
def normalEqn(X, y):
    theta = np.linalg.inv(X.T@X)@X.T@y #X.T@X等价于X.T.dot(X)
    return theta

梯度下降与正规方程的比较
在这里插入图片描述

  • 梯度下降:需要选择学习率α,需要多次迭代,当特征数量n大时也能较好适用,适用于各种类型的模型
  • 正规方程:不需要选择学习率α,一次计算得出,但需要计算 ( X T X ) − 1 {{\left( {{X}^{T}}X \right)}^{-1}} (XTX)1。如果特征数量n较大则运算代价大,因为矩阵逆的计算时间复杂度为 O ( n 3 ) O(n3) O(n3),通常来说当 n n n小于10000 时还是可以接受的,只适用于线性模型,不适合逻辑回归模型等其他模型

2.3 sklearn

from sklearn import linear_model

model = linear_model.LinearRegression()
model.fit(X, y)

x = np.array(X[:, 1].A1)
f = model.predict(X).flatten()


fig, ax = plt.subplots(figsize=(12,8))
ax.plot( x, f, 'r', label='Prediction')
ax.scatter(data.x, data.y, label='Traning Data')
ax.legend(loc=2)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('xxx')
plt.show()

最小二乘法线性回归:sklearn.linear_model.LinearRegression(fit_intercept=True, normalize=False,copy_X=True, n_jobs=1)

主要参数说明

参数说明
fit_intercept布尔型,默认为True,若参数值为True时,代表训练模型需要计算截距;若参数为False时,代表模型无需加截距项
normalize布尔型,默认为False,若fit_intercept参数设置False时,normalize参数无需设置;若normalize设置为True时,则输入的样本数据将(X-X均值)/||X||;若设置normalize=False时,在训练模型前,可以使用sklearn.preprocessing.StandardScaler进行标准化处理
copy_X布尔型,默认为True,否则X会被改写
n_jobsint,默认为1,表示用于计算的作业数量,如果为-1,则代表调用所有cpu

属性

  • coef_:回归系数(斜率)
regr = linear_model.LinearRegression()
regr.fit(X,y)
regr.coef_
  • intercept_:截距项
regr = linear_model.LinearRegression()
regr.fit(X,y)
regr.intercept_

主要方法

  • fit(X, y, sample_weight=None),x和y以矩阵的形式传入,sample_weight则是每条测试数据的权重,同样以矩阵方式传入
  • predict(X),预测方法,用来返回预测值
  • score(X, y, sample_weight=None),评分函数,将返回一个小于1的得分,可能会小于0
  • get_params(deep=True), 返回对regressor 的设置值

3 逻辑回归的代码实现

3.1 逻辑回归

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

data = pd.read_csv(path, header=None, names=['x1', 'x2', 'y'])

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

# 创建两个"正负"分数的散点图,并使用颜色编码来可视化
fig, ax = plt.subplots(figsize=(12,8))
ax.scatter(positive['x1'], positive['x2'], s=50, c='b', marker='o', label='Yes')
ax.scatter(negative['x1'], negative['x2'], s=50, c='r', marker='x', label='No')
ax.legend()
ax.set_xlabel('x1 Score')
ax.set_ylabel('x2 Score')
plt.show()

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

# 定义代价函数
def cost(theta, X, y):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
    second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))
    return np.sum(first - second) / (len(X))

# 数据处理及初始化
data.insert(0, 'Ones', 1) #插入ones
cols = data.shape[1] #获得列数
X = data.iloc[:,0:cols-1]
y = data.iloc[:,cols-1:cols]

X = np.array(X.values)
y = np.array(y.values)
theta = np.zeros(3)

cost(theta, X, y)

# 梯度下降算法
def gradient(theta, X, y):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    
    parameters = int(theta.ravel().shape[1])
    grad = np.zeros(parameters)
    
    error = sigmoid(X * theta.T) - y
    
    for i in range(parameters):
        term = np.multiply(error, X[:,i])
        grad[i] = np.sum(term) / len(X)
    
    return grad

gradient(theta, X, y) #查看数据和初始参数为0的梯度下降法的结果

# 用SciPy's truncated newton(TNC)实现寻找最优参数
import scipy.optimize as opt
result = opt.fmin_tnc(func=cost, x0=theta, fprime=gradient, args=(X, y))
cost(result[0], X, y)

# 使用获得的参数theta来为数据集X输出预测,并使用这个函数为分类器的训练精度打分。
def predict(theta, X):
    probability = sigmoid(X * theta.T)
    return [1 if x >= 0.5 else 0 for x in probability]

theta_min = np.matrix(result[0])
predictions = predict(theta_min, X)
correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y)]
accuracy = (sum(map(int, correct)) % len(correct))
print ('accuracy = {0}%'.format(accuracy))

若原始数据无明显的线性决策界限,一种方法是利用原始特征多项式得到特征,并对该特征使用像逻辑回归这样的线性技术。

degree = 5
x1 = data['Test 1']
x2 = data['Test 2']

data.insert(3, 'Ones', 1)

for i in range(1, degree):
    for j in range(0, i):
        data['F' + str(i) + str(j)] = np.power(x1, i-j) * np.power(x2, j)

data.drop('Test 1', axis=1, inplace=True)
data.drop('Test 2', axis=1, inplace=True)

# 正则化代价函数
def costReg(theta, X, y, learningRate):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
    second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))
    reg = (learningRate / (2 * len(X))) * np.sum(np.power(theta[:,1:theta.shape[1]], 2))
    return np.sum(first - second) / len(X) + reg

def gradientReg(theta, X, y, learningRate):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    
    parameters = int(theta.ravel().shape[1])
    grad = np.zeros(parameters)
    
    error = sigmoid(X * theta.T) - y
    
    for i in range(parameters):
        term = np.multiply(error, X[:,i])
        
        if (i == 0):
            grad[i] = np.sum(term) / len(X)
        else:
            grad[i] = (np.sum(term) / len(X)) + ((learningRate / len(X)) * theta[:,i])
    
    return grad

# 数据初始化,X、y
cols = data.shape[1]
X = data.iloc[:,1:cols]
y = data.iloc[:,0:1]

X = np.array(X.values)
y = np.array(y.values)
theta = np.zeros(11)

learningRate = 1 # 初始化学习率
costReg(theta, X, y, learningRate) #代价
gradientReg(theta, X, y, learningRate) #获得参数

result = opt.fmin_tnc(func=costReg, x0=theta, fprime=gradientReg, args=(X, y, learningRate))
theta_min = np.matrix(result[0])
predictions = predict(theta_min, X)
correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y)]
accuracy = (sum(map(int, correct)) % len(correct))
print ('accuracy = {0}%'.format(accuracy))

3.2 sklearn

from sklearn import linear_model #调用sklearn的线性回归包
model = linear_model.LogisticRegression(penalty='l2', C=1.0)
model.fit(X, y.ravel())

model.score(X, y)

参考资料

logistic 回归(内附推导)
线性回归和逻辑回归
浅析机器学习:线性回归 & 逻辑回归
代码部分主要引用黄海广博士的资料

热门文章

暂无图片
编程学习 ·

exe4j详细使用教程(附下载安装链接)

一、exe4j介绍 ​ exe4j是一个帮助你集成Java应用程序到Windows操作环境的java可执行文件生成工具,无论这些应用是用于服务器,还是图形用户界面(GUI)或命令行的应用程序。如果你想在任务管理器中及Windows XP分组的用户友好任务栏…
暂无图片
编程学习 ·

AUTOSAR从入门到精通100讲(126)-浅谈车载充电系统通信方案

01 引言 本文深入研究车载充电系统策略,设计出一套基于电动汽车电池管理系统与车载充电机的CAN通信协议,可供电动汽车设计人员参考借鉴。 02 电动汽车充电系统通讯网络 电动汽车整车控制系统中采用的是CAN总线通信方式,由一个整车内部高速CAN网络、内部低速CAN网络和一个充电…
暂无图片
编程学习 ·

CMake(九):生成器表达式

当运行CMake时,开发人员倾向于认为它是一个简单的步骤,需要读取项目的CMakeLists.txt文件,并生成相关的特定于生成器的项目文件集(例如Visual Studio解决方案和项目文件,Xcode项目,Unix Makefiles或Ninja输入文件)。然…
暂无图片
编程学习 ·

47.第十章 网络协议和管理配置 -- 网络配置(八)

4.3.3 route 命令 路由表管理命令 路由表主要构成: Destination: 目标网络ID,表示可以到达的目标网络ID,0.0.0.0/0 表示所有未知网络,又称为默认路由,优先级最低Genmask:目标网络对应的netmaskIface: 到达对应网络,应该从当前主机哪个网卡发送出来Gateway: 到达非直连的网络,…
暂无图片
编程学习 ·

元宇宙技术基础

请看图: 1、通过AR、VR等交互技术提升游戏的沉浸感 回顾游戏的发展历程,沉浸感的提升一直是技术突破的主要方向。从《愤怒的小鸟》到CSGO,游戏建模方式从2D到3D的提升使游戏中的物体呈现立体感。玩家在游戏中可以只有切换视角,进而提升沉浸…
暂无图片
编程学习 ·

flink的伪分布式搭建

一 flink的伪分布式搭建 1.1 执行架构图 1.Flink程序需要提交给 Job Client2.Job Client将作业提交给 Job Manager3.Job Manager负责协调资源分配和作业执行。 资源分配完成后,任务将提交给相应的 Task Manage。4.Task Manager启动一个线程以开始执行。Task Manage…
暂无图片
编程学习 ·

十进制正整数与二进制字符串的转换(C++)

Function one: //十进制数字转成二进制字符串 string Binary(int x) {string s "";while(x){if(x % 2 0) s 0 s;else s 1 s;x / 2;}return s; } Function two: //二进制字符串变为十进制数字 int Decimal(string s) {int num 0, …
暂无图片
编程学习 ·

[含lw+源码等]微信小程序校园辩论管理平台+后台管理系统[包运行成功]Java毕业设计计算机毕设

项目功能简介: 《微信小程序校园辩论管理平台后台管理系统》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 本系统包含微信小程序做的辩论管理前台和Java做的后台管理系统: 微信小程序——辩论管理前台涉及技术:WXML 和 WXS…
暂无图片
编程学习 ·

树莓派驱动DHT11温湿度传感器

1,直接使用python库 代码如下 import RPi.GPIO as GPIO import dht11 import time import datetimeGPIO.setwarnings(True) GPIO.setmode(GPIO.BCM)instance dht11.DHT11(pin14)try:while True:result instance.read()if result.is_valid():print(ok)print(&quo…
暂无图片
编程学习 ·

ELK简介

ELK简介 ELK是三个开源软件的缩写,Elasticsearch、Logstash、Kibana。它们都是开源软件。不过现在还新增了一个 Beats,它是一个轻量级的日志收集处理工具(Agent),Beats 占用资源少,适合于在各个服务器上搜集日志后传输给 Logstas…
暂无图片
编程学习 ·

Linux 基础

通常大数据框架都部署在 Linux 服务器上,所以需要具备一定的 Linux 知识。Linux 书籍当中比较著名的是 《鸟哥私房菜》系列,这个系列很全面也很经典。但如果你希望能够快速地入门,这里推荐《Linux 就该这么学》,其网站上有免费的电…
暂无图片
编程学习 ·

Windows2022 无线网卡装不上驱动

想来 Windows2022 和 windows10/11 的驱动应该差不多通用的,但是死活装不上呢? 搜一下,有人提到 “默认安装时‘无线LAN服务’是关闭的,如果需要开启,只需要在“添加角色和功能”中,选择开启“无线LAN服务…
暂无图片
编程学习 ·

【嵌入式面试宝典】版本控制工具Git常用命令总结

目录 创建仓库 查看信息 版本回退 版本检出 远程库 Git 创建仓库 git initgit add <file> 可反复多次使用&#xff0c;添加多个文件git commit -m <message> 查看信息 git status 仓库当前的状态git diff 差异对比git log 历史记录&#xff0c;提交日志--pret…
暂无图片
编程学习 ·

用Postman生成测试报告

newman newman是一款基于nodejs开发的可以运行postman脚本的工具&#xff0c;使用Newman&#xff0c;可以直接从命令运行和测试postman集合。 安装nodejs 下载地址&#xff1a;https://nodejs.org/en/download/ 选择自己系统相对应的版本内容进行下载&#xff0c;然后傻瓜式安…
暂无图片
编程学习 ·

Java面向对象之多态、向上转型和向下转型

文章目录前言一、多态二、引用类型之间的转换Ⅰ.向上转型Ⅱ.向下转型总结前言 今天继续Java面向对象的学习&#xff0c;学习面向对象的第三大特征&#xff1a;多态&#xff0c;了解多态的意义&#xff0c;以及两种引用类型之间的转换&#xff1a;向上转型、向下转型。  希望能…