线性回归
任务1. 一元线性回归
任务介绍:
- 自定义一元回归函数MyLinearRegression(),输入参数为x和y的数组xArr和yArr,输出为参数w1和w0,利用最小二乘法求得参数;
- 使用美国医疗保险费数据insurance.csv中的输入特征age和目标特征charges,输入MyLinearRegression()函数,得到回归参数值w1和w0,并保留到小数点后两位;
- 调用sklearn的LinearRegression()函数,比较其运行结果与上述自定义函数MyLinearRegression()的输出结果是否一致。
- 利用age与charges绘制真实样本点,利用w1与w0计算预测值,再绘制age与预测值的点图,观察真实样本点与预测点之间的拟合程度。
补全代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression
insurance = pd.read_csv('insurance.csv') age = insurance['age'].values charges = insurance['charges'].values
def MyLinearRegression(xArr, yArr): mean_x = xArr.mean() mean_y = yArr.mean() numerator = np.sum((xArr - mean_x) * (yArr - mean_y)) denominator = np.sum((xArr - mean_x)**2) w1 = numerator / denominator w0 = mean_y - w1 * mean_x return round(w0,2), round(w1,2) print("模型训练,得到参数值") w0, w1 = MyLinearRegression(age, charges) print(w1,'\n', w0)
print("sklearn的训练结果") lr = LinearRegression()
lr.fit(age.reshape(-1, 1), charges) print(round(lr.coef_[0],2)) print(round(lr.intercept_,2))
plt.scatter(age, charges, marker='.')
plt.scatter(age, w1 * age + w0, marker='+') plt.show()
|
模型训练,得到参数值
257.72
3165.89
sklearn的训练结果
257.72
3165.89
png
最小二乘法求解公式
目标:最小化预测值与真实值的平方误差之和: $$ \min_{w_0, w_1} \sum_{i=1}^n (y_i - \hat{y}_i)^2
$$
闭式解(Normal Equation):
1. 斜率 ( w_1 ):
$$ w_1 = \frac{\sum_{i=1}^n (x_i -
\bar{x})(y_i - \bar{y})}{\sum_{i=1}^n (x_i - \bar{x})^2} $$
其中 ({x}) 和 ({y}) 分别是 (x) 和 (y) 的均值。
- 截距 ( w_0 ):
w0 = ȳ − w1x̄
round(w0, 2) 和 round(w1, 2)
的作用是对线性回归模型的参数进行四舍五入处理,保留两位小数。
这段代码使用 scikit-learn 的
LinearRegression
类实现线性回归,并输出模型参数。以下是逐行解释: ### 1.
创建线性回归模型实例 -
LinearRegression() 是 scikit-learn
中用于线性回归的类。 - lr
是该类的一个实例,后续通过它调用模型训练、预测等方法。 ### 2.
模型训练 1
| lr.fit(age.reshape(-1, 1), charges)
|
-
作用:用输入数据 age(特征)和
charges(目标值)训练线性回归模型。 -
关键细节: - age 是一维数组(形状如
(n,)),但 scikit-learn
要求输入特征为二维数组(形状如 (n, 1))。 -
age.reshape(-1, 1)
将一维数组转换为二维列向量(n 行 1 列),确保输入格式正确。
- charges 是目标值的一维数组,无需调整形状。 ### 3.
输出模型参数 1 2
| print(round(lr.coef_[0], 2)) print(round(lr.intercept_, 2))
|
-
lr.coef_: - 存储模型的回归系数(即
w1,特征权重)。 - 对于一元线性回归,coef_
是一个包含单个元素的数组(如 [w1]),因此用
coef_[0] 提取数值。 -
lr.intercept_: - 存储模型的截距项(即
w0)。 - 直接通过 intercept_ 访问,无需索引。
-
round(..., 2):将参数四舍五入保留两位小数,便于与自定义函数结果对比。
任务2. 多元线性回归
任务介绍:
- 自定义多元线性回归函数MyLinearRegression2(),输入参数为X和y的数组xArr和yArr,输出为参数ws,利用最小二乘法求得参数;
- 使用美国医疗保险费数据insurance.csv中的输入特征age、bmi和children,目标特征charges,根据MyLinearRegression2()函数,得到回归参数值ws;注意判断(X^T
X)^{-1}是否为满秩,如果满秩,则引入正则项,参数为alpha,目标函数变为岭回归问题。
- 为了得到模型的截距,需要在矩阵X最后增加一列,并且该列所有行的值均为1。
- 调用sklearn的LinearRegression()函数,比较其运行结果与上述自定义函数MyLinearRegression2()的输出结果是否一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| from sklearn.linear_model import LinearRegression import numpy as np from numpy import linalg, column_stack, ones, array import pandas as pd insurance = pd.read_csv('insurance.csv')
def MyLinearRegression2(xArr, yArr): xMat = np.asmatrix(xArr) yMat = np.asmatrix(yArr).T xTx = xMat.T*xMat if linalg.det(xTx) < 1e-8: print( "singular matrix, can't do inverse") alpha = 0.1 xTx += alpha * np.eye(xMat.shape[1])
ws = xTx.I * (xMat.T * yMat) return ws
X = insurance[['age', 'bmi', 'children']].values
X = column_stack((X, ones(X.shape[0]))) y = insurance['charges'] ws = MyLinearRegression2(X, y) print("自定义的训练结果") print(ws)
lr = LinearRegression(fit_intercept=False)
lr.fit(X, y) print("sklearn的训练结果") print(lr.coef_) print(lr.intercept_)
|
自定义的训练结果
[[ 239.99447429]
[ 332.0833645 ]
[ 542.86465225]
[-6916.24334779]]
sklearn的训练结果
[ 239.99447429 332.0833645 542.86465225 -6916.24334779]
0.0
任务3.
线性回归应用:预测医疗费用
任务介绍
- 对insurance.csv中的名义型特征进行One-Hot编码,得到了数据变量insurance
- 请使用自定义的多元回归函数MyLinearRegression2()得到回归模型参数ws和预测值y_pred,并计算R2分数
- 比较使用sklearn进行模型训练和模型评价R2分数的结果
复用上一节实验中实现的代码,可以复制粘贴代替下面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| import pandas as pd import numpy as np from sklearn import linear_model, metrics from numpy import array, mean, ones import matplotlib.pyplot as plt
insurance = pd.read_csv('insurance.csv') insurance = pd.get_dummies(insurance, drop_first=True) print(insurance.shape)
X = insurance.drop(['charges'], axis=1).values.astype(np.float64) y = insurance['charges'].values.astype(np.float64)
plt.figure(figsize=(20,10)) for i in range(X.shape[1]): plt.subplot(2,6,i+1) plt.scatter(array(X)[:,i],y,s=20) plt.show()
def MyLinearRegression2(xArr, yArr): xMat = np.asmatrix(xArr) yMat = np.asmatrix(yArr).T xTx = xMat.T*xMat if np.linalg.det(xTx) < 1e-8: print( "singular matrix, can't do inverse") alpha = 0.1 xTx += alpha * np.eye(xMat.shape[1])
ws = xTx.I * (xMat.T * yMat) return ws
ws = MyLinearRegression2(X, y) y_pred = X.dot(ws) y_pred = array(y_pred).reshape(y_pred.shape[0],)
score = metrics.r2_score(y, y_pred)
lr = linear_model.LinearRegression(fit_intercept=False)
lr.fit(X, y)
y_pred_sk = lr.predict(X) score_sk = metrics.r2_score(y, y_pred_sk) print(score_sk)
|
(1338, 9)
png
0.7235368166092777