(李沐课程)kaggle房价预测
读取并处理数据
需要预测的数据是sold Price,将其当作labeltrain_label=train_data.iloc[:,2:3]
使用pd.concat把train_data的第三列去掉,用其他的特征项构成新的train_data
同时对于test_data也做类似的处理,去掉id列,保留剩下的所有features列
处理数字特征(numeric_features)
将数字项进行标准化处理,并且把NaN项填写为0train_data.dtypes得到的是DataFrame或Series中每列的数据类型的类型,返回的数据是一个Series
从其中选出数字类型的索引名
使用train_data.dtypes!='object'得到符合条件的bool值列表
使用train_data.dtypes[train_data.dtypes!='object']来通过Series可以通过bool列表进行访问的特性,得到符合条件的键值对
再加上.index 变成train_data.dtypes[train_data.dtypes!='object'].index获取到所有符合条件的索引列表
这里实际上是获取的Series对象的index
标准化处理并处理NaN
train_data[numeric_features]=train_data[numeric_features].apply(lambda x:(x-x.mean())/x.std(),axis=0)
#这句对指定列中的NaN做填充0处理
train_data[numeric_features]=train_data[numeric_features].fillna(0)
apply()函数
上述处理中用到了apply函数,DataFrame.apply(func: 'AggFuncType', axis: 'Axis' = 0,raw: 'bool' = False,result_type=None,args=(),**kwargs)
其中func是应用到每行或者每列的函数,由后面的Axis控制
处理离散特征(obj_features)
处理方法
注意:这里在处理过程中,必须同时把验证集和训练集的离散特征都做处理(因为两个数据集中离散特征可能会有不同,对后面模型的维度一致性会产生影响)
所以这里对离散数据进行one-hot编码的时候,把两个数据集拼接后一起编码,再从其中选择属于训练集的行进行训练(后面验证的时候,对验证数据集也要做同样的处理)dummy_na=True顺便处理了NaN的数据
#选取属于训练集的行作为训练特征数据集,并从DataFrame转换为tensor
train_features=torch.tensor(train_data.iloc[:train_data_num].values).float()
其中函数的作用
变成one-hot编码将非数字项进行分类标识
使用pd.get_dummies()将每列的非数字项进行one-hot编码
该函数会在后面新增很多列(列名默认为原来的列名+其值),表示每一行数据是否有该列
- dummy_na 表示将NaN项但拿出来组成一个列
City_NaN - dtype=int 默认是bool,便于计算改为float

对于关键离散特征的选取
所有的离散特征太多了,所以选取其中重要的几个离散特征,进而使用pd.get_dummies()将one-hot编码的离散特征加到后面
#主要的非数字特征
main_obj_features = ['Type', 'Cooling', 'Bedrooms', 'Region',
'Cooling features', 'City', 'State']
构建网络并开始训练
网络结构
构建网络有多种方法,先用个最快捷的nn.Sequential
def get_net():
net = nn.Sequential(nn.Linear(features_num, 64),
nn.ReLU(),
nn.Linear(64, 1))
return net
net=get_net()
这样就生成了两层的神经网络
也能自己一点点构建网络,参照[[PyTorch 神经网络基础]]
class myNN(nn.Module):
def __init__(self):
super().__init__()
#定义层
self.fc1=nn.Linear(features_num,300)
self.fc2=nn.Linear(300,1)
def forward(self,x):
x=torch.relu(self.fc1(x))
x=torch.relu(self.fc2(x))
return x
net=myNN()
损失函数
可以自定义,也可以直接用nn里面自带的
因为这里是回归问题,这里先用nn自带的均方误差
criterion=nn.MSELoss()
优化器(梯度如何更新)
这里采用Adam方法
它能够自适应学习率作用于动量上,然后利用动量来更新学习率,从而实现自适应学习率
optimizer=torch.optim.Adam(net.parameters(),lr=0.1,weight_decay=0.001)
获取训练设备
获取设备,有N卡选N卡,没有N卡就是cpu训练
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
开始训练
#网络移动到显卡上
net.to(device)
epochs=300
batch_size=64
for epoch in range(epochs):
for i in range(0,train_data_num,batch_size):
x_batch=train_features[i:i+batch_size]
#将张量移动到显卡上
x_batch=x_batch.to(device)
labels_batch=train_labels[i:i+batch_size]
#将张量移动到显卡上
labels_batch=labels_batch.to(device)
#每次优化前,梯度置0
optimizer.zero_grad()
#前向传播
output=net(x_batch)
#计算损失
loss=criterion(output,labels_batch)
#反向传播和优化
loss.backward()
#优化一次
optimizer.step()
if(epoch%10==0 and epoch!=0):
#计算完的东西默认都在显卡上,所以先取出到cpu上,再固定参数然后转为numpy数组
train_loss.append(loss.cpu().detach().numpy())
train_epoch.append(epoch)
print("损失:",loss.cpu().item())
保存网络训练完的参数
torch.save(net.state_dict(),'net.pth')
读取训练好的参数并进行验证
构建网络并读取训练好的参数
测试的网络必须和训练的网络一致,使用同样的方法生成网络对象
def get_net():
net = nn.Sequential(nn.Linear(4361, 64),
nn.ReLU(),
nn.Linear(64, 1))
return net
net=get_net()
#读取之前保存的训练好的参数的文件,因为训练的时候是在显卡上,如果需要在cpu上验证则加上后面的map_location=torch.device('cpu')这部分参数就将网络中的参数转移到cpu上了
net.load_state_dict(torch.load('net.pth',map_location=torch.device('cpu')),)
#开启评估模式
net.eval()
处理测试数据集
由于有离散特征值,所以还需要把训练数据集拿过来一起给离散特征值进行独热编码后再提取其中属于测试数据集的行
test_data=pd.read_csv('./dataset/test.csv')
test_num=test_data.shape[0]
train_data=pd.read_csv('./dataset/train.csv')
train_data=pd.concat([train_data.iloc[:,1:2],train_data.iloc[:,3:]],axis=1)
test_data=test_data.iloc[:,1:]
#主要的非数字特征
main_obj_features = ['Type', 'Cooling', 'Bedrooms', 'Region',
'Cooling features', 'City', 'State']
numeric_features=test_data.dtypes[test_data.dtypes!='object'].index
train_data=pd.concat([train_data[numeric_features],train_data[main_obj_features]])
#对数字特征进行标准化处理,并且填充NaN
test_data[numeric_features]=test_data[numeric_features].apply(lambda x:(x-x.mean())/x.std(),axis=0)
test_data[numeric_features]=test_data[numeric_features].fillna(0)
test_features=pd.concat([test_data[numeric_features],test_data[main_obj_features]],axis=1)
all_data=pd.concat([test_features,train_data],axis=0)
#对离散特征进行one-hot编码
features=pd.get_dummies(all_data,dummy_na=True,dtype=float)
#选取其中属于测试数据集的行,得到的test_features就是合法的测试数据的特征集合,可以开始验证
test_features=features.iloc[:test_num]
#转换为张量
test_features=torch.tensor(test_features.values).float()
开始验证,并记录结果
output=net(test_features)
output=output.detach().numpy()
id=np.arange(47439,79065).reshape(-1,1)
#生成列名为id和Sold Price的两个DataFrame对象,并拼接完后写入csv文件
id=pd.DataFrame(id,columns=['Id'])
output=pd.DataFrame(output,columns=['Sold Price'])
res=pd.concat([id,output],axis=1)
#index=False表示不带DataFrame默认的index
res.to_csv('output.csv',index=False)

完整代码
train.py
import pandas as pd
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
#读取数据
train_data=pd.read_csv('./dataset/train.csv')
#获取到训练数据集的个数,用于后面分割训练和测试数据集
train_data_num=train_data.shape[0]
test_data=pd.read_csv('./dataset/test.csv')
#读取labels(售价)
train_labels=train_data.iloc[:,2:3]
#pd.concat 需要传入一个列表
train_data=pd.concat([train_data.iloc[:,1:2],train_data.iloc[:,3:]],axis=1)
test_data=test_data.iloc[:,1:]
#主要的非数字特征
main_obj_features = ['Type', 'Cooling', 'Bedrooms', 'Region',
'Cooling features', 'City', 'State']
#获取每一个特征的数据类型,从中取出纯数字的特征值的索引
#numeric_features就是所有数字项目的索引
numeric_features=train_data.dtypes[train_data.dtypes!='object'].index
train_data[numeric_features]=train_data[numeric_features].apply(lambda x:(x-x.mean())/x.std(),axis=0)
train_data[numeric_features]=train_data[numeric_features].fillna(0)
test_data=pd.concat([test_data[numeric_features],test_data[main_obj_features]],axis=1)
train_data=pd.concat([train_data[numeric_features],train_data[main_obj_features]],axis=1)
train_data=pd.concat([train_data,test_data],axis=0)
train_data=pd.get_dummies(train_data,dummy_na=True,dtype=float)
features_num=train_data.shape[1]
print('特征数量:',features_num)
#整合完特征之后,把test数据集的数据去掉,并将train_data转为tensor
train_features=torch.tensor(train_data.iloc[:train_data_num].values).float()
train_labels=torch.tensor(train_labels.iloc[:train_data_num].values).float()
print(train_features.shape,train_labels.shape)
def get_net():
net = nn.Sequential(nn.Linear(features_num, 64),
nn.ReLU(),
nn.Linear(64, 1))
return net
net=get_net()
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
net.to(device)
#这里是回归问题,用均方误差
criterion=nn.MSELoss()
def relative_error(y,y_hat):
return torch.pow((y-y_hat),2)/y_hat
optimizer=torch.optim.Adam(net.parameters(),lr=0.1,weight_decay=0.001)
train_loss=[]
train_epoch=[]
epochs=300
batch_size=64
for epoch in range(epochs):
for i in range(0,train_data_num,batch_size):
x_batch=train_features[i:i+batch_size]
x_batch=x_batch.to(device)
labels_batch=train_labels[i:i+batch_size]
labels_batch=labels_batch.to(device)
#每次优化前,梯度置0
optimizer.zero_grad()
output=net(x_batch)
loss=criterion(output,labels_batch)
#反向传播和优化
loss.backward()
#优化一次
optimizer.step()
if(epoch%10==0 and epoch!=0):
train_loss.append(loss.cpu().detach().numpy())
train_epoch.append(epoch)
print("损失:",loss.cpu().item())
plt.plot(train_epoch,train_loss,label="train_loss")
plt.show()
torch.save(net.state_dict(),'net.pth')
test.py
import torch
import torch.nn as nn
import pandas as pd
import numpy as np
def get_net():
net = nn.Sequential(nn.Linear(4361, 64),
nn.ReLU(),
nn.Linear(64, 1))
return net
net=get_net()
net=get_net()
net.load_state_dict(torch.load('net.pth',map_location=torch.device('cpu')),)
#评估模式
net.eval()
test_data=pd.read_csv('./dataset/test.csv')
test_num=test_data.shape[0]
train_data=pd.read_csv('./dataset/train.csv')
train_data=pd.concat([train_data.iloc[:,1:2],train_data.iloc[:,3:]],axis=1)
test_data=test_data.iloc[:,1:]
#主要的非数字特征
main_obj_features = ['Type', 'Cooling', 'Bedrooms', 'Region',
'Cooling features', 'City', 'State']
numeric_features=test_data.dtypes[test_data.dtypes!='object'].index
train_data=pd.concat([train_data[numeric_features],train_data[main_obj_features]])
#对数字特征进行标准化处理,并且填充NaN
test_data[numeric_features]=test_data[numeric_features].apply(lambda x:(x-x.mean())/x.std(),axis=0)
test_data[numeric_features]=test_data[numeric_features].fillna(0)
test_features=pd.concat([test_data[numeric_features],test_data[main_obj_features]],axis=1)
all_data=pd.concat([test_features,train_data],axis=0)
features=pd.get_dummies(all_data,dummy_na=True,dtype=float)
#选取其中属于测试数据集的行,得到的test_features就是合法的测试数据的特征集合,可以开始验证
test_features=features.iloc[:test_num]
#转换为张量
test_features=torch.tensor(test_features.values).float()
output=net(test_features)
#将输出转换为numpy数组,再转换为DataFrame
id=np.arange(47439,79065).reshape(-1,1)
output=output.detach().numpy()
id=pd.DataFrame(id,columns=['Id'])
output=pd.DataFrame(output,columns=['Sold Price'])
res=pd.concat([id,output],axis=1)
res.to_csv('output.csv',index=False)
print(res)
更多推荐


所有评论(0)