李沐 《動手學深度學習》 | 實戰Kaggle比賽:預測房價

文章目錄

    • 1.下載和緩存數據集
    • 2.數據預處理
      • 讀取樣本
      • 預處理樣本
        • 數值型特征處理
        • 特征標準化的好處
        • 離散值處理
        • 轉換為張量表示
      • 訓練
      • K折交叉驗證
      • 模型選擇
      • 最終模型確認及結果預測
      • 代碼總結
      • 提交到Kaggle

房價預測比賽鏈接:https://www.kaggle.com/c/house-prices-advanced-regression-techniques

1.下載和緩存數據集

我們建立字典DATA_HUB, 它可以將數據集名稱的字符串映射到數據集相關的二元組上, 這個二元組包含數據集的url和驗證文件完整性的sha-1密鑰。 所有類似的數據集都托管在地址為DATA_URL的站點上(這里只托管了小一點的數據集,大的數據集還是需要去官網下載)。

import hashlib # Python的哈希庫,用于文件校驗(計算SHA1、MD5等哈希值)
import os # 操作系統接口庫 用于處理文件路徑、目錄創建等操作
import tarfile # 導入tar文件處理庫 用于解壓縮.tar、.tar.gz、.tar.bz2等歸檔文件
import zipfile # 導入zip文件處理庫 用于解壓縮.zip格式的壓縮文件
import requests # 導入HTTP請求庫 提供簡潔的API用于網絡文件下載DATA_HUB = dict()
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'

一般情況需要自己去Kaggle將數據集下載到本地目錄。這里使用一個download函數用來下載數據集, 將數據集緩存在本地目錄(默認情況下為../data)中, 并返回下載文件的名稱。 如果緩存目錄中已經存在此數據集文件,并且其sha-1與存儲在DATA_HUB中的相匹配, 我們將使用緩存的文件,以避免重復的下載。

def download(name, cache_dir=os.path.join('..', 'data')):"""下載一個DATA_HUB中的文件,返回本地文件名"""assert name in DATA_HUB, f"{name} 不存在于 {DATA_HUB}"url, sha1_hash = DATA_HUB[name]os.makedirs(cache_dir, exist_ok=True)fname = os.path.join(cache_dir, url.split('/')[-1])if os.path.exists(fname):sha1 = hashlib.sha1()with open(fname, 'rb') as f:while True:data = f.read(1048576)if not data:breaksha1.update(data)if sha1.hexdigest() == sha1_hash:return fname  # 命中緩存print(f'正在從{url}下載{fname}...')r = requests.get(url, stream=True, verify=True)with open(fname, 'wb') as f:f.write(r.content)return fname

競賽數據分為訓練集和測試集。 每條記錄都包括房屋的屬性和屬性值,如街道類型、施工年份、屋頂類型、地下室狀況等, 這些特征由各種數據類型組成。 例如,建筑年份由整數表示,屋頂類型由離散類別表示,其他特征由浮點數表示。 這就是現實讓事情變得復雜的地方:例如,一些數據完全丟失了,缺失值被簡單地標記為“NA”。

每套房子的價格只出現在訓練集中,我們將劃分訓練集以創建驗證集,但是在將預測結果上傳到Kaggle之后, 我們只能在官方測試集中評估我們的模型。

訓練集拆分 訓練集+驗證集 , 測試集用于評估模型。

方法1:Kaggle 比賽網站中下載數據

加入比賽后,可以在Data下載數據集。

方法2:代碼遠程下載

使用上面定義的腳本下載并緩存Kaggle房屋數據集。

import numpy as np
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2lDATA_HUB['kaggle_house_train'] = (  DATA_URL + 'kaggle_house_pred_train.csv','585e9cc93e70b39160e7921475f9bcd7d31219ce')DATA_HUB['kaggle_house_test'] = ( DATA_URL + 'kaggle_house_pred_test.csv','fa19780a7b011d9b009e8bff8e99922a8ee2eb90')train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))

2.數據預處理

讀取樣本

訓練數據集包括1460個樣本,每個樣本80個特征和1個標簽, 而測試數據集包含1459個樣本,每個樣本80個特征。

# 使用pandas分別加載包含訓練數據和測試數據的兩個CSV文件。
train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))
print(train_data.shape) #(1460,81)
print(test_data.shape) #(1459,80)

查看一下前4個樣本的前四個特征以及最后二個特征以及相應標簽(房價)

# train_data 是一個Pandas DataFrame對象 通常包含表格數據(行是樣本/記錄,列是特征/字段)
# iloc 按位置索引選擇數據的屬性,第一個參數為行選擇器,第二個參數為列選擇器
print(train_data.iloc[0:4, [0, 1, 2, 3, -3, -2, -1]])

在每個樣本中,第一個特征是ID, 它不攜帶任何用于預測的信息。 因此,在將數據提供給模型之前,我們將其從數據集中刪除。

# train_data.iloc[:, 1:-1] 選擇所有行,選取第二列和倒數第二列  排除訓練集的第一列(通常是ID)和最后一列(通常是標簽/目標變量)
# test_data.iloc[:, 1:] 測試集選取從第2列開始到最后一列的所有列
# 參數2接著參數1,將多個DataFrame連接成一個新的DataFrame
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))

預處理樣本

數值型特征處理
  1. 將數據中所有缺失的值替換為相應特征的平均值。
  2. 為了將所有特征放在一個共同的尺度上, 我們通過將特征重新縮放到零均值和單位方差來標準化數據 x 標準 = x ? μ σ x_{標準}=\frac{x?μ}{σ} x標準?=σx?μ?

其中 μ μ μ σ σ σ分別表示特征 x x x均值和標準差。 這些特征具有零均值和單位方差,即 E [ x ? μ σ ] = μ ? μ σ = 0 E[\frac{x?μ}{σ}] = \frac{μ-μ}{σ}=0 E[σx?μ?]=σμ?μ?=0 E [ ( x ? μ ) 2 ] = ( σ 2 + μ 2 ) ? 2 μ 2 + μ 2 = σ 2 E[(x?μ)^2]=(σ^2+μ^2)?2μ^2+μ^2=σ^2 E[(x?μ)2]=(σ2+μ2)?2μ2+μ2=σ2

all_features.dtypes返回pandas Series對象,包含索引index:列名 值values:對應的數據類型。

all_features.dtypes != 'object'比較的存儲在Series中的實際值(values),返回布爾Series

布爾Series機制

在 pandas 中,當您使用一個布爾 Series 來索引另一個 Series 時,pandas 會選擇布爾 Series 中值為 True 的所有對應元素。

  1. 對齊索引:首先 pandas 會根據索引名稱對齊兩個 Series
  2. 選擇元素:然后只保留布爾 Series 中值為 True 的位置對應的元素
  3. 返回結果:返回一個新的 Series,包含所有被選中的元素
# numeric_features包含所有數值型特征列名的列表
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index

all_features[numeric_features]是根據列名選擇all_featuresDataFrame子集。

DataFrame.apply會遍歷每一列,每次取一列數據作為Series傳入lambda函數進行標準化 x 標準 = x ? μ σ x_{標準}=\frac{x?μ}{σ} x標準?=σx?μ?并收集每次lambda的返回值(這里使用了Pandas的廣播機制),組合所有結果返回新的DataFrame

這里的均值是包含數據集和測試集的,實際情況不一定有測試集,可能只能在數據集上求均值。

# 所有數值特征的標準化
all_features[numeric_features] = all_features[numeric_features].apply(lambda x: (x - x.mean()) / (x.std()))

numeric_features選中數值列,但有些數值列的值為NaN,最后需要將數值特征中的所有缺失值替換為0,并返回新的DataFrame。這里替換為0因為標準化后所有特征的均值為0。

# 在標準化數據之后,所有均值消失,因此我們可以將缺失值設置為0
all_features[numeric_features] = all_features[numeric_features].fillna(0)
特征標準化的好處
  1. 方便優化

假設預測房價有兩個特征,房間數(1-5)和房屋面積(50-300),對每個特征求梯度。發現面積方向的梯度是房間數方向梯度的幾十倍!

大梯度需要小的學習率抑制梯度爆炸,而大的梯度需要大的學習率去加速收斂,沒有一個合適的學習率可以兼容。

如果采取標準化,假設房間_std=(房間數-3)/1.5 ,面積_std =(面積-175)/125,新梯度之間差異不會太大

# 標準化變換:
房間_std = (房間數 - 3)/1.5   # 范圍[-1.33,1.33]
面積_std = (面積 - 175)/125   # 范圍[-1,1]# 新梯度:
?Loss/?w_房間 = -2(y-?)×房間_std ≈ -2(y-?)×0 (平均)
?Loss/?w_面積 = -2(y-?)×面積_std ≈ -2(y-?)×0 (平均)
→ 梯度大小比例恢復11
  1. 正則化懲罰公平

正則項 λ 2 ∣ ∣ w ∣ ∣ 2 \frac{\lambda}{2}||w||^2 2λ?∣∣w2懲罰 權重的平方和,這里超參數 λ \lambda λ控制了正則項的重要程度, λ \lambda λ設置的越大,對大的權重施加的懲罰就越重,沒辦法選出一個合適的值。

離散值處理

MSZoning的類型是一個object之類的離散值,使用one-hot編碼處理。假設這個特征(這一列)有5個不一樣的值,那我們就使用5個分量來表示。

pd.get_dummies會處理所有字符串類型(object)或分類類型(category)的列,將其轉換為可用的數值格式(one-hot編碼),在DataFrame結構中以多列方式呈現,生成新的列 列原列名_值,返回新的DataFrame。

參數dummy_na=True表示將NaN視為一個獨立有效的類別,因為默認情況會忽略缺失值。

# “Dummy_na=True”將“na”(缺失值)視為有效的特征值,并為其創建指示符特征
# 處理字符串類型或分類類型
all_features = pd.get_dummies(all_features,dummy_na=True)
print(all_features.shape)  #(2919,330)

可以發現此轉換之后,特征的總數量從79個增加到330個。

這里原始的列被剔除了!

print(all_features.select_dtypes(include='object').columns)
# Index(['MSZoning', 'Street', 'Alley', 'LotShape', 'LandContour', 'Utilities',
#      'LotConfig', 'LandSlope', 'Neighborhood', 'Condition1', 'Condition2',
#       'BldgType', 'HouseStyle', 'RoofStyle', 'RoofMatl', 'Exterior1st',
#       'Exterior2nd', 'MasVnrType', 'ExterQual', 'ExterCond', 'Foundation',
#       'BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2',
#       'Heating', 'HeatingQC', 'CentralAir', 'Electrical', 'KitchenQual',
#       'Functional', 'FireplaceQu', 'GarageType', 'GarageFinish', 'GarageQual',
#       'GarageCond', 'PavedDrive', 'PoolQC', 'Fence', 'MiscFeature',
#       'SaleType', 'SaleCondition'],
#      dtype='object')
all_features = pd.get_dummies(all_features,dummy_na=True,dtype=np.uint8)
print(all_features.select_dtypes(include='object').columns)
# Index([], dtype='object')

大模型的解釋:


**問題:**can’t convert np.ndarray of type numpy.object_. The only supported types are: float64, float32, float16, complex64, complex128, int64, int32, int16, int8, uint64, uint32, uint16, uint8, and bool

嘗試將一個包含 numpy.object_** **類型數據 的 NumPy 數組轉換為其他類型(如 PyTorch Tensor 或特定數值類型),但操作僅支持特定數據類型。

評論解答

get_dummies函數在pandas1.6.0版本之前返回numpy.uint8,無符號八位整數,在1.6.0版本開始更改為返回numpy.bool_,numpy布爾值。

# “Dummy_na=True”將“na”(缺失值)視為有效的特征值,并為其創建指示符特征
# 處理字符串類型或分類類型 只控制新的列的類型
all_features = pd.get_dummies(all_features,dummy_na=True,dtype=int)
print(all_features.shape)  #(2919,310)

這里確實可以解決問題,但是我測試了之后發現布爾類型是不會報錯的??

轉換為張量表示

pandas格式中提取NumPy格式,并將其轉換為張量表示用于訓練。

all_features[:n_train]表示前n_train行數據,只包含數據行,不包含列名,.values表示返回NumPy數組。torch,tensor表示將NumPy數組轉換為PyTorch張量,并且指定格式為32位浮點數

train_data.SalePrice.values通過列名SalePrice獲取到該列的值,輸出是一個一維數組,形狀為一維數組(n_train,)。

將其重塑數組二維數組形狀為(n_train, 1),最后轉換為PyTorch張量。

n_train = train_data.shape[0] #獲取訓練數據集的樣本數train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32)
test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32)
train_labels = torch.tensor(train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32)

訓練

損失函數使用均方誤差損失 1 n ∑ i = 1 n ( y i ? y ^ i ) 2 \frac{1}{n} \sum_{i=1}^n(y_i?\hat y_i)^2 n1?i=1n?(yi??y^?i?)2

loss = nn.MSELoss()

我們訓練一個帶有損失平方的線性模型。 顯然線性模型很難讓我們在競賽中獲勝,但線性模型提供了一種健全性檢查, 以查看數據中是否存在有意義的信息。

如果我們在這里不能做得比隨機猜測更好,那么我們很可能存在數據處理錯誤。 如果一切順利,線性模型將作為基線(baseline)模型, 讓我們直觀地知道最好的模型有超出簡單的模型多少。

in_features = train_features.shape[1] # 特征數量def get_net():net = nn.Sequential(nn.Linear(in_features,1))return net

對于真實值減去誤差值來說,我們更關心相對誤差 y ? y ^ y \frac{y-\hat y}{y} yy?y^??,對于房價來說不同的房子價格相差較大,有10w的有100w的。例如,如果我們在俄亥俄州農村地區估計一棟房子的價格時, 假設我們的預測偏差了10萬美元, 然而那里一棟典型的房子的價值是12.5萬美元, 那么模型可能做得很糟糕。 另一方面,如果我們在加州豪宅區的預測出現同樣的10萬美元的偏差, (在那里,房價中位數超過400萬美元) 這可能是一個不錯的預測。

對數變換(log transformation)這種方法被廣泛應用于Kaggle等數據科學競賽中。我們評估模型時使用 1 n ∑ i = 1 n ( l o g ( y i ) ? l o g ( y ^ i ) ) 2 \sqrt {\frac{1}{n}\sum_{i=1}^n (log(y_i)?log(\hat y_i))^2} n1?i=1n?(log(yi?)?log(y^?i?))2 ?等價于 1 n ∑ i = 1 n ( l o g y i y ^ i ) 2 \sqrt {\frac{1}{n}\sum_{i=1}^n (log \frac {y_i}{\hat y_i})^2} n1?i=1n?(logy^?i?yi??)2 ?。這個評估值越小越好。

torch.clamp(input, min, max, *, out=None) -> Tensor將張量中的元素限制在指定范圍,min表示下限值,max表示上限值。這里將最低值限制為1,防止出現負數和為0的情況影響對數的取值。

def log_rmse(net, features, labels):# 為了在取對數時進一步穩定該值,將小于1的值設置為1clipped_preds = torch.clamp(net(features), 1, float('inf'))rmse = torch.sqrt(loss(torch.log(clipped_preds),torch.log(labels)))return rmse.item() # 從張量中提取python標量值

這里訓練使用Adam優化器(后續會講),主要優勢是對于初始學習率不那么敏感。

  1. 從train_iter中按batch_size取出數據集
  2. 將optimizer管理的所有參數的梯度歸零,防止每一batch_size的梯度累加錯誤更新
  3. 前向傳播與損失計算。訓練中使用均方誤差損失,這里y和net(X)的形狀在之前的步驟已經統一
  4. 反向傳播計算梯度,自動微分計算梯度。
  5. 使用優化器更新參數。

每輪結束后評估整個訓練集的性能,將每輪結果放入train_ls中,如果提供了測試標簽test_labels,評估模型在測試集上的表現。

def train(net, train_features, train_labels, test_features, test_labels,num_epochs, learning_rate, weight_decay, batch_size):train_ls, test_ls = [], []train_iter = d2l.load_array((train_features, train_labels), batch_size)# 這里使用的是Adam優化算法optimizer = torch.optim.Adam(net.parameters(),lr = learning_rate,weight_decay = weight_decay)for epoch in range(num_epochs):for X, y in train_iter:# 每次返回一個(X_batch, y_batch)元組optimizer.zero_grad()l = loss(net(X), y) # 輸出形狀 net(X)=[batch_size, 1]l.backward()optimizer.step()train_ls.append(log_rmse(net, train_features, train_labels))if test_labels is not None:test_ls.append(log_rmse(net, test_features, test_labels))return train_ls, test_ls

K折交叉驗證

我們通過學習訓練集可以得到一組模型參數,現在通過K折交叉驗證來幫助模型選和超參數調整。

我們首先需要定義一個函數,在 K K K折交叉驗證過程中返回第 i i i折的數據。 具體地說,它選擇第 i i i個切片作為驗證數據,其余部分作為訓練數據。

注意,這并不是處理數據的最有效方法,如果我們的數據集大得多,會有其他解決辦法。

返回訓練和驗證誤差的平均值

# k總折數,i當前折數索引
def get_k_fold_data(k, i, X, y):assert k > 1 # 如果 k≤1,拋出 AssertionError#計算每折大小,整除會舍棄余數,少量樣本不被包含在任何折中fold_size = X.shape[0] // k X_train, y_train = None, Nonefor j in range(k): # slice(start, stop, step):slice對象是用于表示切片操作的特殊對象# 以下代碼相當于創建了一個切片對象:# idx = [j * fold_size : (j + 1) * fold_size]idx = slice(j * fold_size, (j + 1) * fold_size)X_part, y_part = X[idx, :], y[idx]if j == i: # 驗證集X_valid, y_valid = X_part, y_partelif X_train is None: # 如果不是驗證集且訓練集尚未初始化 - 第一個訓練集X_train, y_train = X_part, y_partelse: # 將其余訓練集拼接在一起# torch.cat():沿指定維度連接張量,0表示垂直堆疊X_train = torch.cat([X_train, X_part], 0)y_train = torch.cat([y_train, y_part], 0)return X_train, y_train, X_valid, y_valid

將數據集分成K份后,每次使用第i份作為驗證集,其余作為訓練集。

下面的代碼獨立訓練K次模型,每一次都創建一個全新初始化的模型,每次都有新的訓練數據與驗證數據。復用模型會使用上一次訓練后參數信息,

交叉驗證目標是評估最終模型性能,每一次訓練模型都取模型最后一輪的評估誤差。

def k_fold(k, X_train, y_train, num_epochs, learning_rate, weight_decay,batch_size):train_l_sum, valid_l_sum = 0, 0for i in range(k):data = get_k_fold_data(k, i, X_train, y_train)net = get_net()#         解包為X_train, y_train, X_valid, y_validtrain_ls, valid_ls = train(net, *data, num_epochs, learning_rate,weight_decay, batch_size)# 只取訓練完成時(最后一輪)的誤差train_l_sum += train_ls[-1]valid_l_sum += valid_ls[-1]# K折的學習曲線通常相似,所以這里選擇只繪制第一折if i == 0:d2l.plot(list(range(1, num_epochs + 1)),  # X軸:訓練輪次[1, num_epochs][train_ls, valid_ls],           # Y軸數據:[訓練誤差列表, 驗證誤差列表]xlabel='epoch',                 # X軸標簽ylabel='rmse',                 # Y軸標簽(均方根誤差)xlim=[1, num_epochs],           # X軸顯示范圍legend=['train', 'valid'],      # 圖例說明yscale='log'                    # Y軸使用對數刻度)print(f'折{i + 1},訓練log rmse{float(train_ls[-1]):f}, 'f'驗證log rmse{float(valid_ls[-1]):f}')return train_l_sum / k, valid_l_sum / k

模型選擇

這里選擇了一組未調優的參數,有時一組超參數的訓練誤差可能非常低,但 K K K折交叉驗證的誤差要高得多, 這表明模型過擬合了。 在整個訓練過程中,我們希望監控訓練誤差和驗證誤差這兩個數字。

k, num_epochs, lr, weight_decay, batch_size = 5, 100, 5, 0, 64
train_l, valid_l = k_fold(k, train_features, train_labels, num_epochs, lr,weight_decay, batch_size)
print(f'{k}-折驗證: 平均訓練log rmse: {float(train_l):f}, 'f'平均驗證log rmse: {float(valid_l):f}')

代碼總結

  1. 初始化一組超參數
  2. 進行 K K K折交叉驗證,對于每一折 i i i過程執行如下的步驟
    1. 將訓練集劃分為k份,其中第i份作為驗證集,其余k-1份作為訓練集
    2. 初始化一個新的模型
    3. 使用當前超參數、訓練集和驗證集訓練模型(訓練該模型的參數)
    4. 累計訓練完成的評估誤差 - 訓練集的評估誤差與驗證集的評估誤差
  3. 返回折數的平均評估誤差

通過不斷調整超參數重復上述過程,選擇出最優的超參數。

最終模型確認及結果預測

  1. 通過之前的步驟,我們已經選擇出了一組超參數。現在使用這些超參數和全部的訓練數據來訓練最終模型。
  2. 將最終模型應用于測試集,將預測結果保存在CSV文件中。

在預測階段不需要知道梯度信息了,更關心內存的優化,所以通常會將預測結果從計算圖中分離datach出來創建一個新的不含梯度信息的張量。然后將PyTorch張量轉換為NumPy數組。

將模型預測結果轉換為Pandas DataFrame中的格式,preds.reshape(1, -1)表示將數組轉換為形狀為(1,N)的二維數組,取出二維數組中的唯一元素(一維數組)轉換為Pandas Series對象。

def train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size):# 1. 初始化模型net = get_net() # # 2. 完整訓練(不使用驗證集)train_ls, _ = train(net, train_features, train_labels, None, None,num_epochs, lr, weight_decay, batch_size)# 3. 可視化訓練過程d2l.plot(np.arange(1, num_epochs + 1), [train_ls], xlabel='epoch',ylabel='log rmse', xlim=[1, num_epochs], yscale='log')# 4. 打印最終訓練誤差print(f'訓練log rmse:{float(train_ls[-1]):f}')# 5. 測試集預測preds = net(test_features).detach().numpy()# 6. 格式化預測結果test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])

Kaggle提交規范

1.文件命名:通常要求固定文件名。

2.首列必須為id,次列為預測值列,列名大小寫敏感。

    # 7. 創建提交文件# 將測試集id和模型預測的房價水平拼接形成新的DataFrame# Id	SalePrice# 1461	181000# 1462	179500# 將DataFrame轉換為CSV格式(Kaggle標準提交格式)submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)submission.to_csv('submission.csv', # 輸出的文件名index=False	# 禁止寫入行索引)

如果測試集上的預測與 K K K倍交叉驗證過程中的預測相似, 那就是時候把它們上傳到Kaggle了。 下面的代碼將生成一個名為submission.csv的文件。

train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size)

代碼總結

import hashlib # Python的哈希庫,用于文件校驗(計算SHA1、MD5等哈希值)
import os # 操作系統接口庫 用于處理文件路徑、目錄創建等操作
import tarfile # 導入tar文件處理庫 用于解壓縮.tar、.tar.gz、.tar.bz2等歸檔文件
import zipfile # 導入zip文件處理庫 用于解壓縮.zip格式的壓縮文件
import requests # 導入HTTP請求庫 提供簡潔的API用于網絡文件下載
import numpy as np
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2lDATA_HUB = dict()
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'def download(name, cache_dir=os.path.join('..', 'data')):"""下載一個DATA_HUB中的文件,返回本地文件名"""assert name in DATA_HUB, f"{name} 不存在于 {DATA_HUB}"url, sha1_hash = DATA_HUB[name]os.makedirs(cache_dir, exist_ok=True)fname = os.path.join(cache_dir, url.split('/')[-1])if os.path.exists(fname):sha1 = hashlib.sha1()with open(fname, 'rb') as f:while True:data = f.read(1048576)if not data:breaksha1.update(data)if sha1.hexdigest() == sha1_hash:return fname  # 命中緩存print(f'正在從{url}下載{fname}...')r = requests.get(url, stream=True, verify=True)with open(fname, 'wb') as f:f.write(r.content)return fname# 數據獲取
DATA_HUB['kaggle_house_train'] = (  DATA_URL + 'kaggle_house_pred_train.csv','585e9cc93e70b39160e7921475f9bcd7d31219ce')DATA_HUB['kaggle_house_test'] = ( DATA_URL + 'kaggle_house_pred_test.csv','fa19780a7b011d9b009e8bff8e99922a8ee2eb90')train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))# 數據處理
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index
all_features[numeric_features] = all_features[numeric_features].apply(lambda x: (x - x.mean()) / (x.std()))
all_features[numeric_features] = all_features[numeric_features].fillna(0)all_features = pd.get_dummies(all_features,dummy_na=True,dtype=np.uint8)
n_train = train_data.shape[0] #獲取訓練數據集的樣本數
train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32)
test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32)
train_labels = torch.tensor(train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32)# 模型的訓練
loss = nn.MSELoss()
in_features = train_features.shape[1] # 特征數量
# 訓練損失
def get_net():net = nn.Sequential(nn.Linear(in_features,1))return net
# 評估誤差
def log_rmse(net, features, labels):# 為了在取對數時進一步穩定該值,將小于1的值設置為1clipped_preds = torch.clamp(net(features), 1, float('inf'))rmse = torch.sqrt(loss(torch.log(clipped_preds),torch.log(labels)))return rmse.item() # 從張量中提取python標量值def train(net, train_features, train_labels, test_features, test_labels,num_epochs, learning_rate, weight_decay, batch_size):train_ls, test_ls = [], []train_iter = d2l.load_array((train_features, train_labels), batch_size)# 這里使用的是Adam優化算法optimizer = torch.optim.Adam(net.parameters(),lr = learning_rate,weight_decay = weight_decay)for epoch in range(num_epochs):for X, y in train_iter:# 每次返回一個(X_batch, y_batch)元組optimizer.zero_grad()l = loss(net(X), y) # 輸出形狀 net(X)=[batch_size, 1]l.backward()optimizer.step()train_ls.append(log_rmse(net, train_features, train_labels))if test_labels is not None:test_ls.append(log_rmse(net, test_features, test_labels))return train_ls, test_ls# K折交叉驗證
# 獲取訓練集和數據集
def get_k_fold_data(k, i, X, y):assert k > 1 # 如果 k≤1,拋出 AssertionError#計算每折大小,整除會舍棄余數,少量樣本不被包含在任何折中fold_size = X.shape[0] // k X_train, y_train = None, Nonefor j in range(k): # slice(start, stop, step):slice對象是用于表示切片操作的特殊對象# 以下代碼相當于創建了一個切片對象:# idx = [j * fold_size : (j + 1) * fold_size]idx = slice(j * fold_size, (j + 1) * fold_size)X_part, y_part = X[idx, :], y[idx]if j == i: # 驗證集X_valid, y_valid = X_part, y_partelif X_train is None: # 如果不是驗證集且訓練集尚未初始化 - 第一個訓練集X_train, y_train = X_part, y_partelse: # 將其余訓練集拼接在一起# torch.cat():沿指定維度連接張量,0表示垂直堆疊X_train = torch.cat([X_train, X_part], 0)y_train = torch.cat([y_train, y_part], 0)return X_train, y_train, X_valid, y_validdef k_fold(k, X_train, y_train, num_epochs, learning_rate, weight_decay,batch_size):train_l_sum, valid_l_sum = 0, 0for i in range(k):data = get_k_fold_data(k, i, X_train, y_train)net = get_net()#         解包為X_train, y_train, X_valid, y_validtrain_ls, valid_ls = train(net, *data, num_epochs, learning_rate,weight_decay, batch_size)# 只取訓練完成時(最后一輪)的誤差train_l_sum += train_ls[-1]valid_l_sum += valid_ls[-1]# K折的學習曲線通常相似,所以這里選擇只繪制第一折if i == 0:d2l.plot(list(range(1, num_epochs + 1)),  # X軸:訓練輪次[1, num_epochs][train_ls, valid_ls],           # Y軸數據:[訓練誤差列表, 驗證誤差列表]xlabel='epoch',                 # X軸標簽ylabel='rmse',                 # Y軸標簽(均方根誤差)xlim=[1, num_epochs],           # X軸顯示范圍legend=['train', 'valid'],      # 圖例說明yscale='log'                    # Y軸使用對數刻度)print(f'折{i + 1},訓練log rmse{float(train_ls[-1]):f}, 'f'驗證log rmse{float(valid_ls[-1]):f}')return train_l_sum / k, valid_l_sum / k# 超參數
k, num_epochs, lr, weight_decay, batch_size = 5, 100, 5, 0, 64
train_l, valid_l = k_fold(k, train_features, train_labels, num_epochs, lr,weight_decay, batch_size)
print(f'{k}-折驗證: 平均訓練log rmse: {float(train_l):f}, 'f'平均驗證log rmse: {float(valid_l):f}')def train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size):# 1. 初始化模型net = get_net() # # 2. 完整訓練(不使用驗證集)train_ls, _ = train(net, train_features, train_labels, None, None,num_epochs, lr, weight_decay, batch_size)# 3. 可視化訓練過程d2l.plot(np.arange(1, num_epochs + 1), [train_ls], xlabel='epoch',ylabel='log rmse', xlim=[1, num_epochs], yscale='log')# 4. 打印最終訓練誤差print(f'訓練log rmse:{float(train_ls[-1]):f}')# 5. 測試集預測preds = net(test_features).detach().numpy()# 6. 格式化預測結果test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)submission.to_csv('submission.csv', # 輸出的文件名index=False	# 禁止寫入行索引)train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size)

提交到Kaggle

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/909073.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/909073.shtml
英文地址,請注明出處:http://en.pswp.cn/news/909073.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一鍵部署Prometheus+Grafana+alertmanager對網站狀態進行監控

在建設監控體系的過程中,針對一個系統的監控是多維度的,除了服務器資源狀態、中間件狀態、應用狀態外,對系統訪問狀態的監控也是很有必要,可以在系統訪問出現異常時第一時間通知到我們。本文介紹使用 Docker-compose 方式一鍵部署…

康謀方案 | 高精LiDAR+神經渲染3DGS的完美融合實踐

目錄 一、從點云到高精地圖的重建 1、數據采集 2、點云聚合 3、高精地圖建模 4、三維建模與裝飾 二、顛覆性革新:NeRF 與 3DGS 重建 1、僅需數日,完成街景重建 2、進一步消除 Domain gap,場景逼真如實地拍攝 3、降本增效&#xff0c…

MySQL-事務(TRANSACTION-ACID)管理

目錄 一、什么是事務? 1.1.事務的定義 1.2.事務的基本語句 1.3.事務的四大特性(ACID) 二、數據庫的并發控制 2.1.什么是并發及并發操作帶來的影響? 2.2.并發操作帶來的隔離級別 三、使用事務的場景 3.1.銀行轉賬場景示例 3.2.模擬…

centos系統docker配置milvus教程

本人使用的是京東云服務器配置milvus 參考教程:https://blog.csdn.net/withme977/article/details/137270087 首先確保安裝了docker 、docker compose docker -- version docker-compose --version創建milvus工作目錄 mkdir milvus # 進入到新建的目錄 cd milvu…

什么是JSON ?從核心語法到編輯器

一、什么是JSON ? JSON,即 JavaScript 對象表示法,是一種輕量級、跨語言、純文本的數據交換格式 。它誕生于 JavaScript 生態,但如今已成為所有編程語言通用的 “數據普通話”—— 無論前端、后端,還是 Python、Java&…

計算機網絡(7)——物理層

1.數據通信基礎 1.1 物理層基本概念 物理層(Physical Layer)是所有網絡通信的物理基礎,它定義了在物理介質上傳輸原始比特流(0和1)所需的機械、電氣、功能、過程和規程特性 1.2 數據通信系統模型 信源:生成原始數據的終端設備,常見形態包括…

深度學習基礎知識總結

1.BatchNorm2d 加速收斂:Batch Normalization 可以使每層的輸入保持較穩定的分布(接近標準正態分布),減少梯度更新時的震蕩問題,從而加快模型訓練速度。 減輕過擬合:批歸一化引入了輕微的正則化效果&#…

iOS 抖音首頁頭部滑動標簽的實現

抖音首頁的頭部滑動標簽(通常稱為"Segmented Control"或"Tab Bar")是一個常見的UI組件,可以通過以下幾種方式實現: 1. 使用UISegmentedControl 最簡單的實現方式是使用系統自帶的UISegmentedControl: let segmentedCo…

ThreadLocal實現原理

ThreadLocal 是 Java 中實現線程封閉(Thread Confinement)的核心機制,它通過為每個線程創建變量的獨立副本來解決多線程環境下的線程安全問題。 Thread └── ThreadLocalMap (threadLocals) // 每個線程持有的專屬Map├── Entry[] tab…

【筆記】結合 Conda任意創建和配置不同 Python 版本的雙軌隔離的 Poetry 虛擬環境

如何結合 Conda 任意創建和配置不同 Python 版本的雙軌隔離的Poetry 虛擬環境? 在 Python 開發中,為不同項目配置獨立且適配的虛擬環境至關重要。結合 Conda 和 Poetry 工具,能高效創建不同 Python 版本的 Poetry 虛擬環境,接下來…

defineAsyncComponent

下面,我們來系統的梳理關于 defineAsyncComponent 懶加載 的基本知識點: 一、異步組件核心概念 1.1 什么是異步組件? 異步組件是 Vue 中一種按需加載組件的機制,允許將組件代碼拆分為獨立的 chunk,在需要時再從服務器加載。這種技術能顯著提升應用初始加載速度。 1.2 為…

ANeko v1.0.3 | 在手機里養只寵物貓 實時互動 動畫細膩

ANeko是一款專為喜歡貓咪的用戶設計的互動養寵應用。它讓你在手機屏幕上擁有一只可愛的貓咪動畫,這只貓咪會實時跟隨你的手指觸摸軌跡,帶來生動有趣的互動體驗。該應用不僅保留了用戶熟悉的交互式貓動畫,還結合了現代高清圖形技術&#xff0c…

人工智能AI

AI 簡介 AI 使我們能夠生成可以改進衛生保健的出色軟件,讓人能夠克服生理上的不便,改進智能基礎結構,創造令人驚嘆的娛樂體驗,甚至拯救地球! 什么是 AI? 簡而言之,AI 就是一種模仿人類行為和能力的軟件。 關鍵工作負載包括: 機器學習 - 它通常是 AI 系統的基礎,也是…

Vue 中 data 選項:對象 vs 函數

Vue 中 data 選項&#xff1a;對象 vs 函數 在 Vue 開發中&#xff0c;data 選項可以使用對象或函數形式&#xff0c;了解它們的使用場景非常重要。下面我將通過一個直觀的示例來展示兩者的區別和適用場景。 <!DOCTYPE html> <html lang"zh-CN"> <h…

python打卡第49天

知識點回顧&#xff1a; 通道注意力模塊復習空間注意力模塊CBAM的定義 CBAM 注意力模塊介紹 從 SE 到 CBAM&#xff1a;注意力機制的演進 之前我們介紹了 SE&#xff08;Squeeze-and-Excitation&#xff09;通道注意力模塊&#xff0c;其本質是對特征進行增強處理。現在&#…

iOS和桌面雙端抓包實戰經驗總結:Sniffmaster與常見工具組合解析

近幾年&#xff0c;移動端和桌面端的網絡調試工作變得越來越“棘手”。過去一個代理證書搞定的場景&#xff0c;現在常常被HTTPS加密、雙向驗證、App安全策略給難住。特別是涉及到iOS平臺時&#xff0c;很多傳統抓包方案都不再適用。作為一名在多個平臺開發和測試的程序員&…

cloudstudio騰訊云:matplotlib 設置中文字體

檢查可用字體&#xff1a; import matplotlib.font_manager as fm fonts [f.name for f in fm.fontManager.ttflist] print(fonts) # 查看系統中可用的字體列表# 列出所有中文字體文件 !fc-list :langzh沒有中文字體&#xff0c;需要下載 !sudo apt-get install fonts-wqy-m…

Django中的ORM的使用步驟----以MySQL為例

1 以純Python的形式創建項目虛擬環境 2 命令安裝Django 3 在當前虛擬環境目錄下命令創建Django項目 4 命令創建app 注&#xff1a; 若想將創建的子應用存放到指定目錄&#xff0c;如app&#xff0c; 那么需要先手動創建app目錄&#xff0c;再手動創建子應用目錄&#xff0c;如o…

Rust 學習筆記:通過 Send 和 Sync trait 實現可擴展并發性

Rust 學習筆記&#xff1a;通過 Send 和 Sync trait 實現可擴展并發性 Rust 學習筆記&#xff1a;通過 Send 和 Sync trait 實現可擴展并發性Send trait&#xff1a;允許在線程之間轉移所有權Sync trait&#xff1a;允許多線程訪問手動實現 Send 和 Sync 是不安全的練習題 Rust…

【C++】第十一節—一文詳解vector(使用+楊輝三角+深度剖析+模擬實現+細節詳細補充)

Hi&#xff0c;我是云邊有個稻草人&#xff0c;偶爾中二的C領域博主^(*&#xffe3;(oo)&#xffe3;)^&#xff0c;與你分享專業知識—— C_本篇博客所屬專欄—持續更新中—歡迎訂閱喔 目錄 一、vector的介紹及使用 1.1 vector的介紹 1.2 vector的使用 &#xff08;1&…