kaggle房价预测

比赛地址:https://www.kaggle.com/c/house-prices-advanced-regression-techniques

读取数据

python 复制代码
% matplotlib inline
import torch
import torch.nn as nn
import numpy as np
import pandas as pd
import d2lzh_pytorch as d2l  # 或者直接安装d2l包:pip install d2l==0.17.6  然后导入 import d2l

print(torch.__version__)
torch.set_default_tensor_type(torch.FloatTensor)  # 设置默认的tensor类型,
复制代码
1.12.0
python 复制代码
train_data = pd.read_csv('../data/kaggle_house/train.csv')
test_data = pd.read_csv('../data/kaggle_house/test.csv')
python 复制代码
print(train_data.shape, test_data.shape)
复制代码
(1460, 81) (1459, 80)
python 复制代码
train_data.iloc[0:4, [0, 1, 2, 3, -3, -2, -1]]

| | Id | MSSubClass | MSZoning | LotFrontage | SaleType | SaleCondition | SalePrice |
| 0 | 1 | 60 | RL | 65.0 | WD | Normal | 208500 |
| 1 | 2 | 20 | RL | 80.0 | WD | Normal | 181500 |
| 2 | 3 | 60 | RL | 68.0 | WD | Normal | 223500 |

3 4 70 RL 60.0 WD Abnorml 140000

可以看到第一个特征是Id,它能帮助模型记住每个训练样本,但难以推广到测试样本,所以我们不使用它来训练。我们将所有的训练数据和测试数据的79个特征按样本连结。

python 复制代码
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))

预处理数据

对连续数值的特征做标准化(standardization),对于缺失的特征值,将其替换成该特征的均值。

python 复制代码
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()))
# 标准化后,每个数值特征的均值变为0,所以可以直接用0来替换缺失值
all_features[numeric_features] = all_features[numeric_features].fillna(0)

接下来将离散数值转成指示特征。举个例子,假设特征MSZoning里面有两个不同的离散值RL和RM,那么这一步转换将去掉MSZoning特征,并新加两个特征MSZoning_RL和MSZoning_RM,其值为0或1。如果一个样本原来在MSZoning里的值为RL,那么有MSZoning_RL=1且MSZoning_RM=0。

python 复制代码
# dummy_na=True将缺失值也当作合法的特征值并为其创建指示特征
all_features = pd.get_dummies(all_features, dummy_na=True)
all_features.shape  # (2919, 331)
复制代码
(2919, 331)

最后,通过values属性得到NumPy格式的数据,并转成Tensor方便后面的训练。

python 复制代码
n_train = train_data.shape[0]
train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float)
test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float)
train_labels = torch.tensor(train_data.SalePrice.values, dtype=torch.float).view(-1, 1)

训练模型

python 复制代码
loss = torch.nn.MSELoss()


def get_net(feature_num):
    net = nn.Linear(feature_num, 1)
    for param in net.parameters():  # 初始化模型参数
        nn.init.normal_(param, mean=0, std=0.01)
    return net

下面定义比赛用来评价模型的对数均方根误差。其定义为 1 n ∑ i = 1 n ( log ⁡ ( y i ) − log ⁡ ( y ^ i ) ) 2 \sqrt{\frac{1}{n}\sum_{i=1}^n(\log(y_i) - \log(\hat{y}_i))^2} n1i=1∑n(log(yi)−log(y^i))2

对数均方根误差的实现如下。

python 复制代码
def log_rmse(net, features, labels):
    with torch.no_grad():
        # 将小于1的值设成1,使得取对数时数值更稳定
        clipped_preds = torch.max(net(features), torch.tensor(1.0))
        rmse = torch.sqrt(loss(clipped_preds.log(), labels.log()))
    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 = [], []
    dataset = torch.utils.data.TensorDataset(train_features, train_labels)
    train_iter = torch.utils.data.DataLoader(dataset, batch_size, shuffle=True)
    # 这里使用了Adam优化算法
    optimizer = torch.optim.Adam(params=net.parameters(), lr=learning_rate, weight_decay=weight_decay)
    net = net.float()
    for epoch in range(num_epochs):
        for X, y in train_iter:
            l = loss(net(X.float()), y.float())
            optimizer.zero_grad()
            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折交叉验证

它将被用来选择模型设计并调节超参数。下面实现了一个函数,它返回第i折交叉验证时所需要的训练和验证数据。

python 复制代码
def get_k_fold_data(k, i, X, y):
    # 返回第i折交叉验证时所需要的训练和验证数据
    assert k > 1
    fold_size = X.shape[0] // k  # 计算每一折的数据量
    X_train, y_train = None, None
    for j in range(k):
        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_part
        elif X_train is None:
            X_train, y_train = X_part, y_part
        else:
            X_train = torch.cat((X_train, X_part), dim=0)
            y_train = torch.cat((y_train, y_part), dim=0)
    return X_train, y_train, X_valid, y_valid

在K折交叉验证中我们训练K次并返回训练和验证的平均误差。

python 复制代码
def k_fold(k, X_train, y_train, num_epochs, learning_rate, weight_decay, batch_size):
    train_l_sum, valid_l_sum = 0, 0
    for i in range(k):
        data = get_k_fold_data(k, i, X_train, y_train)
        net = get_net(X_train.shape[1])
        train_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]
        if i == 0:
            d2l.semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'rmse',
                         range(1, num_epochs + 1), valid_ls,
                         ['train', 'valid'])
        print('fold %d, train rmse %f, valid rmse %f' % (i, train_ls[-1], valid_ls[-1]))
    return train_l_sum / k, valid_l_sum / k

模型选择

我们使用一组未经调优的超参数并计算交叉验证误差。可以改动这些超参数来尽可能减小平均测试误差。

python 复制代码
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('%d-fold validation: avg train rmse %f, avg valid rmse %f' % (k, train_l, valid_l))
复制代码
fold 0, train rmse 0.169539, valid rmse 0.156727
fold 1, train rmse 0.162395, valid rmse 0.190494
fold 2, train rmse 0.163862, valid rmse 0.168476
fold 3, train rmse 0.167720, valid rmse 0.154207
fold 4, train rmse 0.162936, valid rmse 0.182907
5-fold validation: avg train rmse 0.165290, avg valid rmse 0.170562

预测并在Kaggle提交结果

下面定义预测函数。在预测之前,我们会使用完整的训练数据集来重新训练模型,并将预测结果存成提交所需要的格式。

python 复制代码
def train_and_pred(train_features, test_features, train_labels, test_data,
                   num_epochs, lr, weight_decay, batch_size):
    net = get_net(train_features.shape[1])
    train_ls, _ = train(net, train_features, train_labels, None, None,
                        num_epochs, lr, weight_decay, batch_size)
    d2l.semilogy(range(1, num_epochs + 1), train_ls, 'epochs', 'rmse')
    print('train rmse %f' % train_ls[-1])
    preds = net(test_features).detach().numpy()
    test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])
    submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)
    submission.to_csv('../data/kaggle_house/submission_1.csv', index=False)

设计好模型并调好超参数之后,下一步就是对测试数据集上的房屋样本做价格预测。如果我们得到与交叉验证时差不多的训练误差,那么这个结果很可能是理想的,可以在Kaggle上提交结果。

python 复制代码
train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size)
复制代码
train rmse 0.162583

上述模型无调参的情况下在Kaggle上的得分是0.16719。

参考李沐《动手学深度学习》

相关推荐
Biomamba生信基地27 分钟前
《Advanced Science》前沿工具发布:STAID,空间反卷积自优化深度学习框架
论文阅读·深度学习·生物信息学·模型训练
一次旅行30 分钟前
Deepseek-V4-Flash 快速部署与调用实战指南
人工智能·深度学习
凯丨2 小时前
让 AI 通宵优化神经网络:Karpathy autoresearch 的设计哲学与启示
人工智能·深度学习·神经网络
AI医影跨模态组学2 小时前
Sci. Adv.(IF=12.5)首都医科大学宣武医院卢洁等团队:一种用于预测乳腺癌新辅助化疗病理完全缓解的多模态全自动系统
人工智能·深度学习·论文·医学影像·影像组学
lucky_syq2 小时前
【深度学习核心】注意力机制(Attention)详细解析
人工智能·深度学习
砥锋4 小时前
图注意力网络(GAT)深度实战:原理推导+PyG代码+从零开始写GAT层(附注意力可视化)
深度学习·机器学习
动物园猫4 小时前
水面5种垃圾目标检测数据集分享(适用于YOLO系列深度学习分类检测任务)
深度学习·yolo·目标检测
AI算法沐枫4 小时前
机器学习经典小项目4:泰坦尼克号生存预测
人工智能·python·深度学习·线性代数·算法·机器学习·回归
君为先-bey5 小时前
LeMiCa——基于扩散的高效视频生成的词典序最小最大路径缓存
人工智能·深度学习·计算机视觉·扩散模型
今天吃饺子5 小时前
50种近五年主流深度学习模型×10种时频方法,故障诊断、分类一键跑通!
人工智能·深度学习·机器学习·分类·数据挖掘