深度学习 <实战Kaggle比赛:预测房价> 代码分析 跟李沐学AI

news2025/1/15 23:57:05

4.10. 实战Kaggle比赛:预测房价 — 动手学深度学习 2.0.0 documentation

若有错误请指出

一.数据处理部分

1.下载部分 没啥好说的 

import hashlib
import os
import tarfile
import zipfile
import requests

#@save
DATA_HUB = dict()
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'

def download(name, cache_dir=os.path.join('..', 'data')):  #@save
    """下载一个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


def download_extract(name, folder=None):  #@save
    """下载并解压zip/tar文件"""
    fname = download(name)
    base_dir = os.path.dirname(fname)
    data_dir, ext = os.path.splitext(fname)
    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.还是下载部分跟导包 也跳过

# 如果没有安装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

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')

3.读表

train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))#读表 

print(train_data.shape)
print(test_data.shape)

#形状是这样的
(1460, 81)
(1459, 80)

4.初步看看样本

print(train_data.iloc[0:4, [0, 1, 2, 3, -3, -2, -1]])


'''  注意第一行id对于训练没用 最后一行-1 是SalePrice 训练属于label(y)的部分 需要抽走
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
'''

5.抽走部分列

并all_features是两个表组合在了一起 以行形式叠加了    0-1459 调试点view dataframe拉到下面可以看到  所以下面抽取train的时候是0-1459 但表有2900多行  当时还愣了很久

all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))

6.数据处理

# 若无法获得测试数据,则可根据训练数据计算均值和标准差
#pandas的 object是python的string  此处是提取所有非string字符串的部分,就是数字部分(包括NAN)的index 列数
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
#fillna不是fill一开始看错了没看懂啥意思  就是所有na全变0了
all_features[numeric_features] = all_features[numeric_features].fillna(0)

这里方便理解 进调试模式debug 点view dataframe

 可以很直观看出MSZoning Street Alley LotShape LandContous这些是字符串项

 故numeric_features 得到的是 纯数字列的列名

然后对所有这些列 all_features[numeric_features]  通过将特征重新缩放到零均值和单位方差来标准化数据,好处:首先,它方便优化。 其次,因为我们不知道哪些特征是相关的, 所以我们不想让惩罚分配给一个特征的系数比分配给其他任何特征的系数更大。

原文:

 处理之后  明显看出都相应变小了 脱离了原本的大数值,领本身拥有对应的特征

 不懂之处1:但是代码注释的'所有均值消失'不知道什么意思

之后填充nan数值为0 之后变成 

这部分看不懂可以回想一下这小节 2.2. 数据预处理 — 动手学深度学习 2.0.0 documentation

7.

# “Dummy_na=True”将“na”(缺失值)视为有效的特征值,并为其创建指示符特征
all_features = pd.get_dummies(all_features, dummy_na=True)
all_features.shape

看不懂可以看看 【机器学习】pd.get_dummies()_pd.getdummies_洋气月的博客-CSDN博客 分类编程纯数字编码 0 1   也叫one hot

方便理解看看这列Alley  执行 all_features = pd.get_dummies(all_features, dummy_na=True)这行之前 

之后 alley列不见了 变成了   strng分类问题变成 01分类

以上步骤就把所有string转成了 只有数字的形式 这就是1-7步骤做的初步训练 

这种模式可以进行训练了 但是数据形式还要变一变    

''可以看到此转换会将特征的总数量从79个增加到331个。 最后,通过values属性,我们可以 从pandas格式中提取NumPy格式,并将其转换为张量表示用于训练。''

8.注意all_features是两个表,此处取第一个表所以是

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)

all_features[:n_train]    0-1459行 所有列的values

先别急,看看 all_features[:n_train].values的样子

列名变成数字 符合输入形式

而test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32)

从n_train开始 就是取第二个表

因为all_features中已经删了saleprice的列了 要从原始train表取 并初始化成n*1的列向量形式

train_labels = torch.tensor(train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32)

二.训练部分

1.loss选均方损失函数   net选单层线性就是 Y=WX+b  

loss = nn.MSELoss()
in_features = train_features.shape[1]

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

2.新增log_rmse处理误差  有点复杂

老师原话:房价就像股票价格一样,我们关心的是相对误差,而不是绝对误差。比如房价原本12.5万,误差10万;和房价原本420万,误差10万;显然是不一样的。即:

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.不再用sgd优化而用Adam 老师说后面章节会讲我也还没看到 

Adam 对初始学习率不那么敏感

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

4.K折交叉验证

4.4. 模型选择、欠拟合和过拟合 — 动手学深度学习 2.0.0 documentation

视频有详细讲解12分前后  11 模型选择 + 过拟合和欠拟合【动手学深度学习v2】_哔哩哔哩_bilibili

比如一张长条纸按照固定成K次,就K折了 每次取K-1个训练 剩下最后一个用来验证,而一共需要进行这样的操作K次循环,

翻到下面可以看到K取了5,带去k_fold来分析

fold_size = X.shape[0] // k

fold_size=1460/5 取整=292 这里刚好能整除  就是1460行折5下 每个区域292行

def get_k_fold_data(k, i, X, y):
    assert k > 1  
    fold_size = X.shape[0] // k  #整除k 一开始看成java的注释了
    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], 0)
            y_train = torch.cat([y_train, y_part], 0)
    return X_train, y_train, X_valid, y_valid

已知fold_size=292  k=5  进入for循环 我们假定本次i为4 即是最后一次

slice()是内置函数本身就返回一个slice对象,可以被用于任何可以被切片的地方 左开右闭取0到291的值

j=0时,idx = slice(0, 292)  , X_part, y_part = X[idx, :], y[idx]

X_part为从X取0到291行的所有列;y_part为0,291行,因为只有一列就不用写后面的:

接着判断j是否为指定的i=4 本次j是0≠4

进入第一个elif 发现X_train为None,故进行第一次赋值X_train, y_train = X_part, y_part,之后结束本次循环

j=1时,idx =slice(292, 584), X_part为从X取292到583行的所有列;y_part为292到583行,本次j是1≠4

进入第一个elif 发现X_train不为None,故进入else,追加赋值cat,按行追加下去,之后结束本次循环

可以用这段进行验证:

#j>=i假如设置的j大于等于i,证明有一段折是给验证集的,于是减1,而此处结果为bool类型 于是+0强制转换成1
#而e1的第(j-((j>=i)+0)) * fold_size(比如292)就是X-part加上去的第一个
e1=X_train[(j-((j>=i)+0)) * fold_size]
e2=X_part[1]
c = e1.eq(e2).sum()#没想到更好的办法解决了 用e1和e2比较结果会出现全true的tensor 这时候sum把true全加起来 如果全true就是全1 加起来数字就是总列数331 
print(c.item()==X_train[1].shape[0])
#可以debug详细看看
#c.item() 从tensor中取数值
#X_train[1].shape是  tensor.size类型 取出来要用
#X_train[1].shape[0]

cat不熟悉的可以看看这图

j=2时,idx =slice(584, 876), X_part为从X取584到875行的所有列;y_part为584到875行,本次j是2≠4

追加赋值cat,之后结束本次循环

j=3时,idx =slice(876, 1168), X_part为从X取876到1167行的所有列;y_part为876到1167行,本次j是3≠4

追加赋值cat,之后结束本次循环

j=4时,idx =slice(1168, 1460), X_part为从X取1168到1459行的所有列;y_part为1168到1459行,本次j是4=4,因为此次等于用X_part,y_part做验证集,之后结束本次循环,结束所有循环返回对应参数

k_fold部分

train_l_sum += train_ls[-1]#只取最后第100次用训练好的参数的对训练y的损失

valid_l_sum += valid_ls[-1]##只取最后第100次用训练好的参数的对验证y的损失

不懂之处2:没太搞懂valid_l_sum是训练一次之后同时再验证一次吗?

否则全训练完用训练的参数验证valid_l_sum结果的话应该取平均?

画图部分不说了

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折做k次,0~(k-1)
        data = get_k_fold_data(k, i, X_train, y_train) #data 是四个参数 训练x,y 验证x,y
        net = get_net() #取出net 此处是线性
        train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,
                                   weight_decay, batch_size) #放入k折处理后的数据 
        #train_ls,valid_ls  返回100次epoch每次得到的值组合起来的训练损失
        train_l_sum += train_ls[-1]#只取最后第100次用训练好的参数的对训练y的损失

        valid_l_sum += valid_ls[-1]##只取最后第100次用训练好的参数的对验证y的损失
        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

返回训练损失和验证之和/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}')

需要显示图可以加

d2l.plt.show()

接下来是验证所有数据集

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)

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

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

相关文章

2-8 SpringCloud快速开发入门: Eureka 注册中心高可用集群搭建

Eureka 注册中心高可用集群搭建 Eureka 注册中心高可用集群就是各个注册中心相互注册 Eureka Server的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这样就会形成一组互相注册的服务注册中心,进而实现服务清单的互相同步,往注…

【博学谷学习记录】超强总结,用心分享丨人工智能 机器学习 逻辑回归模型遗漏知识点总结

目录激活函数逻辑回归的优缺点总结LR可以进行多分类吗?激活函数 h(w)表示输入的线性方程 逻辑回归的优缺点总结 优点: 形式简单,模型的可解释性非常好。从特征的权重可以看到不同的特征对最后结果的影响,某个特征的权重值比较高…

Docker搭建redis-cluster集群

以下是搭建redis-cluster集群,该集群是redis3.0引进了的,该集群比redis-sentinel哨兵架构有以下优点 可以配置多主多从,在redis设置内存可以更大,而哨兵只能配置一主多从,且单个主节点内存不宜设置过大,否…

操作系统内核与安全分析课程笔记【0】环境搭建

本学期选择了游伟和黄建军老师的操作系统内核分析与安全,目前已经试听了第一节课。这门的授课老师建了一个网页用于收录本次课程的幻灯片材料,录屏材料,以及软件安装包等一系列课程用得到的材料。对于学生而言,这是一门既硬核能够…

【机器学习】机器学习实验三:集成算法1(详细代码展示)

文章目录一、实验介绍1.1 简单介绍1.2 Breast Cancer 数据实验1.3 Boston 数据实验二、项目地址三、算法结果展示一、实验介绍 1.1 简单介绍 AdaBoost 和 Random Forest 算法的原理 1.2 Breast Cancer 数据实验 对 Breast Cancer 数据进行探索性数据分析; 数据预…

VMware虚拟机安装ubuntu系统在虚拟机中全屏以及主机和虚拟机之间文件的复制

一、从Wndows复制文字到VMware(Linux) List item 今天需要用到了Linux操作系统。在VMware装上linux之后经常面临这样一个问题,那就是很多指令很长,逐字去敲显然费时费力。 按照惯例我也查了几种方法,然而要么就是需要…

API 接口测试经验分享

接口开发完成后,我们需要调用接口来测试接口的表现,当表现符合预期时,则代表接口可用。 在测试中我们可能会关注状态码、响应体以及响应时间,这些数据 Postcat 通通都会展示给你,判断 API 是否正常。 开始测试之前&…

pytorch-把线性回归实现一下。原理到实现,python到pytorch

线性回归 线性回归输出是一个连续值,因此适用于回归问题。回归问题在实际中很常见,如预测房屋价格、气温、销售额等连续值的问题。 与回归问题不同,分类问题中模型的最终输出是一个离散值。所说的图像分类、垃圾邮件识别、疾病检测等输出为离…

ModStartBlog v6.8.0 博客置顶功能,界面样式优化

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用,支持后台一键快速安装,让开发者能快的实现业务功能开发。 系统完全开源,基于 Apache 2.0 开源协议。 功能特性 丰富的模块市场,后台一键快速安装 …

2-7 SpringCloud快速开发入门: Eureka 服务注册中心发现与消费服务

Eureka 服务注册中心发现与消费服务 我们已经搭建一个服务注册中心,同时也向这个服务注册中心注册了服务,接下来我们就可以发现和消费服务了,这其中服务的发现由 eureka 客户端实现,而服务的消费由 Ribbon 实现,也就是…

10组小程序界面设计案例分享

10组小程序界面设计分享而对于设计师来说,小程序的设计也相对 APP 简单和直接,在这里分享给大家一些小程序界面设计案例,包含多种类别:出游旅行类、电商购物类、电商家居类、生活社区类、快递物流类、智能家居类、在线文档类、书籍…

基于四信网络摄像机的工业自动化应用

方案背景 随着数控机床被广泛的应用在工业生产中,数控技术发展成为制造业的核心。 鉴于数控机床的复杂性,以及企业人力储备有限,设备的监控和维护必须借助外部力量,而如何实现车间实时监测成了目前迫切解决的问题。 方案需求 ①兼…

PHP使用chilkat入门教程

前言: 我们需要先确认自己的版本,在PHP中,可以利用phpinfo()函数来查看php是ts版本还是nts版本,该方法可以展示出当前phpinfo信息,若“Thread Safety”项的信息是“enabled”,一般来说就表示ts版本&#xf…

什么是接口测试,我们如何实现接口测试?

1. 什么是接口测试 顾名思义,接口测试是对系统或组件之间的接口进行测试,主要是校验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系。其中接口协议分为HTTP,WebService,Dubbo,Thrift,Socket等类型,测试类型又主…

Hbase限流 -- HBase Quota调研

1 背景 HBase的生产环境中,每个业务之间的重要性是不一致的,每个业务的数据量、读写需求也不一致,一个集群中往往有很多个业务,有的同学可以执行一个耗时的scan操作,整个集群的资源被大量占用,其它非常重要…

【Servlet篇2】创建一个web项目

在上一篇文章当中,已经提到了什么是Maven,以及如何使用maven从中央仓库下载jar包。【Tomcat与Servlet篇1】认识Tomcat与Maven_革凡成圣211的博客-CSDN博客Tomcat,mavenhttps://blog.csdn.net/weixin_56738054/article/details/129228140?spm…

vue 3 第六章:to全家桶

文章目录1. toRef1.1. 使用toRef函数2. toRefs2.1. 使用toRefs函数3. toRaw3.1. 使用toRaw函数1. toRef 将一个对象中的属性转换成单独的响应式引用接收两个参数:参数一 > 对象 参数二 > 属性转换后的响应式引用会跟踪原始属性的变化转换后的响应式可以被用于…

Mysql从基础入门(1)之数据库建表和增删改

文章目录数据库的介绍1.ER图2.约束Mysql常用命令数据库定义(DDL)1.DDL操作数据库2.DDL操作表操作数据(DML)1. 添加数据2. 修改数据3. 删除数据数据库的介绍 数据库:存储和管理数据的仓库,数据是有组织的进…

java 2(程序流程控制)【含例题详解】

java ——程序流程控制 ✍作者:电子科大不知名程序员 🌲专栏:java学习指导 各位读者如果觉得博主写的不错,请诸位多多支持;如果有错误的地方,欢迎在评论区指出 目录java ——程序流程控制分支结构if-elsesw…

【Redis学习1】Redis安装

Redis基础 什么是Redis REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。 Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-…