天天看點

線性回歸-PyTorch-Kaggle房價預測問題

關于線性回歸的介紹可以看這裡:線性回歸介紹

下文主要介紹通過線性回歸解決Kaggle中的HousePrices問題,使用的是PyTorch。

下文會給出使用線性回歸建立的最終模型,以及超參數等内容,但是整個模型的搭建以及試錯的過程由于内容太長,感興趣

的可以去作者的GitHub下載下傳相關的Jupyter notebook檔案,訓練資料和測試資料也可以從上面下載下傳。

相關庫:

import numpy as np # linear algebra
import pandas as pd
from pandas import DataFrame
import matplotlib.pyplot as plt
import torch
import      

模型:

class Net(nn.Module):
    def __init__(self, D_in, H1, H2, H3, D_out):
        # D_in, H1, H2, H3, D_out  --  輸入次元 第一層輸出次元 第二層輸出次元 第三層輸出次元 最終輸出次元
        super(Net, self).__init__()
        self.linear1 = nn.Linear(D_in, H1)
        self.linear2 = nn.Linear(H1, H2)
        self.linear3 = nn.Linear(H2, H3)
        self.linear4 = nn.Linear(H3, D_out)
        
    def forward(self, x):
        # torch.clamp() 将張量的每個元素範圍限制到一個(min, max)
        y = self.linear1(x).clamp(min=0)
        y = self.linear2(y).clamp(min=0)
        y = self.linear3(y).clamp(min=0)
        y = self.linear4(y)
        return      

解決這個問題最重要的不是模型結構而是對訓練資料的處理,這裡選擇的是将訓練資料中非數值資料映射為int值,并且将

每一列資料減去均值後再除以最大值和最小值的內插補點,也可以通過減去均值除以标準差的方式,不過本文采用的是前者,

感興趣的讀者可以自己實作。

資料的導入和處理:

raw_data = pd.read_csv('./data/kaggle_house/train.csv')
# 數值資料的列
numeric_colmuns = []
numeric_colmuns.extend(list(raw_data.dtypes[raw_data.dtypes == np.int64].index))
numeric_colmuns.extend(list(raw_data.dtypes[raw_data.dtypes == np.float64].index))
# 将SalePrice放在最後一列
numeric_colmuns.remove('SalePrice')
numeric_colmuns.append('SalePrice')
# 去除Id這一列
numeric_colmuns.remove('Id')
numeric_data = DataFrame(raw_data, columns=numeric_colmuns)
# 預設值補0
# pd.fillna(n)填充缺失資料
numeric_data['LotFrontage'] = numeric_data['LotFrontage'].fillna(0)
numeric_data['MasVnrArea'] = numeric_data['MasVnrArea'].fillna(0)
numeric_data['GarageYrBlt'] = numeric_data['GarageYrBlt'].fillna(0)
# 均值 最大值 最小值
means, maxs, mins = dict(), dict(), dict()
for col in numeric_data:
    means[col] = numeric_data[col].mean()
    maxs[col] = numeric_data[col].max()
    mins[col] = numeric_data[col].min()
numeric_data = (numeric_data - numeric_data.mean()) / (numeric_data.max() - numeric_data.min())
# 将原始資料中非數值資料的列找出來
non_numeric_columns = [col for col in list(raw_data.columns) if col not in numeric_colmuns]
non_numeric_columns.remove('Id')
# 非數值資料
non_numeric_data = DataFrame(raw_data, columns=non_numeric_columns)
nan_columns = np.any(pd.isna(non_numeric_data), axis=0)
nan_columns = list(nan_columns[nan_columns == True].index)
# 将缺失值作為 'N/A'
for col in nan_columns:
    non_numeric_data[col] = non_numeric_data[col].fillna('N/A')
# 用映射表把字元串轉為int
mapping_table = dict()

for col in non_numeric_columns:
    curr_mapping_table = dict()
    
    unique_values = pd.unique(non_numeric_data[col])
    print(unique_values)
    for inx, v in enumerate(unique_values):
        curr_mapping_table[v] = inx + 1
        non_numeric_data[col] = non_numeric_data[col].replace(v, inx + 1)
    
    mapping_table[col] = curr_mapping_table
# 歸一化
for col in non_numeric_data:
    means[col] = non_numeric_data[col].mean()
    maxs[col] = non_numeric_data[col].max()
    mins[col] = non_numeric_data[col].min()
for col in non_numeric_data:
    non_numeric_data[col] = (non_numeric_data[col] - means[col]) / (maxs[col] - mins[col])
non_numeric_x_df = DataFrame(non_numeric_data, columns=non_numeric_columns)
non_numeric_y_df = DataFrame(numeric_y_df)
# 用上所有資料
x_df = DataFrame(numeric_x_df, columns=numeric_x_columns)
y_df = DataFrame(numeric_y_df)
# 将非數值資料的那些列拼接上去
# x_df = pd.concat([numeric_x_df, non_numeric_x_df], axis=1)
# 可以下面的循環語句 也可以用上面的那條語句 pd.concat()
for col in non_numeric_columns:
    x_df[col] = non_numeric_x_df[col]
x = torch.tensor(x_df.values, dtype=torch.float)
y = torch.tensor(y_df.values, dtype=torch.float)      

超參數:

D_in, D_out = x.shape[1], y.shape[1]
model6 = Net(D_in, H1, H2, H3, D_out)
optimizer = torch.optim.Adam(model6.parameters(), lr=1e-4 * 2)      

模型訓練:

losses6 = []

for t in range(500):
    y_pred = model6(x)
    
    loss = criterion(y_pred, y)
    if (t + 1) % 10 == 0:
        print(t, loss.item())
    losses6.append(loss.item())
    
    if torch.isnan(loss):
        break
    
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()      

下面損失值變化:

9 6.942687511444092
19 4.153867721557617
29 2.8861405849456787
39 2.1543002128601074
49 1.6814405918121338
59 1.2690644264221191
69 0.9127545356750488
79 0.6374701857566833
89 0.44278401136398315
99 0.3076871335506439
109 0.21465598046779633
119 0.15101489424705505
129 0.11797764152288437
139 0.0813324898481369
149 0.06239088624715805
159 0.0478670597076416
169 0.037706196308135986
179 0.029238209128379822
189 0.025697028264403343
199 0.018969601020216942
209 0.015594517812132835
219 0.013458245433866978
229 0.010695122182369232
239 0.009573224931955338
249 0.01129293255507946
259 0.008044157177209854
269 0.008845468983054161
279 0.00610680878162384
289 0.0053095207549631596
299 0.007215226534754038
309 0.002987970830872655
319 0.009104212746024132
329 0.01189067866653204
339 0.0026393337175250053
349 0.002604425884783268
359 0.0021756708156317472
369 0.001827285042963922
379 0.0014763239305466413
389 0.0014955512015148997
399 0.00858624093234539
409 0.002981389407068491
419 0.004797589499503374
429 0.0007704143645241857
439 0.0008664355846121907
449 0.0006161347846500576
459 0.0010636755032464862
469 0.004391425289213657
479 0.008840898983180523
489 0.00047967140562832355
499 0.0010821424657478929      

除了上述使用所有資料訓練的模型,作者還比較了僅使用數值資料訓練模型和僅使用非數值資料訓練的模型:

線性回歸-PyTorch-Kaggle房價預測問題

上面是這三種訓練方式的模型損失值變化曲線。