Press "Enter" to skip to content

做出预测:Python中线性回归的初学者指南

学习最流行的机器学习算法——线性回归,了解其数学直觉和Python实现的所有内容

做出预测:Python中线性回归的初学者指南 机器学习 第1张

线性回归(Linear Regression)是数据科学家在开始数据科学职业生涯时学习的最流行和第一个机器学习算法。它是最重要的监督学习算法,因为它为所有其他高级机器学习算法奠定了基础。这就是为什么我们需要非常清楚地学习和理解这个算法。

在本文中,我们将从零开始介绍线性回归,以及它的数学和几何直觉,以及它的Python实现。唯一的先决条件是您愿意学习和基本的Python语法知识。让我们开始吧。

什么是线性回归?

线性回归是一种用于解决回归问题的监督式机器学习算法。回归模型用于基于其他一些因素预测连续输出。例如,通过考虑利润率、总市值、年增长率等因素预测组织下个月的股票价格。线性回归也可以用于预测天气、股票价格、销售目标等应用。

顾名思义,线性回归建立了两个变量之间的线性关系。该算法找到了最佳的直线(y=mx+c),该直线可以根据自变量(x)预测因变量(y)。预测变量称为因变量或目标变量,用于预测的变量称为自变量或特征。如果只使用一个自变量,则称为单变量线性回归。否则,它被称为多元线性回归。

为了简化本文,我们将只采用一个自变量(x),以便可以在二维平面上轻松可视化。在下一节中,我们将讨论其数学直觉。

数学直觉

现在我们将理解线性回归的几何和数学。假设我们有一组样本X和Y值对,

做出预测:Python中线性回归的初学者指南 机器学习 第2张

我们必须使用这些值来学习一个函数,以便如果我们给出一个未知的(x),它可以根据学习预测一个(y)。在回归中,可以使用许多函数进行预测,但是线性函数是所有函数中最简单的。

做出预测:Python中线性回归的初学者指南 机器学习 第3张

该算法的主要目的是找到这些数据点中最适合的直线,如上图所示,从而产生最小的残差误差。残差误差是预测值与实际值之间的差异。

线性回归的假设

在继续之前,我们需要讨论线性回归的一些假设,以便获取准确的预测。

  1. 线性关系:线性关系意味着自变量和因变量必须遵循线性关系。否则,很难获得一条直线。此外,数据点必须相互独立,即一个观察值的数据不依赖于另一个观察值的数据。
  2. 同方差性:它表示残差误差的方差必须是恒定的。这意味着误差项的方差应该是常数,即使自变量的值发生变化也不会改变。此外,模型中的误差必须遵循正态分布。
  3. 无多重共线性:多重共线性意味着自变量之间存在相关性。因此,在线性回归中,自变量之间不得相关。

假设函数

我们假设我们的因变量(Y)和自变量(X)之间存在线性关系。我们可以将线性关系表示如下。

做出预测:Python中线性回归的初学者指南 机器学习 第4张

我们可以观察到,直线取决于参数θ0和θ1。因此,为了获得最佳拟合线,我们需要调整这些参数。它们也称为模型的权重。为了计算这些值,我们将使用损失函数,也称为成本函数。它计算预测值和实际值之间的均方误差。我们的目标是最小化此成本函数。使成本函数最小化的θ0和θ1值将形成我们的最佳拟合线。成本函数由(J)表示。

做出预测:Python中线性回归的初学者指南 机器学习 第5张

其中,

N是样本的总数

选择平方误差函数来处理负值(即如果预测值小于实际值)。此外,该函数除以2以便于差分过程。

优化器(梯度下降)

优化器是一种算法,通过迭代更新模型的属性,如权重或学习率,以实现最佳拟合线来最小化MSE。在线性回归中,使用梯度下降算法来通过更新Θ0和Θ1的值来最小化成本函数。

做出预测:Python中线性回归的初学者指南 机器学习 第6张

是称为学习率的超参数。它确定我们的权重相对于梯度损失调整的程度。学习率的值应该是最佳的,不要太高也不要太低。如果太高,模型很难收敛到全局最小值,如果太小,则需要更长时间才能收敛。

我们将绘制成本函数和权重之间的图来找到最佳的Θ0和Θ1。

做出预测:Python中线性回归的初学者指南 机器学习 第7张

最初,我们将为Θ0和Θ1分配随机值,然后计算成本函数和梯度。对于负梯度(成本函数的导数),我们需要向增加Θ1的方向移动以达到最小值。对于正梯度,我们必须向后移动才能达到全局最小值。我们的目标是找到一个梯度几乎等于零的点。在这一点上,成本函数的值是最小的。

到目前为止,您已经了解了线性回归的工作原理和数学知识。下一节将介绍如何使用Python在样本数据集上从零开始实现它。

线性回归Python实现

在本节中,我们将学习如何使用基本库(如Numpy、Pandas和Matplotlib)从零开始实现线性回归算法。我们将实现单变量线性回归,其中只包含一个独立变量和一个依赖变量。

我们将使用包含约700个(X,Y)对的数据集,其中X是独立变量,Y是依赖变量。Ashish Jangra贡献了此数据集,您可以从此处下载。

导入库

# 导入必要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.axes as ax
from IPython.display import clear_output

Pandas读取CSV文件并获取数据帧,而Numpy执行基本的数学和统计操作。Matplotlib负责绘制图形和曲线。

加载数据集

# 数据集链接:
# https://github.com/AshishJangra27/Machine-Learning-with-Python-GFG/tree/main/Linear%20Regression

df = pd.read_csv("lr_dataset.csv")
df.head()

# 删除空值
df = df.dropna()

# 训练集和测试集分割
N = len(df)
x_train, y_train = np.array(df.X[0:500]).reshape(500, 1), np.array(df.Y[0:500]).reshape(
    500, 1
)
x_test, y_test = np.array(df.X[500:N]).reshape(N - 500, 1), np.array(
    df.Y[500:N]
).reshape(N - 500, 1)

首先,我们将获取数据帧df,然后删除空值。之后,我们将数据分为训练和测试x_train、y_train、x_test和y_test。

构建模型

class LinearRegression:
    def __init__(self):
        self.Q0 = np.random.uniform(0, 1) * -1  # 截距
        self.Q1 = np.random.uniform(0, 1) * -1  # X的系数
        self.losses = []  # 存储每次迭代的损失

    def forward_propogation(self, training_input):
        predicted_values = np.multiply(self.Q1, training_input) + self.Q0  # y = mx + c
        return predicted_values

    def cost(self, predictions, training_output):
        return np.mean((predictions - training_output) ** 2)  # 计算损失

    def finding_derivatives(self, cost, predictions, training_input, training_output):
        diff = predictions - training_output
        dQ0 = np.mean(diff)  # d(J(Q0, Q1))/d(Q0)
        dQ1 = np.mean(np.multiply(diff, training_input))  # d(J(Q0, Q1))/d(Q1)
        return dQ0, dQ1

    def train(self, x_train, y_train, lr, itrs):
        for i in range(itrs):
            # 找到预测值(使用线性方程y=mx+c)
            predicted_values = self.forward_propogation(x_train)

            # 计算损失
            loss = self.cost(predicted_values, y_train)
            self.losses.append(loss)

            # 反向传播(找到权重的导数)
            dQ0, dQ1 = self.finding_derivatives(
                loss, predicted_values, x_train, y_train
            )

            # 更新权重
            self.Q0 = self.Q0 - lr * (dQ0)
            self.Q1 = self.Q1 - lr * (dQ1)

            # 它将动态更新直线的绘图
            line = self.Q0 + x_train * self.Q1
            clear_output(wait=True)
            plt.plot(x_train, y_train, "+", label="实际值")
            plt.plot(x_train, line, label="线性方程")
            plt.xlabel("训练-X")
            plt.ylabel("训练-Y")
            plt.legend()
            plt.show()
        return (
            self.Q0,
            self.Q1,
            self.losses,
        )  # 返回最终模型权重和损失

我们创建了一个名为LinearRegression()的类,在其中构建了所有所需的函数。

__init__:这是一个构造函数,在创建该类的对象时将使用随机值初始化权重。

forward_propogation():此函数将使用直线方程查找预测输出。

cost():这将计算与预测值相关联的残差误差。

finding_derivatives():此函数计算权重的导数,稍后可以用于更新权重以获得最小误差。

train():此函数将从训练数据、学习率和总迭代次数中获取输入。它将使用反向传播更新权重,直到指定数量的迭代为止。最后,它将返回最佳拟合线的权重。

训练模型

lr = 0.0001  # 学习率
itrs = 30  # 迭代次数
model = LinearRegression()
Q0, Q1, losses = model.train(x_train, y_train, lr, itrs)

# 输出迭代次数与损失
for itr in range(len(losses)):
    print(f"迭代次数 = {itr+1},损失 = {losses[itr]}")

输出:

迭代次数 = 1,损失 = 6547.547538061649
迭代次数 = 2,损失 = 3016.791083711492
迭代次数 = 3,损失 = 1392.3048668536044
迭代次数 = 4,损失 = 644.8855797373262
迭代次数 = 5,损失 = 301.0011032250385
迭代次数 = 6,损失 = 142.78129818453215
.
.
.
.
迭代次数 = 27,损失 = 7.949420840198964
迭代次数 = 28,损失 = 7.949411555664398
迭代次数 = 29,损失 = 7.949405538972356
迭代次数 = 30,损失 = 7.949401025888949

您可以观察到,在第一次迭代中,损失最大,在后续迭代中,此损失减小并在第30次迭代结束时达到其最小值。

做出预测:Python中线性回归的初学者指南 机器学习 第8张图3 查找最佳拟合线|作者提供的图像

以上动态图表明如何在完成第30次迭代后,直线达到其最佳拟合线。

最终预测

# 对测试数据进行预测
y_pred = Q0 + x_test * Q1
print(f"最佳拟合线:(Y = {Q1}*X + {Q0})")

# 用实际数据点绘制回归线
plt.plot(x_test, y_test, "+", label="数据点")
plt.plot(x_test, y_pred, label="预测值")
plt.xlabel("X-Test")
plt.ylabel("Y-Test")
plt.legend()
plt.show()

这是最佳拟合线的最终方程。

最佳拟合线:(Y = 1.0068007107347927*X + -0.653638673779529)

做出预测:Python中线性回归的初学者指南 机器学习 第9张图4 实际输出与预测输出|作者提供的图像

上图显示了测试集的最佳拟合线(橙色)和实际值(蓝色+)。您还可以调整超参数,例如学习率或迭代次数,以增加精度和准确性。

线性回归(使用Sklearn库)

在前一节中,我们已经看到了如何从头开始实现单变量线性回归。但是,也有一个名为sklearn的内置库,可以直接用来实现线性回归。让我们简要地讨论一下如何做到这一点。

我们将使用相同的数据集,但如果您愿意,也可以使用其他数据集。您需要导入两个额外的库,如下所示。

# 导入额外的库
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

加载数据集

df = pd.read_csv("lr_dataset.csv")

# 删除空值
df = df.dropna()

# 训练测试分离
Y = df.Y
X = df.drop("Y", axis=1)
x_train, x_test, y_train, y_test = train_test_split(
    X, Y, test_size=0.25, random_state=42
)

之前,我们必须手动使用 numpy 库执行训练测试分离。但现在我们可以使用 sklearn 的 train_test_split(),只需指定测试大小即可直接将数据分成训练集和测试集。

模型训练和预测

model = LinearRegression()
model.fit(x_train, y_train)
y_pred = model.predict(x_test)

# 使用实际数据点绘制回归线
plt.plot(x_test, y_test, "+", label="实际值")
plt.plot(x_test, y_pred, label="预测值")
plt.xlabel("X")
plt.ylabel("Y")
plt.legend()
plt.show()

现在,我们不必编写前向传播、反向传播、成本函数等代码。我们现在可以直接使用 LinearRegression() 类并在输入数据上训练模型。下面是从训练模型的测试数据中获得的绘图。结果与我们自己实现算法时的结果类似。

做出预测:Python中线性回归的初学者指南 机器学习 第10张 图5 Sklearn 模型输出 | 作者提供的图像

参考文献

  1. GeeksForGeeks:ML Linear Regression

总结

完整代码的 Google Colab 链接 – 线性回归教程代码

在本文中,我们全面讨论了线性回归是什么,它的数学直觉以及它的 Python 实现,既可以从头开始,也可以使用 sklearn 库。这个算法很简单直观,因此它有助于初学者打下坚实的基础,同时还能帮助获得使用 Python 进行准确预测的实际编码技能。

感谢您的阅读。 Aryan Garg 是一名电气工程学士学位学生,目前在本科生的最后一年。他的兴趣在于 Web 开发和机器学习领域。他追求这方面的兴趣,并热衷于更多地从事这些方向的工作。

Leave a Reply

Your email address will not be published. Required fields are marked *