pytorch神经网络因素预测_实战:使用PyTorch构建神经网络进行房价预测
微信公號:ilulaoshi / 個人網(wǎng)站:lulaoshi.info
本文將學(xué)習(xí)一下如何使用PyTorch創(chuàng)建一個前饋神經(jīng)網(wǎng)絡(luò)(或者叫做多層感知機(jī),Multiple-Layer Perceptron,MLP),文中會使用PyTorch提供的自動求導(dǎo)功能,訓(xùn)練一個神經(jīng)網(wǎng)絡(luò)。
本文的數(shù)據(jù)集來自Kaggle競賽:房價預(yù)測(https://www.kaggle.com/c/house-prices-advanced-regression-techniques/)。這份數(shù)據(jù)分為訓(xùn)練數(shù)據(jù)集和測試數(shù)據(jù)集。兩個數(shù)據(jù)集都包括每棟房子的特征,如建造年份、地下室狀況等特征值。這些特征中,有連續(xù)的數(shù)值型(Numerical)特征,有離散的分類(Categorical)特征。這些特征中,有些特征值是缺失值“na”。訓(xùn)練數(shù)據(jù)集包括了每棟房子的價格,也就是需要預(yù)測的目標(biāo)值(Label)。我們應(yīng)該用訓(xùn)練數(shù)據(jù)集訓(xùn)練一個模型,并對測試數(shù)據(jù)集進(jìn)行預(yù)測,然后將結(jié)果提交到Kaggle。
數(shù)據(jù)探索和預(yù)處理
首先,我們下載并加載數(shù)據(jù)集:
train_data_path ='./dataset/train.csv'
train = pd.read_csv(train_data_path)
num_of_train_data = train.shape[0]
test_data_path ='./dataset/test.csv'
test = pd.read_csv(test_data_path)
訓(xùn)練數(shù)據(jù)集共1460個樣本,81個維度,其中,Id是每個樣本的唯一編號,SalePrice是房價,也是我們要擬合的目標(biāo)值。其他維度(列)有數(shù)值類特征,也有非數(shù)值列,或者叫分類特征。
先查看訓(xùn)練數(shù)據(jù)集的維度:
train.shape
輸出為:
(1460, 81)
或者通過train.describe()來查看整個數(shù)據(jù)集各個特征的一些統(tǒng)計(jì)情況。
接著,我們要把訓(xùn)練數(shù)據(jù)集和測試數(shù)據(jù)集合并。將訓(xùn)練數(shù)據(jù)集和測試數(shù)據(jù)集合并主要是為了統(tǒng)一特征處理的流程,或者說對訓(xùn)練數(shù)據(jù)集和測試數(shù)據(jù)集使用同樣的方法,進(jìn)行同樣的特征工程處理。
# 房價,要擬合的目標(biāo)值
target = train.SalePrice
# 輸入特征,可以將SalePrice列扔掉
train.drop(['SalePrice'],axis = 1 , inplace = True)
# 將train和test合并到一起,一塊進(jìn)行特征工程,方便預(yù)測test的房價
combined = train.append(test)
combined.reset_index(inplace=True)
combined.drop(['index', 'Id'], inplace=True, axis=1)
接著就要開始進(jìn)行特征工程了。本文沒有進(jìn)行任何復(fù)雜的特征工程,只做了兩件事:1、過濾掉了含有缺失值的列;2、對分類特征進(jìn)行了One-Hot編碼。缺失值會在一定程度上影響算法的預(yù)測效果,一般可以使用一些默認(rèn)值或者一些臨近值來填充缺失值。對于MLP模型,分類特征必須經(jīng)過編碼,轉(zhuǎn)換成數(shù)值才能進(jìn)行模型訓(xùn)練,One-Hot編碼是一種最常見的分類特征處理的方法。
我們用下面的函數(shù)過濾非空列:
# 選出非空列
def get_cols_with_no_nans(df,col_type):
'''
Arguments :
df : The dataframe to process
col_type :
num : to only get numerical columns with no nans
no_num : to only get nun-numerical columns with no nans
all : to get any columns with no nans
'''
if (col_type == 'num'):
predictors = df.select_dtypes(exclude=['object'])
elif (col_type == 'no_num'):
predictors = df.select_dtypes(include=['object'])
elif (col_type == 'all'):
predictors = df
else :
print('Error : choose a type (num, no_num, all)')
return 0
cols_with_no_nans = []
for col in predictors.columns:
if not df[col].isnull().any():
cols_with_no_nans.append(col)
return cols_with_no_nans
分別對數(shù)值特征和分類特征進(jìn)行處理:
num_cols = get_cols_with_no_nans(combined, 'num')
cat_cols = get_cols_with_no_nans(combined, 'no_num')
# 過濾掉含有缺失值的特征
combined = combined[num_cols + cat_cols]
print(num_cols[:5])
print ('Number of numerical columns with no nan values: ',len(num_cols))
print(cat_cols[:5])
print ('Number of non-numerical columns with no nan values: ',len(cat_cols))
經(jīng)過過濾,數(shù)值特征共有25列,分類特征共有20列,共45列。
# 對分類特征進(jìn)行One-Hot編碼
def oneHotEncode(df,colNames):
for col in colNames:
if( df[col].dtype == np.dtype('object')):
# pandas.get_dummies 可以對分類特征進(jìn)行One-Hot編碼
dummies = pd.get_dummies(df[col],prefix=col)
df = pd.concat([df,dummies],axis=1)
# drop the encoded column
df.drop([col],axis = 1 , inplace=True)
return df
對于分類特征,還需要進(jìn)行One-Hot編碼,pandas.get_dummies可以幫我們自動完成One-Hot編碼過程。經(jīng)過One-Hot編碼后,數(shù)據(jù)增加了很多列,共有149列。
至此,我們完成了一次非常簡單的特征工程,將這些數(shù)據(jù)轉(zhuǎn)化為PyTorch模型所能接受的Tensor形式:
# 訓(xùn)練數(shù)據(jù)集特征
train_features = torch.tensor(combined[:num_of_train_data].values, dtype=torch.float)
# 訓(xùn)練數(shù)據(jù)集目標(biāo)
train_labels = torch.tensor(target.values, dtype=torch.float).view(-1, 1)
# 測試數(shù)據(jù)集特征
test_features = torch.tensor(combined[num_of_train_data:].values, dtype=torch.float)
print("train data size: ", train_features.shape)
print("label data size: ", train_labels.shape)
print("test data size: ", test_features.shape)
構(gòu)建神經(jīng)網(wǎng)絡(luò)
接著,我們開始構(gòu)建神經(jīng)網(wǎng)絡(luò)。
在PyTorch中構(gòu)建神經(jīng)網(wǎng)絡(luò)有兩種方式。比較簡單的前饋網(wǎng)絡(luò),可以使用nn.Sequential。nn.Sequential是一個存放神經(jīng)網(wǎng)絡(luò)的容器,直接在nn.Sequential里面添加我們需要的層即可。整個模型的輸入為特征數(shù),輸出為一個標(biāo)量。模型的隱藏層使用了ReLU激活函數(shù),最后一層是一個線性層,得到的是一個預(yù)測的房價值。
model_sequential = nn.Sequential(
nn.Linear(train_features.shape[1], 128),
nn.ReLU(),
nn.Linear(128, 256),
nn.ReLU(),
nn.Linear(256, 256),
nn.ReLU(),
nn.Linear(256, 256),
nn.ReLU(),
nn.Linear(256, 1)
)
另一種構(gòu)建神經(jīng)網(wǎng)絡(luò)的方式是繼承nn.Module類,我們將子類起名為Net類。__init__()方法為Net類的構(gòu)造函數(shù),用來初始化神經(jīng)網(wǎng)絡(luò)各層的參數(shù);forward()也是我們必須實(shí)現(xiàn)的方法,主要用來實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)的前向傳播過程。
class Net(nn.Module):
def __init__(self, features):
super(Net, self).__init__()
self.linear_relu1 = nn.Linear(features, 128)
self.linear_relu2 = nn.Linear(128, 256)
self.linear_relu3 = nn.Linear(256, 256)
self.linear_relu4 = nn.Linear(256, 256)
self.linear5 = nn.Linear(256, 1)
def forward(self, x):
y_pred = self.linear_relu1(x)
y_pred = nn.functional.relu(y_pred)
y_pred = self.linear_relu2(y_pred)
y_pred = nn.functional.relu(y_pred)
y_pred = self.linear_relu3(y_pred)
y_pred = nn.functional.relu(y_pred)
y_pred = self.linear_relu4(y_pred)
y_pred = nn.functional.relu(y_pred)
y_pred = self.linear5(y_pred)
return y_pred
我們已經(jīng)定義好了一個神經(jīng)網(wǎng)絡(luò)的Net類,還要初始化一個Net類的對象實(shí)例model,表示某個具體的模型。然后定義損失函數(shù),這里使用MSELoss,MSELoss使用了均方誤差(Mean Square Error)來衡量損失函數(shù)。對于模型model的訓(xùn)練過程,這里使用Adam算法。Adam是優(yōu)化算法中的一種,在很多場景中效率要優(yōu)于SGD。
model = Net(features=train_features.shape[1])
# 使用均方誤差作為損失函數(shù)
criterion = nn.MSELoss(reduction='mean')
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
訓(xùn)練模型
接著,我們使用Adam算法進(jìn)行多輪的迭代,更新模型model中的參數(shù)。這里對模型進(jìn)行500輪的迭代。
losses = []
# 訓(xùn)練500輪
for t in range(500):
y_pred = model(train_features)
loss = criterion(y_pred, train_labels)
# print(t, loss.item())
losses.append(loss.item())
if torch.isnan(loss):
break
# 將模型中各參數(shù)的梯度清零。
# PyTorch的backward()方法計(jì)算梯度會默認(rèn)將本次計(jì)算的梯度與緩存中已有的梯度加和。
# 必須在反向傳播前先清零。
optimizer.zero_grad()
# 反向傳播,計(jì)算各參數(shù)對于損失loss的梯度
loss.backward()
# 根據(jù)剛剛反向傳播得到的梯度更新模型參數(shù)
optimizer.step()
每次迭代使用訓(xùn)練數(shù)據(jù)集中的所有樣本train_features。model(train_features)實(shí)際是執(zhí)行的model.forward(train_features),即forward()方法中定義的前向傳播邏輯,輸入數(shù)據(jù)在神經(jīng)網(wǎng)絡(luò)模型中前向傳播,得到預(yù)測值y_pred。criterion(y_pred, train_labels)方法計(jì)算了預(yù)測值y_pred和目標(biāo)值train_labels之間的損失。
每次迭代時,我們要先對模型中各參數(shù)的梯度清零:optimizer.zero_grad()。PyTorch中的backward()默認(rèn)是把本次計(jì)算的梯度和緩存中已有的梯度加和,因此必須在反向傳播前先將梯度清零。接著執(zhí)行backward()方法,完成反向傳播過程,PyTorch會幫我們計(jì)算各參數(shù)對于損失函數(shù)的梯度。optimizer.step()會根據(jù)剛剛反向傳播得到的梯度,更新模型參數(shù)。
至此,一個簡單的預(yù)測房價的模型就訓(xùn)練好了。
測試模型
我們可以使用模型對測試數(shù)據(jù)集進(jìn)行預(yù)測,將得到的預(yù)測值保存成文件,提交到Kaggle上。
predictions = model(test_features).detach().numpy()
my_submission = pd.DataFrame({'Id':pd.read_csv('./dataset/test.csv').Id,'SalePrice': predictions[:, 0]})
my_submission.to_csv('{}.csv'.format('./dataset/submission'), index=False)
參考資料
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的pytorch神经网络因素预测_实战:使用PyTorch构建神经网络进行房价预测的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 编写自动化工具
- 下一篇: 为什么用户在注册时需要使用邮箱或手机号作