导语: 开始学习机器学习相关知识。波士顿房价预测,也是很经典的一个案例,我会陆续把自己完成整个项目的过程记录下来,还有就是可能会出现一定的差错,或者数据分析库使用的不是很熟练的情况,也希望大佬指出。另外,我是会一步步完善这个程序,但是只是从流程上完善,最后的结果因为数据集的原因可能不是会很准确。这篇文章更多是记录自己的学习情况,可能可借鉴度不高,如果是纯小白的话可以看一看,说不定会出现相同的问题,大佬请绕开把!!!
该项目中我使用到了一下相关库
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
导入相关库
-------------------
datasets = load_boston() #导入数据集
datasets.keys()
>>> dict_keys(['data', 'target', 'feature_names', 'DESCR', 'filename'])
可以看到存储类型与字典相似,所以使用keys()的方法打印出它的键,有五个参数在这里我们只需要用到前三个。
data = datasets['data'] #这是数据集
target = datasets['target'] #目标,也就是结果
column = datasets['feature_names'] #这是参数的索引
#将上述的数据转化成pandas的Dataframe
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和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)=n1i∈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)=n1i∈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=n2i∈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=n2i∈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=n2i∈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 = [] #我采用的是batch训练
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()
我感觉总体来讲训练效果还是可以的,因为毕竟只有两个参数而且,RM和LASTA的影响情况最大,基本上也是预测出了大概的走势,训练集只有300多,也是造成不精准的一个原因,总体来讲我感觉效果还是不错的,毕竟也是第一次手撸代码。其中我遇见的错误可以分为两类,一个是对于公式的理解还有就是一些对于一些库的熟练程度不够高,但是通过这次又巩固了一下代码能力。