动手学深度学习——实战Kaggle比赛:预测房价(代码详解+调参优化)

news2024/9/29 3:33:03

目录

  • 1. 下载和缓存数据集
  • 2. Kaggle
  • 3. 访问和读取数据集
  • 4. 数据预处理
  • 5. 训练
  • 6. K折交叉验证
  • 7. 模型选择
  • 8. 提交Kaggle预测
  • 9. 调参优化

1. 下载和缓存数据集

数据集百度云:
链接:https://pan.baidu.com/s/14CVZBjmlKA_c3MYNFLSvbg?pwd=pysi 提取码:pysi
1、导入包

# 导入所需要的包
import hashlib
import os
import tarfile
import zipfile
import requests

#@save
# DATA_HUB为二元组:包含数据集的url和验证文件完整性的sha-1密钥
DATA_HUB = dict()

# 数据集托管在DATA_URL的站点上
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'

2、下载数据集并保存数据集

  • os.makedirs(cache_dir, exist_ok=True):创建目录,exist_ok = True指定了,如果某个要创建的目录已经存在,也不报错。
  • shal.sha1():创建一个字符串hashlib_,并将其加密后传入。
  • os.path.join():连接两个或更多的路径名组件
    1.如果各组件名首字母不包含’/’,则函数会自动加上
    2.如果有一个组件是一个绝对路径,则在它之前的所有组件均会被舍弃
    3.如果最后一个组件为空,则生成的路径以一个’/’分隔符结尾
"""
    定义download函数:
    1、下载数据集,将数据集缓存在本地目录(../data),并返回下载文件的名称
    2、如果缓存目录中存在此数据集文件,并且与sha-1与存储在DATA_HUB中相匹配,则使用缓存的文件
"""
# download(文件名称,缓存目录)
def download(name, cache_dir=os.path.join('..', 'data')): #@save
    """下载一个DATA_HUB中的文件,返回本地文件名"""
    # 判断数据集是否存在于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:
                    break
                sha1.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

3、将下载的数据集进行解压操作

"""
    实现两个实用函数:
    1、一个将下载并解压缩一个zip/tar文件
    2、将使用的数据集从DATA_HUB下载到缓存目录
"""
def download_extract(name, folder=None): #@save
    """下载并解压zip/tar文件"""
    fname = dowanload(name)
    base_dir = os.path.dirname(fname)
    data_dir = os.path.splitext(fname)
    
    # 只对zip/tar/gz格式的压缩文件进行解压
    if ext == '.zip':
        fp = zipfile.Zipfile(fname, 'r')
    elif ext in ('.tar', '.gz'):
        fp = tarfile.open(fname, 'r')
    else:
        assert False, '只有zip/tar文件可以解压'
    fp.extractall(base_dir)
    return os.path.join(base_dir, folder) if folder else data_dir

def download_all(): #@save
    """下载DATA_HUB中的所有文件"""
    for name in DATA_HUB:
        download(name)

2. Kaggle

Kaggle是一个当今流行举办机器学习比赛的平台,这里是房价预测比赛页面https://www.kaggle.com/c/house-prices-advanced-regression-techniques。

3. 访问和读取数据集

1、安装并导入pandas等包

# 如果没有安装pandas,请取消下一行的注释
# !pip install pandas

%matplotlib inline
import numpy as np
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2l

2、使用定义的脚本下载并缓存Kaggle房屋数据集

# 使用上面定义的脚本下载并缓存Kaggle房屋数据集
DATA_HUB['kaggle_house_train'] = (  #@save
    DATA_URL + 'kaggle_house_pred_train.csv',
    '585e9cc93e70b39160e7921475f9bcd7d31219ce')

DATA_HUB['kaggle_house_test'] = (  #@save
    DATA_URL + 'kaggle_house_pred_test.csv',
    'fa19780a7b011d9b009e8bff8e99922a8ee2eb90')
# 使用pandas分布加载包含训练数据和测试数据的两个csv文件
train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))

这里查看一下样本特征

# 训练数据集包括1460个样本,每个样本80个特征和1个标签
# 测试数据集包括1459个样本,每个样本80个特征
print(train_data.shape)
print(test_data.shape)

在这里插入图片描述

# 前四个和最后两个特征,以及相应标签(房价)
print(train_data.iloc[0:4, [0, 1, 2, 3, -3, -2, -1]])

在这里插入图片描述
3、对于每个样本:删除第一个特征ID,因为其不携带任何用于预测的信息

# 对于每个样本:删除第一个特征ID,因为其不携带任何用于预测的信息
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:-1]))

4. 数据预处理

1、对数据进行标准化处理

"""
    数据预处理:
    1、将所有缺失的值替换为相应特征的平均值
    2、为了将所有数据放在共同的尺度上,通过特征重新缩放到零均值和单位方差来标准化数据
        (1)方便优化
        (2)不知道哪些特征是相关的,所以不想让惩罚分配给一个特征的系数比分配给其他特征的系数更大
    3、处理离散值,用独热编码来替换。如"MSZoning_RL"为1,"MSZoning_RM"为0
"""
# 若无法获得测试数据,则可根据训练数据计算均值和标准差:x←(x-μ)/σ
# 获取无法获得测试数据的数量
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
all_features[numeric_features] = all_features[numeric_features].fillna(0)

2、将缺失值进行替换

#“Dummy_na=True”将“na”(缺失值)视为有效的特征值,并为其创建指示符特征
# all_features是删除ID那一列之后,将每个样本中所有的特征连接起来
all_features = pd.get_dummies(all_features, dummy_na=True)
all_features.shape

在这里插入图片描述
3、通过values属性,我们可以 从pandas格式中提取NumPy格式,并将其转换为张量表示用于训练。

# 通过values属性将数据从pandas格式提取numpy格式,并将其转为张量用于训练
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)

5. 训练

1、定义损失函数和模型

"""
    训练一个带有损失平方的线性模型:
    1、损失函数为损失平方
    2、线性模型作为基线模型
"""
loss = nn.MSELoss()
in_features = train_features.shape[1]

def get_net():
    net = nn.Sequential(nn.Linear(in_features,1))
    return net

2、采用价格预测的对数来衡量差异

  • clamp():功能将输入input张量每个元素的值压缩到区间 [min,max],并返回结果到一个新张量。
# 采用价格预测的对数来衡量差异:√ ̄(1/n*(∑(logy - logy')^2))
def log_rmse(net, features, labels):
    # 为了在取对数时进一步稳定该值,将小于1的值设置为1
    clipped_preds = torch.clamp(net(features), 1, float('inf'))
    rmse = torch.sqrt(loss(torch.log(clipped_preds),
                          torch.log(labels)))
    return rmse.item()

3、进行训练,优化器借助Adam优化器

  • append:python中的一个函数,它主要是用来在列表末尾添加新的对象。
# 优化器借助Adam优化器
"""
    定义训练函数:
    1、加载训练数据集
    2、使用Adam优化器(对初始学习率不那么敏感)
    3、进行训练:计算损失,进行梯度优化,返回训练损失和测试损失
"""
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:
            optimizer.zero_grad() # 梯度归零
            l = loss(net(X), y) # 计算损失
            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

6. K折交叉验证

1、定义K折交叉验证

  • cat() 函数: 在给定维度上对输入的张量序列seq 进行连接操作。
"""
    定义K折交叉验证:
    1、当k > 1时,进行K折交叉验证,将数据集分为K份
    2、选择第i个切片作为验证集,其余部分作为训练数据
    3、第一片的训练数据直接填进去,之后的使用cat进行相连接
""" 
def get_k_fold_data(k, i, X, y):
    # 假设k折大于1,将数据集分成k份
    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]
        
        # 将第i片数据集作为验证集
        if j == i:
            X_valid, y_valid = X_part, y_part
            
        # 其他余下的片作为训练集
        elif X_train is None:
            X_train, y_train = X_part, y_part
            
        # 使用cat()函数将余下的训练集片进行拼接
        else:
            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

2、在K折交叉验证中训练K次

"""
    在K折交叉验证中训练K次:
    1、返回训练和验证误差的平均值
    2、可视化训练误差和验证误差
"""
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):
        # 进行k折交叉验证
        data = get_k_fold_data(k, i, X_train, y_train)
        net = get_net()
        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.plot(list(range(1, num_epochs + 1)), [train_ls, valid_ls],
                     xlabel='epoch', ylabel='rmse', xlim=[1, num_epochs],
                     legend=['train', 'valid'], yscale='log')
        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

7. 模型选择

1、选择一组未调优的超参数。
k折:5,迭代轮数:100,学习率:5,权重:0,批量大小:64

# 模型选择
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}')

在这里插入图片描述

8. 提交Kaggle预测

"""
    提交Kaggle预测:
    1、使用所有数据进行训练,得到模型
    2、该模型可以应用到测试集上,将预测保存在csv文件
"""
def train_and_pred(train_features, test_features, train_labels, test_data,
                  num_epochs, lr, weight_decay, batch_size):
    net = get_net()
    train_ls, _ = train(net, train_features, train_labels, None, None,
         num_epochs, lr, weight_decay, batch_size)
    d2l.plot(np.arange(1, num_epochs + 1), [train_ls], xlabel='epoch',
            ylabel='log rmse', xlim=[1, num_epochs], yscale='log')
    print(f'训练log rmse:{float(train_ls[-1]):f}')
    # 将网络应用与测试集。
    preds = net(test_features).detach().numpy()
    # 将其重新格式化以导出到Kaggle
    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)

在这里插入图片描述

9. 调参优化

因为之前是给的未优化的超参数,我们可以对k, num_epochs, lr, weight_decay, batch_size进行调参优化,这里给出一组超参数:

k, num_epochs, lr, weight_decay, batch_size = 8, 150, 6, 0, 64

在这里插入图片描述
在这里插入图片描述
其他的超参数可以试一下

组别\超参数knum_epochslrweight_decaybatch_size训练损失验证损失测试损失
原始510050640.16530.17050.1628
第一组510080640.15390.16300.1460
第二组610080640.15340.16090.1460
第三组810080640.15120.15930.1460
第五组1210080640.14880.15530.1456
第六组2010080640.14750.15430.1457
第七组815060640.14470.15370.1404
第八组1220080640.12990.14320.1288
第九组2030080640.12480.14700.1247
第十组810080320.13310.14500.1308
第十一组1220080320.12400.14700.1243

这里只是针对线性模型的部分参数优化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/804506.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

脚手架(vue-cli)的安装详细教程

首先要下载node.js 下载 | Node.js 中文网 (nodejs.cn)https://nodejs.cn/download/ 大家根据自己的系统来选择哪个,我是Windows系统,所以选择红色箭头所指的安装包去安装!!! 接下来双击安装!!…

Docker 如何助您成为数据科学家

一、说明 在过去的 5 年里,我听到了很多关于 docker 容器的嗡嗡声。似乎我所有的软件工程朋友都在使用它们来开发应用程序。我想弄清楚这项技术如何使我更有效率,但我发现网上的教程要么太详细:阐明我作为数据科学家永远不会使用的功能&#…

英伟达 H100 vs. 苹果M2,大模型训练,哪款性价比更高?

M1芯片 | Uitra | AMD | A100 M2芯片 | ARM | A800 | H100 关键词:M2芯片;Ultra;M1芯片;UltraFusion;ULTRAMAN;RTX4090、A800;A100;H100;LLAMA、LM、AIGC、CHATGLM、LLVM、LLM、LLM…

C语言每日一题之整数求二进制1的个数

今天分享一道题目&#xff0c;用三种方法来求解 二进制1的个数 方法1 我们的十进制除10和取余数就可以得到我们每一位的数字&#xff0c;那我们的二进制也可 以 #include<stdio.h> int num_find_1(unsigned int n) {int count 0;while (n){if (1 n % 2){count;}n / 2…

python实现某品牌数据采集

某品牌数据采集 采集需求 地址&#xff1a;http://www.winshangdata.com/brandList 需求&#xff1a;用scrapy框架采集本站数据&#xff0c;至少抓取5个分类&#xff0c;数据量要求5000以上 采集字段&#xff1a;标题、创建时间、开店方式、合作期限、面积要求 网页分析 …

JSP 配置环境的搭建快速入门

JSP搭建环境 创建一个maven的 web 项目&#xff0c;项目结构如下&#xff1a; pom.xml 文件内容如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http:/…

第一百一十七天学习记录:高等数学:向量代数与空间解析几何(上)(宋浩板书)

在数学中&#xff0c;向量是一组按特定顺序排列的数&#xff0c;也可以是其他类型的元素&#xff0c;例如复数或矩阵。向量通常用加粗的小写字母表示&#xff0c;例如 v \mathbf{v} v&#xff0c;其中每个数值或元素称为向量的分量。向量可以表示空间中的方向和大小&#xff0…

【触觉智能Purple Pi OH开发板体验】开箱体验:开源主板Purple Pi RK3566 上手指北

前言 前段时间收到来自【电子发烧友】的一款开发板&#xff0c;名叫&#xff1a;PurplePi&#xff0c;216G售价仅249元。它使用的芯片是rk3566&#xff0c;适配的OpenHarmony版本为3.2 Release 是目前最便宜的OpenHarmony标准系统开源开发板&#xff0c;并且软硬件全部开源&am…

VMPWN的入门级别题目详解(二)

实验四 VMPWN4 题目简介 这道题应该算是虚拟机保护的一个变种&#xff0c;是一个解释器类型的程序&#xff0c;何为解释器&#xff1f;解释器是一种计算机程序&#xff0c;用于解释和执行源代码。解释器可以理解源代码中的语法和语义&#xff0c;并将其转换为计算机可以执行的…

数据结构:线索二叉树

线索二叉树 通过前面对二叉树的学习&#xff0c;了解到二叉树本身是一种非线性结构&#xff0c;采用任何一种遍历二叉树的方法&#xff0c;都可以得到树中所有结点的一个线性序列。在这个序列中&#xff0c;除第一个结点外&#xff0c;每个结点都有自己的直接前趋&#xff1b;…

MySql忘记密码如何修改

前言 好久没用数据库的软件了&#xff0c;要用的时候突然发现密码已经忘记了&#xff0c;怎么试都不对&#xff0c;心态直接爆炸&#xff0c;上一次用还是22年6月份&#xff0c;也记不得当时用数据库干什么了&#xff0c;这份爆炸浮躁的心态值得这样记录一下&#xff0c;警示自…

国内常见的16款低代码开发平台介绍

本文给大家讲解3种不同方向的低代码/无代码开发平台。 第一种&#xff1a;企业级低代码开发平台&#xff0c;企业级这一概念是指&#xff1a;能把企业方方面面的业务需求全都能覆盖到&#xff0c;&#xff08;包括很多定制化且高度复杂的核心应用系统&#xff0c;如ERP、MES、…

浅析嵌入式GUI框架-LVGL

LVGL是什么&#xff1f; LVGL (Light and Versatile Graphics Library) 是最流行的免费开源嵌入式图形库&#xff0c;可为任何 MCU、MPU 和显示类型创建漂亮的 UI。 嵌入式GUI框架对比 Features/框架LVGLFlutter-elinuxArkUI(鸿蒙OS)AWTKQTMIniGUIemWinuC/GUI柿饼UI跨平台…

神经数据库:用于使用 ChatGPT 构建专用 AI 代理的下一代上下文检索系统 — (第 2/3 部分)

书接上回理解构建LLM驱动的聊天机器人时的向量数据库检索的局限性 - &#xff08;第1/3部分&#xff09;_阿尔法旺旺的博客-CSDN博客 其中我们强调了&#xff08;1&#xff09;嵌入生成&#xff0c;然后&#xff08;2&#xff09;使用近似近邻&#xff08;ANN&#xff09;搜索…

Reinforcement Learning with Code 【Chapter 8. Value Funtion Approximation】

Reinforcement Learning with Code This note records how the author begin to learn RL. Both theoretical understanding and code practice are presented. Many material are referenced such as ZhaoShiyu’s Mathematical Foundation of Reinforcement Learning, . 文章…

2.9 线性表的划分

划分规则: 以某个元素为标准, 把顺序表中的元素分为左右两个部分, 标准元素称为枢轴. 考研中划分有三种题型(划分策略). 题型一 要求: 给一个顺序表, 以第一个元素为枢轴, 将该顺序表划分为左右两部分, 使得左边的所有元素都小于枢轴, 右边的所有元素都大于枢轴. 并且枢轴要…

基于Java+SpringBoot+vue前后端分离大学生就业招聘系统设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

【雕爷学编程】Arduino动手做(174)---Sensor Shield V5.0传感器扩展板

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

c++学习(位图)[22]

位图 位图&#xff08;Bitmap&#xff09;是一种数据结构&#xff0c;用于表示一个固定范围的布尔值&#xff08;通常是0或1&#xff09;。它使用一个二进制位来表示一个布尔值&#xff0c;其中每个位的值表示对应位置的元素是否存在或满足某种条件。 位图可以用于解决一些特…