import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sklearn
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import KFold
import torch
from torch import nn
from torch.utils.data import Dataset,DataLoader
from torch.utils.data import TensorDataset
import warnings
def ignore_warn(*args, **kwargs):
pass
warnings.warn = ignore_warn
#load data
train = pd.read_csv('traindata.csv',index_col='Id')
test = pd.read_csv('testdata.csv',index_col='Id')
Xtrain = train.drop(labels='SalePrice',axis=1) ytrain = train['SalePrice'].values # normalization from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_n = scaler.fit_transform(Xtrain) test_n = scaler.transform(test)写在前面
接下来就是将预处理好的数据喂给机器学习的模型训练。需要说明的是,查阅了几个大佬的高分代码可以看出,比较好的方式是调包(划掉)训练多个机器学习模型并以stacking的方式组合。笔者复现类似的代码也得到了比单一模型要好得多的结果。不过做这个入门项目也不是追求预测准确度,原意是想借这一项目练习一下pytorch的最基础的一些用法,所以试一下用pytorch搭建神经网络(即使对于这个只有1455个样本的数据集用深度学习可以说是杀鸡用牛刀)
数据清洗和特征工程的步骤在上一篇文章里:(一)特征工程
数据集构建
X_train = torch.tensor(X_n).float() y_train = torch.tensor(ytrain).view(-1, 1).float() X_test = torch.tensor(test_n).float() datasets = torch.utils.data.TensorDataset(X_train, y_train) train_iter = torch.utils.data.DataLoader(datasets, batch_size=10, shuffle=True)
这里有两种办法实现dataset类,一是直接构造
# class HouseDataset(Dataset):
# def __init__(self,X,y):
# self.X = X
# self.y = y
# def __len__(self):
# return len(self.X)
# def __getitem__(self, idx):
# return self.X[idx,:],self.y[idx]
# data_train = HouseDataset(X=X_train,y=y_train)
# data_loader = DataLoader(data_train, batch_size=5, shuffle=True)
二是使用 TensorDataset 来将数据包装成Dataset类,再使用dataloader
from torch.utils.data import Dataset,DataLoader from torch.utils.data import TensorDataset data = TensorDataset(X_train, y_train)搭建神经网络
设置参数
# setting Hyperparameters num_epochs = 400 learning_rate = 0.05 size_hidden1 = 600 size_hidden2 = 300 size_hidden3 = 300 size_hidden4 = 10 output_size = 1 input_size = Xtrain.shape[1] K = 5
class HouseNet(nn.Module):
def __init__(self,input_size, size_hidden1, size_hidden2,size_hidden3,output_size):
super().__init__()
self.lin1 = nn.Linear(input_size, size_hidden1)
self.act1 = nn.ReLU()
self.BatchNorm1d1 = nn.BatchNorm1d(size_hidden1, affine=False)
self.drop1 = nn.Dropout(0.3)
self.lin2 = nn.Linear(size_hidden1, size_hidden2)
self.act2 = nn.ReLU()
self.BatchNorm1d2 = nn.BatchNorm1d(size_hidden2, affine=False)
self.drop2 = nn.Dropout(0.3)
self.lin3 = nn.Linear(size_hidden2, size_hidden3)
self.act3 = nn.ReLU()
self.BatchNorm1d3 = nn.BatchNorm1d(size_hidden3, affine=False)
self.drop3 = nn.Dropout(0.3)
self.lin4 = nn.Linear(size_hidden3, size_hidden4)
self.act4 = nn.ReLU()
self.BatchNorm1d4 = nn.BatchNorm1d(size_hidden4, affine=False)
self.lin5 = nn.Linear(size_hidden4,output_size)
def forward(self, input):
lin1_out = self.lin1(input)
lin1_out = self.BatchNorm1d1(lin1_out)
lin1_out = self.drop1(lin1_out)
act1_out = self.act1(lin1_out)
lin2_out = self.lin2(act1_out)
lin2_out = self.BatchNorm1d2(lin2_out)
lin2_out = self.drop2(lin2_out)
act2_out = self.act2(lin2_out)
lin3_out = self.lin3(act2_out)
lin3_out = self.BatchNorm1d3(lin3_out)
lin3_out = self.drop3(lin3_out)
act3_out3 = self.act3(lin3_out)
lin4_out = self.lin4(act3_out3)
lin4_out = self.BatchNorm1d4(lin4_out)
act4_out4 = self.act4(lin4_out)
lin5_out = self.lin5(act4_out4)
return lin5_out
初始化参数函数
def reset_weights(model):
'''
Try resetting model weights to avoid
weight leakage.
'''
for layer in model.children():
if hasattr(layer, 'reset_parameters'):
layer.reset_parameters()
定义神经网络的训练函数
def trainnetwork(X):
model = HouseNet(input_size, size_hidden1, size_hidden2,size_hidden3,output_size)
model.train()
model.apply(reset_weights)
# Loss and optimizer
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
Xloarder = torch.utils.data.DataLoader(X, batch_size=50,shuffle=True)
total_step = len(Xloarder)
losslist = pd.DataFrame({'loss' : [0.0]})
for epoch in range(num_epochs):
for i,(trainX,trainy) in enumerate(Xloarder):
# Forward pass
outputs = model(trainX)
loss = criterion(outputs, trainy)
# Backward and optimize
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (i+1) % total_step == 0:
print ('Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}'
.format(epoch+1, num_epochs, i+1, total_step, loss.item()))
losslist.loc[str(epoch)] = loss.item()
return model,losslist
测试函数,绘制一下学习曲线
model,losslist = trainnetwork(data)
Epoch [1/400], Step [30/30], Loss: 22.5647 Epoch [2/400], Step [30/30], Loss: 4.2579 Epoch [3/400], Step [30/30], Loss: 8.2732 Epoch [4/400], Step [30/30], Loss: 5.2298 Epoch [5/400], Step [30/30], Loss: 0.7501 Epoch [6/400], Step [30/30], Loss: 0.2774 Epoch [7/400], Step [30/30], Loss: 0.9184 Epoch [8/400], Step [30/30], Loss: 4.9067 Epoch [9/400], Step [30/30], Loss: 1.1154 Epoch [10/400], Step [30/30], Loss: 3.6600 Epoch [11/400], Step [30/30], Loss: 3.1540 Epoch [12/400], Step [30/30], Loss: 1.3145 ... Epoch [393/400], Step [30/30], Loss: 0.0221 Epoch [394/400], Step [30/30], Loss: 0.0039 Epoch [395/400], Step [30/30], Loss: 0.0204 Epoch [396/400], Step [30/30], Loss: 0.0253 Epoch [397/400], Step [30/30], Loss: 0.0529 Epoch [398/400], Step [30/30], Loss: 0.0701 Epoch [399/400], Step [30/30], Loss: 0.0187 Epoch [400/400], Step [30/30], Loss: 0.0368
losslist[1:].plot()
K折交叉验证
定义测试函数,输出为该model的rmse误差
def testmse(X,model):
Xloarder = torch.utils.data.DataLoader(X, batch_size=10,shuffle=True,drop_last = True)
rmse = 0.0
with torch.no_grad():
for i,(X,y) in enumerate(Xloarder):
y_pre = model(X).numpy()
y = y.numpy()
rmse += sklearn.metrics.mean_squared_error(y, y_pre,squared=False)
rmse = rmse/len(Xloarder)
return rmse
算一下之前训练的网络的rmse误差
testmse(data,model)
0.21277317800398532
交叉验证主函数
kfold = KFold(n_splits=K,random_state=43, shuffle=True)
models = []
mses = []
for i, (train_idx, test_idx) in enumerate(kfold.split(data)):
Ktrain = torch.utils.data.Subset(data, train_idx)
Ktest = torch.utils.data.Subset(data,test_idx)
model,_ = trainnetwork(Ktrain)
models += [model]
mse = testmse(Ktest,model)
mses += [mse]
msesd = np.round(np.array(mses),decimals=4)
plt.bar([1,2,3,4,5],msesd, width = 0.5, align = 'center', label = 'rmse')
for a,b in zip([1,2,3,4,5],msesd):
plt.text(a,b,b,ha = 'center', va = 'bottom', fontsize = 12)
plt.legend()
可以看到吻合得不是特别好但反正搭这个也不是为了排名所以我们下次努力吧
from numpy import *
mean_mse = mean(mses)
print(f'几个模型的误差为{mses}')
print(f'平均误差为{mean_mse}')
几个模型的误差为[0.20241131813361726, 0.19209420141474953, 0.19965740986939134, 0.2314058002726785, 0.2180823195597221] 平均误差为0.20873020985003174
最后做出预测,将K个模型的结果做一个平均,得出预测结果。
pre_num = np.zeros((len(test),K))
for i,model in enumerate(models):
ypre = model(X_test)
ypre = ypre.detach().numpy()
pre_num[:,i] = ypre.ravel()
ypredic = mean(pre_num,axis=1)
提交数据~
ypredic = np.expm1(ypredic)
ypredic
array([121556.59045634, 158763.30902425, 183182.03429701, ...,
155690.86633615, 113216.03077972, 201623.90664553])
submission = pd.DataFrame({'SalePrice':ypredic},index=test.index)
submission.to_csv('Sublib.csv')



