昨天已经跟着慕课完成了一个最简单的机器学习实例:线性回归。而且是只有一个变量的,不过通过那个例子我已经理解了机器学习的基本步骤,如何创建数据集、如何创建模型、如何训练模型、如何用训练好的模型进行预测等等。
接下来我又跟着慕课做了一个多元线性回归的实例:波士顿房价的预测。这里的变量就不是一个了,而是12个,这样我们就必须使用到多元线性回归的问题。
关于慕课的学习,我是在中国大学mooc上学习的,课程名称是:深度学习应用开发-TensorFlow实践,有兴趣可以去学习一下,我觉得讲解的很详细,而且会带着把每一句代码讲解一遍,适合初学者。
1、问题分析与数据下载
话不多说,接下来开始分析这个实例的实现,首先我们需要获取数据集,是一个.csv的文件,里面存储了506条房子的信息,相当于一个506*13的二维矩阵,前12列为房价的一些决定因素,第13列为房价,我们现在的目的就是利用给出的12个决定房价的因素来训练一个模型预测波士顿的房价。
百度网盘
数据链接:https://pan.baidu.com/s/1sYvOqrGGqrq3tindgCyytg
提取码:e582
2、读取数据与归一化处理
在下载好数据之后,把它放到我们当前项目的文件夹之后,就可以利用相应的包将文件读取出来了,利用到了pandas包,读取之后我们还可以看到数据的描述性信息;
当读取完数据之后,由于是列表形式,我们需要利用numpy将列表转换为数组,因为我们后面需要利用矩阵的一些运算特性;
接着就是对特征值进行归一化处理,因为不同的特征值的相差可能会很大,有的甚至会达到几百倍,这个时候我们就需要将他们进行归一化,都化为[0, 1]之间的数,这样就可以消除数值差异带来的影响。
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd # 读取文件的库
from sklearn.utils import shuffle # “洗牌”函数(打乱数据)
# 读取数据文件
df = pd.read_csv("data/boston.csv", header=0)
# 显示数据摘要描述信息
print(df)
print(df.describe())
# 获取df的值
df = df.values
# 把df转换为 np 的数组格式
df = np.array(df)
# print(df)
# 特征数据的归一化
for i in range(12):
df[:, i] = df[:, i]/(df[:, i].max() - df[:, i].min())
# x_data 为前12列特征值
x_data = df[:, :12]
# y_data 为第13列标签数据
y_data = df[:, 12]
print(x_data, '\n shape=', x_data.shape)
print(y_data, '\n shape=', y_data.shape)
对文件中的数据进行描述性统计:
3、创建模型
对于模型的创建,大致的步骤和前面的一元线性回归是一样的,只不过现在是多元的,需要利用矩阵的叉乘进行运算,涉及到线性代数矩阵的叉乘知识。
还有一点不同的就是这里定义了一个命名空间,其实就是对创建模型这一部分的代码进行了一个打包,方便后面的管理,当然这里不打包也是可以的。
x = tf.placeholder(tf.float32, [None, 12], name="X") # 12个特征数据
y = tf.placeholder(tf.float32, [None, 1], name="Y") # 1个标签数据
# 定义模型函数
# 定义一个命名空间(将以下语句进行打包)
with tf.name_scope("Model"):
# w 初始化值为shape=(12, 1)的随机数
w = tf.Variable(tf.random_normal([12, 1], stddev=0.01), name="W")
# b 初始值为1
b = tf.Variable(1.0, name="b")
# w和x是矩阵相乘,用matmul,不能用mutiply或者*
def model(x, w, b):
return tf.matmul(x, w) + b
# 预测计算操作,前向计算节点
pred = model(x, w, b)
4、模型训练
当创建好模型之后,接下来就是对模型进行训练了,和前面的步骤也是一样的,定义训练的轮数、学习率,损失函数、优化器等等;
需要注意的是:因为我们这里占位符(也就是我们需要传入的x和y值)的形状是[None, 12]的,所以在传入数据之前,需要将形状进行重建(reshape);
然后就是对损失的统计并进行可视化等等的操作。
# 模型训练
# 设置训练超参数
# 迭代轮次
train_epochs = 50
# 学习率
learning_rate = 0.01
# 定义损失函数(均方差)
with tf.name_scope("LossFunction"):
loss_function = tf.reduce_mean(tf.pow(y - pred, 2))
# 定义优化器(梯度下降)
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_function)
# 定义会话
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
# 定义损失列表,用于保存loss值
loss_list = []
for epoch in range(train_epochs):
loss_sum = 0.0
for xs, ys in zip(x_data, y_data):
# 将 xs 和 ys 变成相应形状的二维数组(要与前面的x和y的形状相对应)
xs = xs.reshape(1, 12)
ys = ys.reshape(1, 1)
# 训练并且修改参数的值(w和b)
_, loss = sess.run([optimizer, loss_function], feed_dict={x: xs, y: ys})
# 计算一轮的损失总和
loss_sum = loss_sum + loss
# 打乱数据的顺序(防止“肌肉记忆”)
xvalues, yvalues = shuffle(x_data, y_data)
b0temp = b.eval(session=sess)
w0temp = w.eval(session=sess)
loss_average = loss_sum/len(y_data)
# 添加平均损失值
loss_list.append(loss_average)
print("当前训练轮数:", epoch+1, " 平均损失值为:", loss_average, " b=", b0temp, " \nw=", w0temp)
# 损失值的可视化
plt.plot(loss_list)
plt.show()
损失值的可视化:可以看出损失在一刚开始减小的很快,到后面会逐渐变缓。
5、模型应用
在训练好模型之后,我们可以从数据集中选取一个房子作为例子,来验证一下我们模型的准确度,这里选的是第348条数据。
# 模型的应用
n = 348
x_test = x_data[n]
x_test = x_test.reshape(1, 12)
predict = sess.run(pred, feed_dict={x: x_test})
print("预测值:%f" % predict)
print("实际值:", y_data[n])
预测值与实际值对比:
注:
关于数据集的应用,在这个实例中所有的数据我们都用来训练模型了,那么这个时候再拿用来训练的数据来验证数据似乎就少了说服力!正如课程中老师讲到:就像考试一样,如果在考试之前把原题都给你了,那么考试时可能就会根据记忆来写;如果考试前给的复习题目跟考试的题目不一样,但是知识点都是一样的,那么就可以起到检验的效果。
所以比较好的做法是:数据集中一部分用来训练模型,剩下一部分用来检验模型的正确性,然后再拿训练的模型预测其他的。这样一来就起到了很好的作用!
附:完整代码
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd # 读取文件的库
from sklearn.utils import shuffle # “洗牌”函数(打乱数据)
# 读取数据文件
df = pd.read_csv("data/boston.csv", header=0)
# 显示数据摘要描述信息
# print(df)
# print(df.describe())
# 获取df的值
df = df.values
# 把df转换为 np 的数组格式
df = np.array(df)
# print(df)
# 特征数据的归一化
for i in range(12):
df[:, i] = df[:, i]/(df[:, i].max() - df[:, i].min())
# x_data 为前12列特征值
x_data = df[:, :12]
# y_data 为第13列标签数据
y_data = df[:, 12]
# print(x_data, '\n shape=', x_data.shape)
# print(y_data, '\n shape=', y_data.shape)
x = tf.placeholder(tf.float32, [None, 12], name="X") # 12个特征数据
y = tf.placeholder(tf.float32, [None, 1], name="Y") # 1个标签数据
# 定义模型函数
# 定义一个命名空间(将以下语句进行打包)
with tf.name_scope("Model"):
# w 初始化值为shape=(12, 1)的随机数
w = tf.Variable(tf.random_normal([12, 1], stddev=0.01), name="W")
# b 初始值为1
b = tf.Variable(1.0, name="b")
# w和x是矩阵相乘,用matmul,不能用mutiply或者*
def model(x, w, b):
return tf.matmul(x, w) + b
# 预测计算操作,前向计算节点
pred = model(x, w, b)
# 模型训练
# 设置训练超参数
# 迭代轮次
train_epochs = 50
# 学习率
learning_rate = 0.01
# 定义损失函数(均方差)
with tf.name_scope("LossFunction"):
loss_function = tf.reduce_mean(tf.pow(y - pred, 2))
# 定义优化器(梯度下降)
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_function)
# 定义会话
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
# 定义损失列表,用于保存loss值
loss_list = []
for epoch in range(train_epochs):
loss_sum = 0.0
for xs, ys in zip(x_data, y_data):
# 将 xs 和 ys 变成相应形状的二维数组(要与前面的x和y的形状相对应)
xs = xs.reshape(1, 12)
ys = ys.reshape(1, 1)
# 训练并且修改参数的值(w和b)
_, loss = sess.run([optimizer, loss_function], feed_dict={x: xs, y: ys})
# 计算一轮的损失总和
loss_sum = loss_sum + loss
# 打乱数据的顺序(防止“肌肉记忆”)
xvalues, yvalues = shuffle(x_data, y_data)
b0temp = b.eval(session=sess)
w0temp = w.eval(session=sess)
loss_average = loss_sum/len(y_data)
# 添加平均损失值
loss_list.append(loss_average)
print("当前训练轮数:", epoch+1, " 平均损失值为:", loss_average, " b=", b0temp, " \nw=", w0temp)
# 损失值的可视化
plt.plot(loss_list)
plt.show()
# 模型的应用
n = 348
x_test = x_data[n]
x_test = x_test.reshape(1, 12)
predict = sess.run(pred, feed_dict={x: x_test})
print("预测值:%f" % predict)
print("实际值:", y_data[n])