前沿:
先学习本篇文章之前,建议大家先学习我编写的上一篇“使用Python从头实现一个神经网络”,再来学习学习本篇使用神经网络进行房价预测。
介绍:
本次使用神经网络进行房价的预测,利用数据样本学习,得到相关因素预测房价。
数据介绍:
数据来源:
使用爬虫工具爬取广州某小区的售房信息。爬取到的数据如下:
选取变量
共有380条数据,七项指标,选取其中五项指标,分别为总价,面积、房间数量、客厅数量、建造年份。
选取房子总价为预测变量,面积、房间数量、客厅数量、建造年份为输入变量。
数据处理
对数据进行标准化,标准化方程如下:
其中,x'为标准化后的数值,x为原数值,
为该变量的平均值,
为变量的最大值。例如:x代表总价变量,
为所有总价的平均值,也就是Excel中第一列的平均值,
为最高的总价。
神经网络结构:
本次的选用的神经网络结构如下:
我们的神经网络结构较为简单,隐藏层为一层,隐藏层节点数为2,两个偏置单元。
函数说明:
输入层到隐藏层(sigmoid):
隐藏层到输出层(回归函数):
代价函数:
之所以隐藏层到输出层的函数改为回归函数,是因为我们不再使用神经网络进行分类,而是预测。
分类问题得到的输出结果是[0,1]之间,因此使用sigmoid函数;而我们预测的结果是一个大范围的值。
比如我们预测到的房价可能是100万,也可能是500万,因此使用多元回归函数。
这么做的意义,在于我们将原先的四个变量,重新转化为了隐藏层中的两个节点。再利用两个节点,进行多元线性回归。不再使用原先的四个变量直接多元回归,这也是隐藏层的意义。
ps:有人可能看过吴恩达的机器学习视频(强烈推荐),代价函数使用的是另一种形式。那是因为神经网络用于分类时,输出节点在[0,1]之间,使用那种形式可以学习的更好。
反向传播和梯度下降:
由于上一篇已经将反向传播和梯度下降讲的很清楚了,因此不再重复。我们使用学习率为α=0.01时,将380条数据迭代1000次,每10次输出一次代价函数值,得到损失值和迭代次数如下图:
可以看到,损失值在下降,说明学习率选取较好(几次中比较好的一次)。
预测房价和实际房价对比
以380个数据样本为横坐标,房子总价为纵坐标。下图中红色散点为数据样本中真实房价,蓝色散点为预测房价,得到如下所示的散点图。
可以看到,预测房价和实际房价大致呈现吻合关系,说明模型大致正确。
最后:
由于本人为神经网络的初学者, 可能存在解释不清楚甚至错误的地方,希望大家多多指教。
如果大家想深入机器学习,可以观看吴恩达的机器学习视频,或者周志华的机器学习西瓜书(个人推荐)
我将我的数据和代码放在了我的github上,大家如果需要数据和代码,可以前往下载。
附件:代码
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
def sigmoid(x):
# 第一层到第二层的激活函数
return 1 / (1 + np.exp(-x))
def deriv_sigmoid(x):
# 第一层到第二层的激活函数的求导函数
fx = sigmoid(x)
return fx * (1 - fx)
def mse_loss(y_true, y_pred):
# 使用方差作为损失函数
return ((y_true - y_pred) ** 2).mean()
class OurNeuralNetwork:
def __init__(self):
# 第一层到第二层的函数
self.w11 = np.random.normal()
self.w12 = np.random.normal()
self.w13 = np.random.normal()
self.w14 = np.random.normal()
self.w21 = np.random.normal()
self.w22 = np.random.normal()
self.w23 = np.random.normal()
self.w24 = np.random.normal()
# 第二层到第三层的函数
self.w1 = np.random.normal()
self.w2 = np.random.normal()
# 截距项,Biases
self.b1 = np.random.normal()
self.b2 = np.random.normal()
self.b3 = np.random.normal()
def feedforward(self, x):
# 前向传播学习
h1 = sigmoid(self.w11 * x[0] + self.w12 * x[1] + self.w13 * x[2] + self.w14 * x[3] + self.b1)
h2 = sigmoid(self.w21 * x[0] + self.w22 * x[1] + self.w23 * x[2] + self.w24 * x[3] + self.b1)
o1 = self.w1 * h1 + self.w2 * h2 + self.b3
return o1
#训练函数
def train(self, data, all_y_trues):
learn_rate = 0.01 # 学习率
epochs = 1000 # 训练的次数
# 画图数据
self.loss = np.zeros(100)
self.sum = 0;
# 开始训练
for epoch in range(epochs):
for x, y_true in zip(data, all_y_trues):
# 计算h1
h1 = sigmoid(self.w11 * x[0] + self.w12 * x[1] + self.w13 * x[2] + self.w14 * x[3] + self.b1)
# 计算h2
h2 = sigmoid(self.w21 * x[0] + self.w22 * x[1] + self.w23 * x[2] + self.w24 * x[3] + self.b2)
#计算输出节点
y_pred = self.w1 * h1 + self.w2 * h2 + self.b3
# 反向传播计算导数
d_L_d_ypred = -2 * (y_true - y_pred)
d_ypred_d_w1 = h1
d_ypred_d_w2 = h2
d_ypred_d_b3 = 0
d_ypred_d_h1 = self.w1
d_ypred_d_h2 = self.w2
sum_1=self.w11 * x[0] + self.w12 * x[1] + self.w13 * x[2] + self.w14 * x[3] + self.b1
d_h1_d_w11 = x[0] * deriv_sigmoid(sum_1)
d_h1_d_w12 = x[1] * deriv_sigmoid(sum_1)
d_h1_d_w13 = x[2] * deriv_sigmoid(sum_1)
d_h1_d_w14 = x[3] * deriv_sigmoid(sum_1)
d_h1_d_b1 = deriv_sigmoid(sum_1)
sum_2 = self.w21 * x[0] + self.w22 * x[1] + self.w23 * x[2] + self.w24 * x[3] + self.b2
d_h1_d_w21 = x[0] * deriv_sigmoid(sum_2)
d_h1_d_w22 = x[1] * deriv_sigmoid(sum_2)
d_h1_d_w23 = x[2] * deriv_sigmoid(sum_2)
d_h1_d_w24 = x[3] * deriv_sigmoid(sum_2)
d_h1_d_b2 = deriv_sigmoid(sum_2)
# 梯度下降法
self.w11 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w11
self.w12 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w12
self.w13 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w13
self.w14 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_w14
self.b1 -= learn_rate * d_L_d_ypred * d_ypred_d_h1 * d_h1_d_b1
self.w21 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h1_d_w21
self.w22 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h1_d_w22
self.w23 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h1_d_w23
self.w24 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h1_d_w24
self.b2 -= learn_rate * d_L_d_ypred * d_ypred_d_h2 * d_h1_d_b2
self.w1 -= learn_rate * d_L_d_ypred * d_ypred_d_w1
self.w1 -= learn_rate * d_L_d_ypred * d_ypred_d_w2
self.b3 -= learn_rate * d_L_d_ypred * d_ypred_d_b3
if epoch % 10 == 0:
y_preds = np.apply_along_axis(self.feedforward, 1, data)
loss = mse_loss(all_y_trues, y_preds)
print("Epoch %d loss: %.3f" % (epoch, loss))
self.loss[self.sum] = loss
self.sum = self.sum + 1
# 文件的名字
FILENAME = "../data.xlsx"
# 禁用科学计数法
pd.set_option('float_format', lambda x: '%.3f' % x)
np.set_printoptions(suppress=True, threshold=np.nan)
# 得到的DataFrame分别为总价、面积、房间、客厅、年份
data = pd.read_excel(FILENAME, header=0, usecols="A,D,H,I,J")
# DataFrame转化为array
DataArray = data.values
Y = DataArray[:, 0]
X = DataArray[:, 1:5]
X = np.array(X)#转化为array,自变量
Y = np.array(Y)#转化为array,因变量房价
# 处理数据
data = np.array(X)
data_mean = np.sum(data, axis=0) / np.size(data, 0)
data = (data - data_mean) / np.max(data)
all_y_trues = np.array(Y)
all_y_trues_mean = np.sum(all_y_trues) / np.size(all_y_trues)
all_y_trues = (all_y_trues - all_y_trues_mean) / np.max(all_y_trues)
# 训练数据
network = OurNeuralNetwork()
network.train(data, all_y_trues)
# 输出神经网络参数
print("w11-->%.3f" % network.w11)
print("w12-->%.3f" % network.w12)
print("w13-->%.3f" % network.w13)
print("w14-->%.3f" % network.w14)
print("w21-->%.3f" % network.w21)
print("w22-->%.3f" % network.w22)
print("w23-->%.3f" % network.w23)
print("w24-->%.3f" % network.w24)
print("w1-->%.3f" % network.w1)
print("w2-->%.3f" % network.w2)
print("b1-->%.3f" % network.b1)
print("b2-->%.3f" % network.b2)
print("b3-->%.3f" % network.b3)
# 标题显示中文
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 测试数据
testData = np.array([99, 3, 2, 2014])
testPrice = network.feedforward(testData)
# 损失函数曲线图
plt.plot(np.arange(100), network.loss)
plt.show()
# 真实值与预测值对比
y_preds = np.apply_along_axis(network.feedforward, 1, data)
plt.plot(np.arange(380), all_y_trues,"r^")
plt.plot(np.arange(380),y_preds,"bs")
plt.title("红色为真实值,蓝色为预测值")
plt.show()