房价预测
本题是经典的通过表格数据去预测最终值,主要分为几大步骤:
一.将数据集修改为可以代入到网络模型的数字,因为给的数据大部分都是str类型,是无法直接放到网络模型里跑的,例如下图,很多标签值为str类型,并不是数字,那么解决办法就是将这些标签分类,强制让其变为数字类型
二.创建神经网络模型
三.训练网络,最终预测测试集
一.数据集制作和修改(数据的预处理)
对于表格数据集来说,无非就两个操作,1.将标签值变为数字的标准化,2.将标签值为str字符型的变为float类型
分析题目给的train_csv文件中标签值
发现第一个标签Id对于预测没用,那么在制作数据的时候首先需要去除第一个标签数据,可以使用.drop[‘id’],也可以用 iloc() 函数去除,直接筛选从第二个标签开始的值。
将train_csv文件拉到最后,发现最后一个标签值为SalePrice售价,我们本题要做的就是去预测售价,那么在train_csv文件中最后一个标签SalePrice就是我们训练集的label,因此在制作数据集时候,也不能要SalePrice标签,而前面除了Id的所有标签值就是我们训练集的数据,这个房子的各种属性值,比如房子修建时间,面积,或者是否挨着街道等,去用这些数据去预测它的房价。
import pandas as pd #表格处理库
import torch #框架
#读取数据
train_csv=pd.read_csv('/kaggle/input/house-prices-advanced-regression-techniques/train.csv')
test_csv=pd.read_csv('/kaggle/input/house-prices-advanced-regression-techniques/test.csv')
#重点:神经网络去训练数据必须都是Tensor张量模型,iloc将标签值分裂出来,转出来的数据类型为float32因为要统一数据类型,训练集数据也要转为f
#loat32,float会提高预测精度,直接读出数据为一维,而训练集的数据为二维,所以用reshape将label数据变为二维
train_label=torch.tensor(train_csv.iloc[:,-1],dtype=torch.float32).reshape(-1,1)
#将训练集和测试集的数据整合在一块处理,这样的好处就是在后面预测的时候,test_csv里面还是str类标签,还的再处理一次数据,整合起来一次性处理好
#再分离训练集和测试集数据,将训练集的Id和SalePrice标签去除,而test集只需要去除Id标签
all_feature=pd.concat((train_csv.iloc[:,1:-1],test_csv.iloc[:,1:]))
#将数字类标签进行标准化操作,也叫归一化处理,这样方便神经网络计算,简化,避免梯度爆炸
number=all_feature.dtypes[all_feature.dtypes!='object'].index #将数字类型标签索引提取出来,因为归一化只对数字进行处理,str类型不需要管,这也就是上面说的两步中的第一步
all_feature[number]=all_feature[number].apply(
lambda x: (x-x.mean())/(x.std()) #标准化,就是把数据值变小了,让其正态分布
)
#因为csv文件里面经常有数据缺失,将空缺的NaN补为0,否则NaN无法在网络中计算
all_feature[number]=all_feature[number].fillna(0)
#将标签为str类型转换为数字型,具体原理如下图
all_feature=pd.get_dummies(all_feature,dummy_na=True)
标签的值有几种,它就拆为几个小标签,例如标签为生物种类class,那么标签值有狗,猫,人,鸟,牛,那么这个标签会变为class_人,class_狗,class_猫…
经过上面数据处理操作后,那么我们的DataFrame变为以下
数字类别标签已经标准化,str类标签也转化为数字表示,这里的False 和True在网络中会被自动识别为0和1,但此时这个表还只是DataFrame类型数据,并不是我们要的数据集
#分离数据,将训练集和测试集数据分离
train_n=train_csv.shape[0] #因为all_feature是train和test整合起来一块处理的所以得到训练集的数目
all_feature=all_feature.astype(np.float32) #转换数据,将表中的值全变为float类型方便计算
train_data=torch.tensor(all_feature[:train_n].values,dtype=torch.float32) #分离出训练集
test_data=torch.tensor(all_feature[train_n:].values,dtype=torch.float32) #分离测试集
此时我们得到了训练集的数据,和标签,但需要整合起来,也就是一 一对应,每单个样本和其标签值,这篇文章我写了在pytorch中如何整合数据:
https://blog.csdn.net/qq_43767511/article/details/141924633?spm=1001.2014.3001.5501
#创建数据集
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
class data(Dataset): #创建单个数据单元
def __init__(self,tensor1,tensor2): #继承,下面要用到什么变量,这里就要声明什么变量
super().__init__() #模板
self.tensor1=tensor1
self.tensor2=tensor2
def __len__(self):
return len(self.tensor1) #模板随便写
def __getitem__(self, idex): #将单个数据和标签整合到一块的初始化函数
train_one_data=self.tensor1[idex,:] #通过idex得到单个数据
label=self.tensor2[idex,-1] #得到该数据的标签
return train_one_data,label #返回数据+标签,相当于捆绑
#将所有的数据整合成为一个整体
data_1=data(train_data,train_label) #将上面的类实例化
data_2=DataLoader(data_1,batch_size=32) #进行整合,batch_size表示一组有几个单数据,为的是后面的分组训练
那么上面最后的得到的data_2就是我们最终的完整训练集了,既有数据,还有对应的标签,数据的预处理到此结束。
损失函数和网络模型
#损失函数定义
loss=nn.MSELoss() #这里用的是均方误差损失函数
in_feature=train_data.shape[1] #根据单个数据的长度去创建模型
#创建网络,这里只是做了一个简单的全连接层,可以自己多去创建几层
def get_net():
net=nn.Sequential(nn.Linear(in_feature,1)) #搭建模型,这里定义了
return net
损失函数运算原理,第一个y表示我们神经网络预测的y值,第二个y表示标签值:
#损失函数定义,这个函数和上面的损失函数不同,上面的是神经网络需要用到的,下面这个是用来matplotlib图来观察loss的走向的,让数据可视化,当然也可以不用,不会影响我们预测的结果
def loss_function(net,infeature,labels):
final_y=torch.clamp(net(infeature),1,float('inf')) #让预测的值在1-99999之间,得到负数的直接扔掉
rmse=torch.sqrt(loss(torch.log(final_y),torch.log(labels))) #下图公式
return rmse.item() #将张量变为数值输出,不加item的话,输出的就是tensor张量了,我们要的是数值
训练函数
训练函数代码很长,不需要被吓到,一步一步解释,把逻辑理清就好了
#上面创建了网络框架,那么就将网络模型实例化,就一直用这个网络
net=get_net()
#定义训练函数,net参数就是我们的网络模型,第一第二个不说了,数据和标签
#num_epoch要进行几个训练来回,理应越大越好,就是一直不停的训练,但是容易过拟合
#learning_rate学习率,梯度下降时候要求导,w-dw*r 控制梯度下降时候,各个参数变化幅度
#weight_decay 主要用于在模型训练过程中对权重进行正则化,防止过拟合
def train(net,train_data,train_label,num_epoch,learning_rate,weight_decay):
train_ls=[] #负责监控损失函数值变化,就是用到上面说的第二个损失函数
optimer=Adam(net.parameters(), #模板,梯度下降算法,优化算法,优化网络模型的参数
lr=learning_rate, #上面说了,学习率主要控制梯度下降过程中参数的变化
weight_decay=weight_decay
)
#开始训练,以下几步都是神经网络训练的经典模板,理解不了也没事
for epoch in range(num_epoch): #训练几个回合,先预测,后梯度下降算一个来回
for x,y in data_2: #从我们上面做的训练数据集中,分别取出数据和标签
optimer.zero_grad() #将模型中所有参数的梯度清零,以便在下次迭代中进行正确的梯度计算和更新。
loss_value=loss(net(x).squeeze(),y) #利用第一个损失函数来进行梯度下降,这里为什么用squeeze,因为得到的x维度为[32,1,330],该函数会压缩,把1抹去,直接变为[32,330],而y维度为[32,1],要用损失函数时,切记要维度相同
loss_value.backward() #损失函数对每个参数的变化率(梯度),以便根据梯度来更新参数
optimer.step() #作用是根据计算得到的梯度来更新模型的参数
train_ls.append(loss_function(net,train_data,train_label)) #用第二个损失函数记录跟踪损失值变化上面已经解释了,存不存在,不会影响我们预测结果
return train_ls
#上面只是定义训练函数,那么下面就是正儿八经开始调用函数训练,初始参数可以自己调
train(net,train_data,train_label,100,learning_rate=0.1,weight_decay=1)
#上面训练后,那么net里面的w和b参数已经是训练好的参数,直接预测就可以
pred=net(test_data).detach().numpy() #前面已经将训练集处理好了,这里直接放入net网络预测,detach()目的是将得出的结果与模型想隔离,numpy是将向量变为numpy数组,只有这样,才能把我们预测的数据存入到csv文件
#我们开始制作csv文件,因为要提交csv文件才能算通过
test_csv['SalePrice']=pd.Series(pred.reshape(1,-1)[0]) #在最开始读取test_cav的DataFrame里将‘SalePrice’赋值为我们的预测值,因为测试集里没有该标签,需要我们自己填入
submission=pd.concat((test_csv['Id'],test_csv['SalePrice']),axis=1) #将文件中的id和SalePrice提取出来,重新构建一个csv文件,concat表示按列或者按行拼接,axis=1表示列,=0表示按行
submission.to_csv('submission.csv',index=False) #生成csv文件
生成的结果如下图所示
整篇代码
下面是整篇代码
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import torch
from torch.utils.data import Dataset
from torch import nn
from torch.optim import Adam
from torch.utils.data import DataLoader
import os
for dirname, _, filenames in os.walk('/kaggle/input'):
for filename in filenames:
print(os.path.join(dirname, filename)
# 提取数据,处理数据
train_csv=pd.read_csv('/kaggle/input/house-prices-advanced-regression-techniques/train.csv')
test_csv=pd.read_csv('/kaggle/input/house-prices-advanced-regression-techniques/test.csv')
train_label=torch.tensor(train_csv.iloc[:,-1],dtype=torch.float32).reshape(-1,1)
all_feature=pd.concat((train_csv.iloc[:,1:-1],test_csv.iloc[:,1:]))
number=all_feature.dtypes[all_feature.dtypes!='object'].index
all_feature[number]=all_feature[number].apply(
lambda x: (x-x.mean())/(x.std())
)
all_feature[number]=all_feature[number].fillna(0)
all_feature=pd.get_dummies(all_feature,dummy_na=True)
# 分离数据,
train_n=train_csv.shape[0]
all_feature=all_feature.astype(np.float32) #转换数据
train_data=torch.tensor(all_feature[:train_n].values,dtype=torch.float32)
test_data=torch.tensor(all_feature[train_n:].values,dtype=torch.float32)
class data(Dataset):
def __init__(self,tensor1,tensor2):
super().__init__()
self.tensor1=tensor1
self.tensor2=tensor2
def __len__(self):
return len(self.tensor1)
def __getitem__(self, idex):
train_one_data=self.tensor1[idex,:]
label=self.tensor2[idex,-1]
return train_one_data,label
data_1=data(train_data,train_label)
data_2=DataLoader(data_1,batch_size=32)
loss=nn.MSELoss()
in_feature=train_data.shape[1]
def loss_function(net,infeature,labels):
final_y=torch.clamp(net(infeature),1,float('inf'))
rmse=torch.sqrt(loss(torch.log(final_y),torch.log(labels)))
return rmse.item() #将张量变为数值输出
def get_net():
net=nn.Sequential(nn.Linear(in_feature,1))
return net
net=get_net()
def train(net,train_data,train_label,num_epoch,learning_rate,weight_decay):
train_ls=[]
optimer=Adam(net.parameters(),
lr=learning_rate,
weight_decay=weight_decay
)
for epoch in range(num_epoch):
for x,y in data_2:
optimer.zero_grad()
loss_value=loss(net(x).squeeze(),y)
loss_value.backward()
optimer.step()
train_ls.append(loss_function(net,train_data,train_label))
return train_ls
train(net,train_data,train_label,100,learning_rate=0.1,weight_decay=1)
pred=net(test_data).detach().numpy()
test_csv['SalePrice']=pd.Series(pred.reshape(1,-1)[0])
submission=pd.concat((test_csv['Id'],test_csv['SalePrice']),axis=1)
submission.to_csv('submission.csv',index=False)
泰坦尼克号幸存者预测也和该文逻辑一样