还是回到上次谈到的线性回归问题,我们知道,回归分析模型可以用
来表示。对应到第
个样本,可得
,其中,
是第
个样本的因变量值,
是自变量值,
则是真实值
和预估值
之间的差异值,也称为误差项值。对于这个模型,我们目标就是要求出
和
这两个参数的值。那么,通常来说,对于这个问题,有两种方法可以求解。第一种是最小二乘法(The Least Squares Method, LSM),而另一种则是最大似然估计(The Maximum Likelihood Estimation, MLE)。LSM是由德国著名的数学家高斯提出的,该计算方法相对简单且易于理解,主要原理是通过最小化误差来寻找函数的
和
最佳估计值。而MLE,是一种由高斯提出并且经过费希尔完善的估计方法,此方法在已知因变量概率分布的情况下,用产生给定样本概率最大的原则使得参数方程能够最大可能性地反映总体状况,从而确定
和
。今次我们主要谈论最小二乘法的具体算法细节。由上述可知,对于第
个样本,我们有
,所以,
。另外,我们的目标是找到一条直线,该直线能够拟合真实数据点,并且使得其与所有数据点的距离总和最小。因此,这个问题就可以等价于最小化
。学过微积分的朋友们肯定很快就会想到我们可以采用全微分的方法求极值来解决这个问题。为了求导的方便,以上问题也等价于求得
的最小值。求解推导过程如下:
对
和
分别求一阶偏导,并且令一阶偏导为0则:
于是,
以及
对以上两式整理可得:
因为二阶偏导的值都大于0,因此,求得所求得
和
是使得
最小的参数值。一旦求得
和
,因变量
就能通过自变量
来确定了。
让我们用Python编码来验证我们算法结果是否与sklearn求解
和
的结果一致。代码如下。
代码计算结果截图为:
其中,求得
,与sklearn计算结果一致。一方面,我们知道确实是可以通过最小二乘法来估计线性回归的参数值,另一方面则说明我们用Python自己实现的算法计算结果是正确的。
import os
import pandas as pd
import numpy as np
class LinearRegressionLSM:
def LSM(self, train_data, feature_names, label_names):
"""
利用训练数据,估计模型参数
参数
----
train_data : DataFrame,训练数据集,包含特征和标签
feature_names : 特征名列表
label_names : 标签名列表
返回
----
alpha, beta : 估计的参数值
"""
n = len(train_data)
X = np.array(train_data[feature_names])
Y = np.array(train_data[label_names])
beta = (n * np.sum(X*Y) - np.sum(X) * np.sum(Y)) / (n * np.sum(X*X) - np.sum(X) * np.sum(X))
alpha = np.sum(Y)/n - beta * (np.sum(X)/n)
return alpha, beta
def linearModel(self, data, feature_names, label_names, split_ratio):
"""
线性回归模型建模步骤展示
参数
----
data : DataFrame,建模数据
"""
# 划分训练集和测试集
trainData = data[:int(len(data) * split_ratio)]
# 产生并用最小二乘法计算
alpha, beta = self.LSM(trainData, feature_names, label_names)
return alpha, beta
def readData(self, path):
"""
使用pandas从CSV读取数据
参数
----
path : 数据的路径
"""
return pd.read_csv(path)
if __name__ == "__main__":
prefixPath = os.path.dirname(os.path.abspath(__file__))
if os.name == "nt":
dataPath = "%sdataincome_vs_consume.csv" % prefixPath
else:
dataPath = "%s/data/income_vs_consume.csv" % prefixPath
feature_names = ["income"]
label_names = ["consume"]
split_ratio = 0.75
lr = LinearRegression_LSM()
data = lr.readData(dataPath)
alpha, beta = lr.linearModel(data, feature_names, label_names, split_ratio)
print(alpha)
print(beta)
更多最新文章请搜索关注微信公众号“阿艾正传”