线性回归算法实验(最小二乘法)
一、前期准备
1、导出数据集:
我们在进行机器学习各种算法的实验时,遇到的第一个问题都应该是,如何找到需要的数据集,有了数据集我们才能去对相应的数据集进行实验处理。像鸢尾花、波士顿房价等经典的数据集在网上都可以下载到,但是如果每需要一个数据集就都去网上下载的话,也挺麻烦的。这个时候可以用到“sklearn”这个包,这个包里包含了很多机器学习所需的数据集。需要用到某数据集的时候直接从sklearn中导出即可。这个sklearn包也像其他包一样可以在pycharm里直接导入。
- 数据集的导出方法:
import numpy as np
import pandas as pd
from sklearn.datasets import load_boston #从sklearn的数据集中导出波士顿房价的数据集。
data = load_boston()
print(data)
-
在我们导出数据集之后又会遇到新的问题:导出的数据集不经处理的话会显示的很混乱。就如同下图所示:
-
解决数据显示混乱和显示不完整的问题:
import numpy as np import pandas as pd from sklearn.datasets import load_boston # 增加表格的列数行数和每行的宽度以此让数据集完整表示 pd.set_option('display.max_rows', 1000) pd.set_option('display.max_columns', 1000) pd.set_option('display.width', 1000) # 将sklearn数据集转换为csv格式 if __name__ == '__main__': boston = load_boston() data = pd.DataFrame(boston.data, columns=boston.feature_names) data['MEDV'] = boston['target'] data.to_csv('./boston.csv', index=None) print(data)
2、数据集中的各个标签名词解释:
- CRIM:城镇人均犯罪率。
- ZN:住宅用地超过 25000 sq.ft. 的比例。
- INDUS:城镇非零售商用土地的比例。
- CHAS:查理斯河空变量(如果边界是河流,则为1;否则为0)。
- NOX:一氧化氮浓度。
- RM:住宅平均房间数。
- AGE:1940 年之前建成的自用房屋比例。
- DIS:到波士顿五个中心区域的加权距离。
- RAD:辐射性公路的接近指数。
- TAX:每 10000 美元的全值财产税率。
- PTRATIO:城镇师生比例。
- B:1000(Bk-0.63)^ 2,其中 Bk 指代城镇中黑人的比例。
- LSTAT:人口中地位低下者的比例。
- MEDV:自住房的平均房价,以千美元计。
3、对数据进行检测。
-
查看数据的基本信息。同时可以查看各个特征列是否有缺失值。
data.info()
-
检查数据是否有重复
# 检查data里面是否有重复的值 data.duplicated().any()
二、什么是线性回归。
- 线性回归就是用一条直线来解释自变量与因变量之间的关系。
三、算法实现。
- 回归函数:
class LinearRegression:
"""使用Python实现的线性回归(最小二乘法)"""
def fit(self,X,y):
"""根据提供的训练数据X,对模型进行训练。
:parameter
X:类数组类型。形状:[样本数量,特征数量]
特征矩阵,用来对模型进行训练。
y:类数组类型,形状:[样本数量]
"""
# 将X,y转化为矩阵的形式
# 说明:如果X是数组对象的一部分,而不是完整的对象数据(例如:X是由其他对象通过切片传递过来的),
# 则无法完成矩阵的转换。这里创建X的拷贝对象,避免转换矩阵的时候失败
X = np.asmatrix(X.copy())
# y是一维结构(行向量或列向量),一维的格式不需要进行拷贝。
# 注意:我们现在要进行矩阵的运算,因此需要时二维的结构,我们通过reshape的方法进行转换。
y = np.asmatrix(y).reshape(-1, 1) # 只有一列,行数自适应。
# 通过最小二乘公式,求解出最佳的权重值
self.w_ = (X.T * X).I * X.T * y
def predict(self, X):
"""根据参数传递的样本X,对样本数据进行预测。
:parameter
X:类数组类型。形状:[样本数量,特征数量]
待预测的样本特征(属性)。
:return
result:数组类型
预测的结果。
"""
# 将X装换成矩阵,注意要对X进行拷贝。
X = np.asmatrix(X.copy())
result = X * self.w_
# 将矩阵转换成ndarray数组,进行扁平化处理,然后返回结果。
# 使用ravel可以实现扁平化处理
return np.array(result).ravel()
- 进行训练测试并打印结果:
- 不考虑截距:
# 不考虑截距的情况 t = data.sample(len(data),random_state=0) # 训练集 测试集 train_X = t.iloc[:400, :-1] train_y = t.iloc[:400, -1] test_X = t.iloc[400:, :-1] test_y = t.iloc[400:, -1] lr = LinearRegression() # 开始训练 lr.fit(train_X, train_y) # 开始测试 result = lr.predict(test_X) print(result)
- 测试的结果:
测试结果与实际值得误差# 计算一下测试结果与实际结果的误差 print(np.mean((result - test_y) ** 2)) # 查看模型的权重值 print(lr.w_)
- 考虑截距:
- 添加一列值为1的数据将截距w0带入计算:
# 考虑截距:增加一列,让该列的所有值都是1。 t = data.sample(len(data),random_state=0) # 打乱数据顺序 # 按照习惯,截距为w0,我们为之而配上一个x0,x0列放在最前面。 new_columns = t.columns.insert(0, "intercept") # 重新安排列的顺序,如果值为空,则使用fill_value参数指定的值进行填充 t = t.reindex(columns=new_columns, fill_value=1)
- 训练测试:
train_X = t.iloc[:400, :-1] train_y = t.iloc[:400, -1] test_X = t.iloc[400:, :-1] test_y = t.iloc[400:, -1] lr = LinearRegression() # 开始训练 lr.fit(train_X, train_y) # 开始测试 result = lr.predict(test_X) print(result) # 计算一下测试结果与实际结果的误差 print(np.mean((result - test_y) ** 2)) # 查看模型的权重值 print(lr.w_)
- 测试结果:
四、可视化操作
- 实现代码:
# 导入绘图包
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"] = False
# 绘制预测值
plt.plot(result,"ro-", label="预测值")
# 绘制真实值
plt.plot(test_y.values,"go--",label = "真实值")
plt.title("线性回归预测-最小二乘法")
plt.xlabel("样本序号")
plt.ylabel("房价")
plt.legend()
plt.show()
- 最终结果:
五、完整代码。
import numpy as np
import pandas as pd
from sklearn.datasets import load_boston
# 增加表格的列数行数和每行的宽度以此让数据集完整表示
pd.set_option('display.max_rows', 1000)
pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
# 将sklearn数据集转换为csv
if __name__ == '__main__':
boston = load_boston()
data = pd.DataFrame(boston.data, columns=boston.feature_names)
data['MEDV'] = boston['target']
data.to_csv('./boston.csv', index=None)
# # 查看数据的基本信息。同时可以查看各个特征列是否有缺失值。
# data.info()
# # 检查data里面是否有重复的值
# data.duplicated().any()
class LinearRegression:
"""使用Python实现的线性回归(最小二乘法)"""
def fit(self,X,y):
"""根据提供的训练数据X,对模型进行训练。
:parameter
X:类数组类型。形状:[样本数量,特征数量]
特征矩阵,用来对模型进行训练。
y:类数组类型,形状:[样本数量]
"""
# 将X,y转化为矩阵的形式
# 说明:如果X是数组对象的一部分,而不是完整的对象数据(例如:X是由其他对象通过切片传递过来的),
# 则无法完成矩阵的转换。这里创建X的拷贝对象,避免转换矩阵的时候失败
X = np.asmatrix(X.copy())
# y是一维结构(行向量或列向量),一维的格式不需要进行拷贝。
# 注意:我们现在要进行矩阵的运算,因此需要时二维的结构,我们通过reshape的方法进行转换。
y = np.asmatrix(y).reshape(-1, 1) # 只有一列,行数自适应。
# 通过最小二乘公式,求解出最佳的权重值
self.w_ = (X.T * X).I * X.T * y
def predict(self, X):
"""根据参数传递的样本X,对样本数据进行预测。
:parameter
X:类数组类型。形状:[样本数量,特征数量]
待预测的样本特征(属性)。
:return
result:数组类型
预测的结果。
"""
# 将X装换成矩阵,注意要对X进行拷贝。
X = np.asmatrix(X.copy())
result = X * self.w_
# 将矩阵转换成ndarray数组,进行扁平化处理,然后返回结果。
# 使用ravel可以实现扁平化处理
return np.array(result).ravel()
# 不考虑截距的情况
t = data.sample(len(data),random_state=0)
# 训练集 测试集
train_X = t.iloc[:400, :-1]
train_y = t.iloc[:400, -1]
test_X = t.iloc[400:, :-1]
test_y = t.iloc[400:, -1]
lr = LinearRegression()
# 开始训练
lr.fit(train_X, train_y)
# 开始测试
result = lr.predict(test_X)
print(result)
# 计算一下测试结果与实际结果的误差
print(np.mean((result - test_y) ** 2))
# 查看模型的权重值
print(lr.w_)
# 考虑截距的情况:
# 增加一列,让该列的所有值都是1。
t = data.sample(len(data),random_state=0) # 打乱数据顺序
# 按照习惯,截距为w0,我们为之而配上一个x0,x0列放在最前面。
new_columns = t.columns.insert(0, "intercept")
# 重新安排列的顺序,如果值为空,则使用fill_value参数指定的值进行填充
t = t.reindex(columns=new_columns, fill_value=1)
train_X = t.iloc[:400, :-1]
train_y = t.iloc[:400, -1]
test_X = t.iloc[400:, :-1]
test_y = t.iloc[400:, -1]
lr = LinearRegression()
# 开始训练
lr.fit(train_X, train_y)
# 开始测试
result = lr.predict(test_X)
print(result)
# 计算一下测试结果与实际结果的误差
print(np.mean((result - test_y) ** 2))
# 查看模型的权重值
print(lr.w_)
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"] = False
# 绘制预测值
plt.plot(result,"ro-", label="预测值")
# 绘制真实值
plt.plot(test_y.values,"go--",label = "真实值")
plt.title("线性回归预测-最小二乘法")
plt.xlabel("样本序号")
plt.ylabel("房价")
plt.legend()
plt.show()