Paddle_房价预测
本文采用paddle深度学习框架进行房价预测,包含一些其他第三方库,波士顿房价预测问题作为机器学习领域的“hello world”。本文有利于读者更好地理解并入门,为以后更深程度的学习打下良好的基础。
前言:
波士顿房价数据集源于美国某经济学杂志上,分析研究波士顿 房价的数据集。该数据集中的每一行数据都是对波士顿周边或者城镇 的房价情况的概述,统计的是房价的中位数和 13 个指标,试图能够 分析出这些指标和房价之间的关系。本文主要以数据预处理,损失函数,梯度计算,反向传播更新参数展开,具体介绍这几个步骤在代码中的体现。
一,数据处理:
读入数据集:
该数据处理与前文Numpy_房价处理操作完全一样,以阅读过前文的读者可自行跳过。本文采用housing.data数据集。数据集的格式如图所示,该数据集共有506个样本,每个样本包含13个特征值和1个与之对应的标签。如图所示:

该数据集共有506行14列的数据,每一行数据代表一个样本(每个样本里包含14的数据),前13列分别对应13个特征值,最后一列为各个样本值对应的标签,即房价,所有数据均已空格分开。
datafile = 'housing.data'data = np.fromfile(datafile, sep=' ')
其中'housing.data'为路径名,我的直接放在了本文件夹下。并赋值给datafile
np.fromfile表示读取该路径下的文件,sep = ''表示以空格分隔。此时data为一个1行7084列的向量。

数据维度转换:
由于读入的原始数据是1维的。因此需要我们将数据的形状进行变换,形成一个2维的矩阵,每行为一个数据样本(14个值),每个数据样本包含13个特征值(影响房价的特征)和一个对应的标签(该类型房屋的均价)。
# 读入之后的数据被转化成1维array,其中array的第0-13项是第一条数据,第14-27项是第二条数据,以此类推....
# 这里对原始数据做reshape,变成N x 14的形式
feature_names = [ 'CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE','DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV' ]
feature_num = len(feature_names)
data = data.reshape([data.shape[0] // feature_num, feature_num])
feature_names为一个列表,内有14个值,前13个元素代表对应的特征向量,最后一个元素为标签。每个特征向量的含义如下图所示:

feature_number = len(feature_names),用len函数求出特征值的数量并赋值给feature_number,为14(包含标签),data.shape表示求data的维度为一维(7084,),data.shape[0]即为7084,所以data.shape[0]对feature_number(14)取余,得到506;所以data的维度为[506,14]。data为506行,14列的二维矩阵。
区分训练集和测试集,通常取总样本数的80%作为训练集,剩余的20%作为测试集。
代码如下:
ratio = 0.8
offset = int(data.shape[0] * ratio)
training_data = data[:offset]
test_data = data[offset:]
对data进行切片处理,offset为整形变量,代表506*0.8。data[:offset]是指对二维矩阵的第一维进行切片处理,第二维不变。得到的training_data和test_data分别为404行14列的矩阵和102行14列的矩阵。
数据归一化处理:
对每个特征进行归一化处理,使得每个特征的取值缩放到0~1之间。
这样做有两个好处:
一是模型训练更高效;
二是特征前的权重大小可以代表该变量对预测结果的贡献度(因为每个特征值本身的范围相同)
代码如下:
# 计算train数据集的最大值,最小值,平均值
maximums, minimums, avgs = \training_data.max(axis=0), \training_data.min(axis=0), \training_data.sum(axis=0) / training_data.shape[0]
# 对数据进行归一化处理
for i in range(feature_num):#print(maximums[i], minimums[i], avgs[i])data[:, i] = (data[:, i] - minimums[i]) / (maximums[i] - minimums[i])
首先求出每一个特征值的最大值,最小值和平均值并分别赋值给maximums, minimums, avgs。即对所有的列分别求出每列的最大值,最小值和平均值。.max()函数可以求出最大值,但由于training_data是一个404行14列的矩阵,而我们分别求出每一列的最大值,最小值和平均值。所以要指定维度为0,即对列求。 (axis=0),若不指定,则对所有数据求最大值。.min()函数同理。 training_data.sum(axis=0)表示对每一列求和最后得到一个1行14列的矩阵,每一个数据为对应每一列所有行数之和。training_data.shape表示[404,14],其中0表示第一个元素。training_data.shape[0]表示404,二者之比自然为平均数。
之后的for循环表示依次遍历每一列,由于data是506行,14列的矩阵,所以循环里面用到切片操作data[:, i] = (data[:, i] - minimums[i]) / (maximums[i] - minimums[i])。其中data[:, i] 表示506行,第i列的矩阵,minimums[i]表示第i列的最小值,maximums[i]表示第i列的最大值。经过此处理后,便可使所有数据均在0-1之间。
代码封装成类:
import numpy as np
def load_data():# 从文件导入数据datafile = 'housing.data'data = np.fromfile(datafile, sep=' ')# 每条数据包括14项,其中前面13项是影响因素,第14项是相应的房屋价格中位数feature_names = [ 'CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', \'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV' ]feature_num = len(feature_names)# 将原始数据进行Reshape,变成[N, 14]这样的形状data = data.reshape([data.shape[0] // feature_num, feature_num])# 将原数据集拆分成训练集和测试集# 这里使用80%的数据做训练,20%的数据做测试# 测试集和训练集必须是没有交集的ratio = 0.8offset = int(data.shape[0] * ratio)training_data = data[:offset]# 计算训练集的最大值,最小值,平均值maximums, minimums, avgs = training_data.max(axis=0), training_data.min(axis=0), \training_data.sum(axis=0) / training_data.shape[0]# 对数据进行归一化处理for i in range(feature_num):#print(maximums[i], minimums[i], avgs[i])data[:, i] = (data[:, i] - minimums[i]) / (maximums[i] - minimums[i])# 训练集和测试集的划分比例training_data = data[:offset]test_data = data[offset:]return training_data, test_data
二,模型设计
线性回归:
模型设计是深度学习模型关键要素之一,也称为网络结构设计,相当于模型的假设空间,即实现模型“前向计算”(从输入到输出)的过程。本文只讨论线性回归,线性回归是利用数理统计中回归分析,来确定两种或两种以上 变量间相互依赖的定量关系的一种统计分析方法。它对一个或多个自 变量与因变量之间的关系进行建模,得出的函数是一个或多个称为回 归系数的模型参数的线性组合。用一个方程式来表示如下: 𝑦 = 𝜔𝑖𝑥𝑖 + 𝑏 𝑖 = 0,1, …
线性回归要解决的问题便是得出最佳的拟合线,建立自变量与 因变量之间的关系,获得该条最佳拟合线可以通过使用最小二乘法来 解决。对于观测数据,它通过最小化每一个数据点到线的垂直偏差平 方和来计算最佳拟合线。线性回归的目标函数如下: 𝑚𝑖𝑛 𝜔 ‖𝑋𝜔 − 𝑦‖ 2
前向传播:
将上述计算预测输出的过程以“类和对象”的方式来描述,类成员变量有参数w和b。通过写一个forward函数(代表“前向计算”)完成上述从特征和参数到输出预测值的计算过程,代码如下所示。
class Regressor(paddle.nn.Layer):# self代表类的实例自身def __init__(self):# 初始化父类中的一些参数super(Regressor, self).__init__()# 定义一层全连接层,输入维度是13,输出维度是1self.fc = Linear(in_features=13, out_features=1)# 网络的前向计算def forward(self, inputs):x = self.fc(inputs)return x
首先定义一个Regression类,并继承paddle.nn.Layer类。
in_features 表示输入神经元个数
out_features 表示输出神经元个数
forward函数输入inputs表示输入的数据(即13个特征值对应的数据),经过一层全连接层,最后输出的x即为前向传播预测的x(预测房价)。
设置优化算法:
优化算法包含很多种,这里我们采用SGD随机梯度下降,并调用paddleAPI。
代码如下:
opt = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())
learning表示学习率,即沿梯度反方向走的步长,parameters表示对哪一个特征向量采用SGD随机梯度下降,这里不做设置,表示对所有权重均采用。
训练前准备:
# 声明定义好的线性回归模型
model = Regressor()
# 开启模型训练模式
model.train()
# 加载数据
training_data, test_data = load_data()
EPOCH_NUM = 10 # 设置外层循环次数
BATCH_SIZE = 10 # 设置batch大小
首先实例化一个类model,model.train表示模型进入训练状态。并设置迭代10轮,表示所有数据使用十次,设置batch的大小为10,每次像模型输入10个样本数据。
三,开始训练
# 定义外层循环
for epoch_id in range(EPOCH_NUM):# 在每轮迭代开始之前,将训练数据的顺序随机的打乱np.random.shuffle(training_data)# 将训练数据进行拆分,每个batch包含10条数据mini_batches = [training_data[k:k + BATCH_SIZE] for k in range(0, len(training_data), BATCH_SIZE)]# 定义内层循环for iter_id, mini_batch in enumerate(mini_batches):x = np.array(mini_batch[:, :-1]) # 获得当前批次训练数据y = np.array(mini_batch[:, -1:]) # 获得当前批次训练标签(真实房价)# 将numpy数据转为飞桨动态图tensor形式house_features = paddle.to_tensor(x)prices = paddle.to_tensor(y)# 前向计算predicts = model(house_features)# 计算损失loss = F.square_error_cost(predicts, label=prices)avg_loss = paddle.mean(loss)if iter_id % 20 == 0:print("epoch: {}, iter: {}, loss is: {}".format(epoch_id, iter_id, avg_loss.numpy()))# 反向传播avg_loss.backward()# 最小化loss,更新参数opt.step()# 清除梯度opt.clear_grad()
首先定义外层循环,循环十次。np.random.shuffle表示对数据乱序,提高模型的真实预测能力,mini_batches表示一个列表,该列表每个元素还是一个列表,次列表内表示十组样本值,并用for循环一次遍历所有数据。x,y分别表示对应的样本数据和标签,此时的x和y还是np.array的数据类型,因为我们之前使用的是paddleAPI,首先要将数据类型转化为paddle所支持的格式,paddle.to_tensor表示将一个numpy格式转化为tensor格式。
该过程的损失函数采用均方误差的形式,采用paddleAPLsquare_error_cost两个对应的菜蔬分别为模型的预测值和对应的真实值。
后面依次调用反向传播,最小化loss,更新参数分别对应的函数
四,模型的保存.
paddle.save(model.state_dict(), 'LR_model.pdparams')
调用paddleAPI save第一个参数表示保存模型参数为字典类型,第二个为保存的路径。
五,模型测试
def load_one_example():# 从上边已加载的测试集中,随机选择一条作为测试数据#idx = np.random.randint(0, test_data.shape[0])idx = -10one_data, label = test_data[idx, :-1], test_data[idx, -1]# 修改该条数据shape为[1,13]one_data = one_data.reshape([1, -1])return one_data, labelmodel_dict = paddle.load('LR_model.pdparams')
model.load_dict(model_dict)
model.eval()# 参数为数据集的文件地址
one_data, label = load_one_example()
# 将数据转为动态图的variable格式
one_data = paddle.variable(one_data)
predict = model(one_data)# 对结果做反归一化处理
predict = predict * (max_values[-1] - min_values[-1]) + avg_values[-1]
# 对label数据做反归一化处理
label = label * (max_values[-1] - min_values[-1]) + avg_values[-1]print("Inference result is {}, the corresponding label is {}".format(predict.numpy(), label))
运行结果如下:

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
