线性回归(LInear Regression)算法介绍及numpy实现

1. 概述

线性回归:给定数据集 D { ( x i , y i ) , i = 1 , 2 , ⋯   , m } , x i ∈ R n , y i ∈ R D\left \{ (x_{i} ,y_{i}) , i=1, 2, \cdots , m \right \}, x_{i}\in R^{n}, y_{i}\in R D{(xi,yi),i=1,2,,m},xiRn,yiR,基于数据集学习一个线性预测模型 f ( x ) f(x) f(x),使之对于任意的 x i ∈ R n x_{i}\in R^{n} xiRn,尽可能准确预测实值输出 y ^ = f ( x ) \widehat{y} = f(x) y =f(x)

其中模型(预测函数)为线性回归模型: f ( x ) = θ T ⋅ x , f(x) = \theta^{T} \cdot x, f(x)=θTx,其中 θ = [ θ 0 , θ 1 , … , θ n ] T \theta = \left [ \theta_{0}, \theta_{1}, \dots , \theta_{n} \right ] ^{T} θ=[θ0,θ1,,θn]T x = [ x ( 0 ) , x ( 1 ) , … , x ( n ) ] T x = \left [ x^{(0)}, x^{(1)}, \dots , x^{(n)} \right ] ^{T} x=[x(0),x(1),,x(n)]T x ( 0 ) x^{(0)} x(0)始终等于1。

模型使用的代价函数为: J ( Θ ) = 1 2 m ∑ i = 1 m ( f ( x i ) − y i ) 2 , J(\Theta ) = \frac{1}{2m}\sum_{i=1}^{m}(f(x_{i}) - y_{i} ) ^{2}, J(Θ)=2m1i=1m(f(xi)yi)2,该函数为凸函数,只有一个全局最低点。

目标:求得模型的参数 Θ = a r g m i n Θ J ( Θ ) \Theta = \underset{\Theta}{argmin} J(\Theta) Θ=ΘargminJ(Θ)

2. 梯度下降法求解

上一篇文章单独讲了梯度下降法,不了解的可以看一下:梯度下降法求解最优化问题
我们的目标是找到使得代价函数最小的参数向量,最值问题考虑采用梯度下降法求解,该方法主要需要知道代价函数 J ( Θ ) J(\Theta ) J(Θ)对于参数 Θ \Theta Θ的偏导是多少,下面我们假设只有两个参数 θ 0 \theta_{0} θ0 θ 1 \theta_{1} θ1,来求一下各自的偏导。

公式推导

假设只有两个参数,则 f ( x ) = θ 0 + θ 1 x f(x) = \theta_{0} + \theta_{1}x f(x)=θ0+θ1x x ( 0 ) = 1 x^{(0)} = 1 x(0)=1 x ( 1 ) = x x^{(1)} = x x(1)=x.
J ( Θ ) = 1 2 m ∑ i = 1 m ( f ( x i ) − y i ) 2 = 1 2 m ∑ i = 1 m ( θ 0 + θ 1 x i − y i ) 2 \begin{aligned} J(\Theta ) &= \frac{1}{2m}\sum_{i=1}^{m}(f(x_{i}) - y_{i} ) ^{2}\\ &= \frac{1}{2m}\sum_{i=1}^{m}(\theta _{0} + \theta _{1}x_{i} - y_{i} ) ^{2} \end{aligned} J(Θ)=2m1i=1m(f(xi)yi)2=2m1i=1m(θ0+θ1xiyi)2
∂ J ( Θ ) ∂ θ 0 = ∂ 1 2 m ∑ i = 1 m ( θ 0 + θ 1 x i − y i ) 2 ∂ θ 0 = 1 2 m ∑ i = 1 m 2 ( θ 0 + θ 1 x i − y i ) = 1 m ∑ i = 1 m ( f ( x i ) − y i ) = 1 m ∑ i = 1 m ( f ( x i ) − y i ) x i ( 0 ) \begin{aligned} \frac{\partial J(\Theta )}{\partial \theta _{0} } &= \frac{\partial \frac{1}{2m}\sum_{i=1}^{m}(\theta _{0} + \theta _{1}x_{i} - y_{i} ) ^{2}}{\partial \theta _{0}}\\ &= \frac{1}{2m}\sum_{i=1}^{m}2(\theta _{0} + \theta _{1}x_{i} - y_{i})\\ &= \frac{1}{m}\sum_{i=1}^{m}(f(x_{i}) - y_{i})\\ &= \frac{1}{m}\sum_{i=1}^{m}(f(x_{i}) - y_{i})x_{i}^{(0)} \end{aligned} θ0J(Θ)=θ02m1i=1m(θ0+θ1xiyi)2=2m1i=1m2(θ0+θ1xiyi)=m1i=1m(f(xi)yi)=m1i=1m(f(xi)yi)xi(0)
∂ J ( Θ ) ∂ θ 1 = ∂ 1 2 m ∑ i = 1 m ( θ 0 + θ 1 x i − y i ) 2 ∂ θ 1 = 1 2 m ∑ i = 1 m 2 ( θ 0 + θ 1 x i − y i ) x i = 1 m ∑ i = 1 m ( f ( x i ) − y i ) x i = 1 m ∑ i = 1 m ( f ( x i ) − y i ) x i ( 1 ) \begin{aligned} \frac{\partial J(\Theta )}{\partial \theta _{1} } &= \frac{\partial \frac{1}{2m}\sum_{i=1}^{m}(\theta _{0} + \theta _{1}x_{i} - y_{i} ) ^{2}}{\partial \theta _{1}}\\ &= \frac{1}{2m}\sum_{i=1}^{m}2(\theta _{0} + \theta _{1}x_{i} - y_{i})x_{i}\\ &= \frac{1}{m}\sum_{i=1}^{m}(f(x_{i}) - y_{i})x_{i}\\ &= \frac{1}{m}\sum_{i=1}^{m}(f(x_{i}) - y_{i})x_{i}^{(1)} \end{aligned} θ1J(Θ)=θ12m1i=1m(θ0+θ1xiyi)2=2m1i=1m2(θ0+θ1xiyi)xi=m1i=1m(f(xi)yi)xi=m1i=1m(f(xi)yi)xi(1)

推广到n个参数的情况, ∂ J ( Θ ) ∂ θ j = 1 m ∑ i = 1 m ( f ( x i ) − y i ) x i ( j ) \frac{\partial J(\Theta )}{\partial \theta _{j} } = \frac{1}{m}\sum_{i=1}^{m}(f(x_{i}) - y_{i})x_{i}^{(j)} θjJ(Θ)=m1i=1m(f(xi)yi)xi(j)

特征缩放(Feature Scaling)

如果各特征的特征值相差太大,要给数据进行归一化预处理,这样能够加快梯度下降的速率。
给数据做如下变化: x i ′ = x i − μ s , {x}_{i}{}' = \frac{x_{i} - \mu }{s}, xi=sxiμ,其中 μ \mu μ为均值向量, s = { 各 个 特 征 的 m a x − m i n 构 成 的 向 量 标 准 差 向 量 s = \left\{\begin{matrix} 各个特征的max-min构成的向量\\ 标准差向量 \end{matrix}\right. s={maxmin.
注: x 0 x_{0} x0不需要进行缩放, x 0 = 1 x_{0}=1 x0=1.

代码实现

下面我将使用线性回归模型结合批量梯度下降算法拟合波士顿房价数据集。

import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split

def load_data():
    boston = datasets.load_boston()
    dataX = boston.data
    dataY = boston.target
    print("dataX的shape:", dataX.shape)
    return dataX, dataY

def normalization(dataX):
    '''z-score归一化
    Parameters:
        dataX: 输入特征向量
    Returns:
        dataX1: 归一化之后的dataX
        mu: 均值向量
        sigma: 标准差向量
    '''
    mu = dataX.mean(0)
    sigma = dataX.std(0)
    dataX1 = (dataX - mu) / sigma
    return dataX1, mu, sigma

class linear_regression():
    def __init__(self, dataX, dataY, alpha=0.1):
        ones = np.ones((dataX.shape[0], 1))
        self.dataX = np.c_[ones, dataX]
        self.dataY = dataY
        self.datasize = self.dataX.shape[0]
        self.alpha = alpha # 学习率
        self.theta = np.zeros(self.dataX.shape[1]) # 参数初始化
        
    def fit(self):
        iterations = 100 # 设置停止迭代规则,迭代100次就停止更新
        for i in range(iterations):
            y = np.dot(self.dataX, self.theta).reshape(self.datasize,) # 数据集矩阵与参数向量相乘,得到一个向量,为各个样本的预测值
#             print(y)
            loss = 1 / self.datasize * sum((y - self.dataY) ** 2) # 计算平方差损失
            print("第", i, "次迭代,损失为:", loss)
            # 更新theta值
            updated_theta = []
            for j, theta_j in enumerate(self.theta):
                x_j = self.dataX[:, j]
                updated_theta_j = theta_j - self.alpha * (1 / self.datasize) * np.sum((y - self.dataY) * x_j)
                updated_theta.append(updated_theta_j)
            self.theta = np.array(updated_theta)
        print("训练完成!")
        
    def predict(self, testX):
        ones = np.ones((testX.shape[0], 1))
        testX = np.c_[ones, testX]
        y_hat = np.dot(testX, self.theta)
        return y_hat

if __name__ == "__main__":
    # 1.获取数据集
    dataX, dataY = load_data()
    # 2.划分数据集
    trainX, testX, trainY, testY = train_test_split(dataX, dataY, test_size=0.3, random_state=0)
    # 3.标准化预处理
    newTrainX, mu, sigma = normalization(trainX)
    print('mu =', mu, "sigma =", sigma)
    newTestX = (testX - mu) / sigma
    # 4.构建一个线性回归模型
    model = linear_regression(newTrainX, trainY)
    # 5.训练模型
    model.fit()
    # 6.测试模型
    y_hat = model.predict(newTestX)
    # 7.输出预测值与真实值的差距
    print("预测值:", y_hat)
    print("真实值:", testY)
    print("差距:", 1/testX.shape[0] * np.sum((y_hat - testY) ** 2))

代码执行结果:
代码执行结果

3. 正规方程法求解

公式推导

X = [ ( x 1 ) T ( x 2 ) T ⋮ ( x m ) T ] X = \begin{bmatrix} (x_{1})^{T} \\ (x_{2})^{T} \\ \vdots \\ (x_{m})^{T} \end{bmatrix} X=(x1)T(x2)T(xm)T y = [ y 1 y 2 ⋮ y m ] y = \begin{bmatrix} y_{1} \\ y_{2} \\ \vdots \\ y_{m} \end{bmatrix} y=y1y2ym,其中 x i = [ x i ( 0 ) x i ( 1 ) ⋮ x i ( n ) ] ∈ ℜ n + 1 x_{i} = \begin{bmatrix} x_{i}^{(0)} \\ x_{i}^{(1)} \\ \vdots \\ x_{i}^{(n)} \end{bmatrix}\in \Re ^{n+1} xi=xi(0)xi(1)xi(n)n+1
首先给出结果 Θ = ( X T X ) − 1 X T y , \Theta = (X^{T} X)^{-1}X^{T} y, Θ=(XTX)1XTy,下面证明这个结果是正确的:
∵ X Θ = y , Θ = ( X T X ) − 1 X T y ∴ X ( X T X ) − 1 X T y = X X − 1 ( X T ) − 1 X T y = E ⋅ E ⋅ y = y \begin{aligned} &\because X\Theta = y, \Theta = (X^{T} X)^{-1}X^{T} y\\ &\therefore X (X^{T} X)^{-1}X^{T} y\\ &= XX^{-1}(X^{T})^{-1}X^{T}y \\ &= E\cdot E\cdot y\\ &=y \end{aligned} XΘ=y,Θ=(XTX)1XTyX(XTX)1XTy=XX1(XT)1XTy=EEy=y由于式中出现了 ( X T X ) − 1 (X^{T} X)^{-1} (XTX)1,所以要求 X T X X^{T} X XTX必须是可逆的,如果不可逆,则不能使用正规方程法求解。
另外,正规方程法不需要进行特征缩放,直接计算即可。

代码实现

import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split

def load_data():
    boston = datasets.load_boston()
    dataX = boston.data
    dataY = boston.target
    return dataX, dataY

def get_theta(dataX, dataY):
    '''使用正规方程法求解参数
    parameters:
        dataX: shape(m, n)
        dataY: shape(m,)
    Return:
        计算得到的参数向量
        
    用到的numpy中的几个函数:
    1. np.dot(A, B): 矩阵乘法,A为m*n阶, B为n*p阶,运算结果为m*p阶
    2. np.linalg.inv(A): 返回A的逆矩阵
    3. A.T(): 返回A的转置矩阵
    '''
    XTX = np.dot(dataX.T, dataX)
    XTXI = np.linalg.inv(XTX)
    return np.dot(np.dot(XTXI, dataX.T), dataY)

if __name__ == '__main__':
    # 1.加载数据集
    dataX, dataY = load_data()
    # 2.划分数据集
    trainX, testX, trainY, testY = train_test_split(dataX, dataY, test_size=0.3, random_state=0)
    # 3.给特征向量补1
    ones = np.ones((trainX.shape[0], 1))
    trainX = np.c_[ones, trainX]
    # 3.求解参数向量
    theta = get_theta(trainX, trainY)
    # 4.根据求得的参数预测测试集输出
    ones1 = np.ones((testX.shape[0], 1))
    testX = np.c_[ones1, testX]
    n = testX.shape[0]
    y_hat = np.dot(testX, theta)
    loss = 1 / n * np.sum((y_hat - testY) ** 2)
    print('预测值:', y_hat)
    print('真实值:', testY)
    print('差距:', loss)

代码执行结果:
代码执行结果

4. 梯度下降法VS正规方程法

梯度下降法正规方程法
需要选择学习率 α \alpha α不需要选择学习率 α \alpha α
需要很多次迭代不需要迭代
适用于特征数目n较大的情况需要计算 ( X T X ) − 1 (X^{T}X)^{-1} (XTX)1,计算逆矩阵的代价为O( n 3 n^{3} n3)
n = 1 0 6 n = 10^{6} n=106考虑使用梯度下降法 n n n很大时运行很慢,适于 n = 100 , 1000 , 10000 n = 100,1000,10000 n=100,1000,10000

5. 总结

以上就是使用梯度下降法和正规方程法求解线性回归模型的参数的讲解,并且附了相应的代码实现,希望对你有所帮助。
本节涉及到了一些公式的推导,虽然看到公式就头疼,但静下心来看还是非常简单的,希望我们共同进步!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 线性回归是一种统计学方法,可用于预测数值型变量之间的关系,如房价和房屋尺寸之间的关系。在这个场景下,我们考虑通过线性回归来建立一种模型,在已知的房屋尺寸的基础上,预测相应的房价。 假设我们有一个包含有房价和房屋尺寸的数据集,我们可以使用数据探索的工具,如散点图,来初步探索两个变量之间的关系。然后,我们可以使用线性回归模型来拟合这些数据点,并且预测新的房屋尺寸的房价。 接下来,我们将绘制一个图形来展示我们的线性回归模型如何拟合数据点和预测房价。在这张图中,我们将在横轴上表示房屋尺寸,纵轴上表示房价,并绘制出我们的线性回归模型所拟合的直线。这张图将使我们更容易地理解房价和房屋尺寸之间的关系,并且可以用于后续的数据分析以及预测。 在绘制完这张图后,我们可以检查线性回归模型的拟合精度。如果线性回归模型在数据集中存在显著的偏差,就需要重新考虑预测模型,或者增加更多的特征变量,这样可以使预测的结果更准确。此外,在应用线性回归模型之前,我们还应该注意一些其他的影响因素,如噪声或异常值,这样可以避免模型的偏差以及其他的预测错误。 ### 回答2: 线性回归是一种常用的机器学习算法,可以用于预测房价等连续值的问题。具体地说,线性回归就是通过找到一条直线(或者超平面,在高维空间中)来尽可能地拟合已知数据,然后利用这条直线进行预测。 在房价预测的问题中,我们可以使用线性回归算法来构建一个模型。首先,我们需要收集一些房价相关的数据,例如房屋面积、地理位置、年龄等等。然后,我们可以使用这些数据来训练线性回归模型,找到一个最优的线性函数,使得它最好地拟合已有的数据。 训练模型之后,我们就可以利用这个模型来进行预测。比如,我们输入某个房屋的面积、位置等信息,就可以利用模型预测这个房屋的价格了。 为了更加直观地理解线性回归算法,我们可以绘制出数据点和拟合直线的图像。在这个图像中,我们可以看到每一个数据点的位置,以及拟合直线的位置,这样可以更加方便地理解线性回归算法的表现。 总之,线性回归是一种非常实用的机器学习算法,它可以帮助我们解决很多连续值预测的问题,例如房价预测等。同时,在理解线性回归算法的时候,我们可以通过绘制图像来更好地理解模型的表现。 ### 回答3: 线性回归是一种广泛用于预测连续数值的统计学方法,常用于房价预测。我们可以通过已知的房屋面积、房龄等特征,拟合出一个数学函数,进而计算出未知房屋的价格。下面我将简单介绍如何使用Python中的scikit-learn库进行线性回归分析,以及如何绘制预测结果的图像。 首先,我们需要加载数据并探索数据的基本特征。数据可以从Kaggle等网站下载得到。以Boston House Price数据集为例,我们可以通过Pandas库读入数据并查看前几行数据的情况: ``` import pandas as pd df = pd.read_csv('train.csv') print(df.head()) ``` 接下来,我们需要针对数据的特征选择适当的模型进行拟合。这里我们选取最简单的线性回归模型。通过scikit-learn库中的LinearRegression模块,可以方便地进行模型训练。 ``` from sklearn.linear_model import LinearRegression X = df[['RM', 'LSTAT', 'PTRATIO']] # 我们选择房间数量、低收入人群比例以及学生与教师之比三个特征来预测房价 y = df['MEDV'] lr = LinearRegression() lr.fit(X, y) # 模型拟合 ``` 至此,我们已经拟合出了一个模型,可以使用测试数据集进行预测并计算模型的评估指标,例如均方误差(Mean Squared Error,MSE)等。同时,我们还可以通过matplotlib库绘制出预测结果的图像: ``` import matplotlib.pyplot as plt import numpy as np import seaborn as sns sns.set(style='whitegrid', context='notebook') pred_y = lr.predict(X) plt.scatter(y, pred_y) plt.plot([0, 50], [0, 50], '--k') plt.xlabel('True value') plt.ylabel('Predicted value') ``` 在图像中,横坐标代表真实房价,纵坐标代表预测房价。可以看到,预测结果与真实情况的差异较小,说明模型的拟合效果较好。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值