波士顿房价预测(一)
导语: 开始学习机器学习相关知识。波士顿房价预测,也是很经典的一个案例,我会陆续把自己完成整个项目的过程记录下来,还有就是可能会出现一定的差错,或者数据分析库使用的不是很熟练的情况,也希望大佬指出。另外,我是会一步步完善这个程序,但是只是从流程上完善,最后的结果因为数据集的原因可能不是会很准确。这篇文章更多是记录自己的学习情况,可能可借鉴度不高,如果是纯小白的话可以看一看,说不定会出现相同的问题,大佬请绕开把!!!
1.准备工作
该项目中我使用到了一下相关库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import random
from sklearn.datasets import load_boston
大家可以自行检查用pip下载一下(这里就不说怎么用了哈!),然后就是数据集的话,在sklearn库中有提供数据集,所以我就不提供了。
这里我是用的是:python3.8.3 、jupyter1.0.0、vscode
2.数据准备
导入相关库
-------------------
datasets = load_boston()
datasets.keys()
>>> dict_keys(['data', 'target', 'feature_names', 'DESCR', 'filename'])
可以看到存储类型与字典相似,所以使用keys()的方法打印出它的键,有五个参数在这里我们只需要用到前三个。
data = datasets['data']
target = datasets['target']
column = datasets['feature_names']
Dataframe = pd.DataFrame(data,columns=column)
Dataframe['price'] = target
运行结果如下: 在这里呢,我并没有选择用全部的数据(不是不会,而是我发现,我用全部的数据的时候,训练效果不是很好,还没找到原因),所以我只挑选了两个对价格影响最高的参数。pandas中提供了相关系数的计算方法。
相关系数:值为(-1,1)越接近于1,就说明正相关性越强,越接近于-1,负相关性越强,0就是不想关,具体概念在《概率论与数理统计》中协方差那一节。
plt.figure(figsize=(12,8),dpi=80)
sns.heatmap(Dataframe.corr())
plt.show()
r = Dataframe.corr()
r['price']
可以观察到正相关性最大的是RM,负相关性最大的是LSTAT。
制作训练集和测试集
rm = Dataframe.RM
lstat = Dataframe.LSTAT
price = Dataframe.price
using_data = np.array([rm,lstat])
using_price = np.array([price])
train_data,test_data = np.split(using_data ,[int(len(using_data[0])*0.7),] ,axis=1)
train_price,test_price = np.split(using_price,[int(len(using_price[0])*0.7),] ,axis=1)
模型训练
x
?
=
x
0
+
x
1
+
x
2
+
.
.
.
+
x
n
\vec x ={x_0 + x_1 + x_2 +...+x_n}
x
=x0?+x1?+x2?+...+xn?
为了获得最优的参数集合(w,b)
l
o
s
s
(
θ
;
x
?
)
=
∑
i
∈
N
(
f
θ
(
x
i
)
?
y
i
)
2
loss(\theta;\vec{x}) = \sum_{i \in N}(f_\theta(x_i) - y_i)^2
loss(θ;x
)=i∈N∑?(fθ?(xi?)?yi?)2 在统计学中,预估的y往往写成
y
^
\hat{y}
y^?
l
o
s
s
(
x
)
=
1
n
∑
i
∈
N
(
y
^
i
?
y
i
)
2
loss(x) =\frac{1}{n} \sum_{i \in N}(\hat{y}_i - y_i)^2
loss(x)=n1?i∈N∑?(y^?i??yi?)2
为了找出变量让loss能够取得最小值可以采用梯度下降的方法
l
o
s
s
(
x
)
=
1
n
∑
i
∈
N
(
y
^
i
?
y
i
)
2
loss(x) =\frac{1}{n} \sum_{i \in N}(\hat{y}_i - y_i)^2
loss(x)=n1?i∈N∑?(y^?i??yi?)2
l
o
s
s
(
x
)
=
1
n
∑
(
w
1
?
x
1
+
w
2
?
x
2
+
b
?
y
i
)
2
loss(x) =\frac{1}{n} \sum (w_1*x_1 + w_2*x_2 + b -y_i) ^2
loss(x)=n1?∑(w1??x1?+w2??x2?+b?yi?)2
现在为了获得一组 w 和 b,使得loss最小,写出对w1,w2的偏导,对b的偏导,即可求解出来
?
l
o
s
s
?
w
1
=
2
n
∑
i
∈
N
(
w
1
?
x
i
1
+
w
2
?
x
i
2
+
b
?
y
i
)
?
x
i
1
\frac{\partial{loss}}{\partial{w_1}} =\frac{2}{n} \sum_{i \in N}(w_1*x_{i1} + w_2 *x_{i2}+b-y_i ) * x_{i1}
?w1??loss?=n2?i∈N∑?(w1??xi1?+w2??xi2?+b?yi?)?xi1?
?
l
o
s
s
?
w
2
=
2
n
∑
i
∈
N
(
w
1
?
x
i
1
+
w
2
?
x
i
2
+
b
?
y
i
)
?
x
i
2
\frac{\partial{loss}}{\partial{w_2}} =\frac{2}{n} \sum_{i \in N}(w_1*x_{i1} + w_2 *x_{i2}+b-y_i ) * x_{i2}
?w2??loss?=n2?i∈N∑?(w1??xi1?+w2??xi2?+b?yi?)?xi2?
?
l
o
s
s
?
b
=
2
n
∑
i
∈
N
(
w
1
?
x
i
1
+
w
2
?
x
i
2
+
b
?
y
i
)
\frac{\partial{loss}}{\partial{b}} =\frac{2}{n} \sum_{i \in N}(w_1*x_{i1} + w_2 *x_{i2}+b-y_i )
?b?loss?=n2?i∈N∑?(w1??xi1?+w2??xi2?+b?yi?)
x
i
1
=
=
>
r
m
i
x_{i1} ==> rm_i
xi1?==>rmi?
x
i
2
=
=
>
l
a
s
t
a
i
x_{i2} ==> lasta_i
xi2?==>lastai?
所以可以根据上式子去写出模型训练过程。
def model(x,w,b):
"""求yhat"""
return np.dot(x,w.T) + b
def loss(yhat,y):
"""损失函数,要让他不断变小"""
return np.mean((yhat - y) ** 2)
def partial_w(x,y,yhat):
"""这是求得其中一组参数——x的系数"""
return np.array([2 * np.mean(yhat-y) * x[i] for i in range(len(x))])
def partial_b(x,y,yhat):
"""这是另一个系数——常数项b"""
return 2 * np.mean(yhat - y)
下面就是训练过程了
w = np.random.random_sample((1,len(train_data)))
b = random.random()
leanring_rate = 1e-5
epoch = 400
losses = []
for i in range(epoch):
batch_losses = []
for batch in range(train_data.shape[1]):
index = np.random.choice(range(train_data.shape[1]))
x = train_data[:,index]
y = train_price[:,index]
yhat = model(x,w,b)
loss_v = loss(yhat,y)
batch_losses.append(loss_v)
w = w - partial_w(x,y,yhat) * leanring_rate
b = b - partial_b(x,y,yhat) * leanring_rate
if batch % 100 == 0:
print(f'epoch:{i} ,bath:{batch} ,loss:{loss_v}')
losses.append(np.mean(batch_losses))
关于梯度下降什么的可以看一下吴恩达的视频或者在高数下中也有讲到。下面是训练过程。其实很快的,数据只有300多一点。 下图中可以看到loss值是一直变小的趋势,但是抖动下降的
plt.figure(figsize=(12,8),dpi = 80)
plt.plot(losses)
plt.show()
验证模型情况
通过模型训练已经得到了一组参数模型w,b在测试集验证一下训练结果的情况
model_price = []
for i in range(test_data.shape[1]):
x = test_data[:,i]
res = model(x,w,b)
model_price.append(res)
同样用途可以更直观的查看
plt.figure(figsize=(12,8),dpi = 80)
plt.plot(model_price ,label = 'model_price')
plt.plot(test_price[0] ,color = 'r' ,label = 'price')
plt.legend()
plt.show()
也可以排一下序,可以更直观的观察训练的模型情况
model_prices = sorted(model_price)
price_ = sorted(list(test_price[0]))
plt.figure(figsize=(12,8),dpi = 80)
plt.plot(model_prices ,label = 'model_price')
plt.plot(price_ ,color = 'r' ,label = 'price')
plt.legend()
plt.show()
总结
我感觉总体来讲训练效果还是可以的,因为毕竟只有两个参数而且,RM和LASTA的影响情况最大,基本上也是预测出了大概的走势,训练集只有300多,也是造成不精准的一个原因,总体来讲我感觉效果还是不错的,毕竟也是第一次手撸代码。其中我遇见的错误可以分为两类,一个是对于公式的理解还有就是一些对于一些库的熟练程度不够高,但是通过这次又巩固了一下代码能力。
|