深度学习--------------Kaggle房价预测
目录
- 下载和缓存数据集
- 访问和读取数据集
- 总代码
- 数据预处理
- 训练
- K折交叉验证
- 模型选择
- 总代码
- 提交你的Kaggle预测
- 提交Kaggle
下载和缓存数据集
import hashlib
import os
import tarfile
import zipfile
import requests# download传递的参数分别是数据集的名称、缓存文件夹的路径
def download(name, cache_dir=os.path.join('..', 'data')): # @save"""下载一个DATA_HUB中的文件,返回本地文件名"""# 检查变量name是否存在于名为DATA_HUB的字典中,如果是异常则给出消息提示assert name in DATA_HUB, f"{name} 不存在于 {DATA_HUB}"# 检查与name相对应的元组并解包赋值给url和sha1_hashurl, sha1_hash = DATA_HUB[name]os.makedirs(cache_dir, exist_ok=True)# 缓存的路径和目标目录,[-1]:url指向文件名fname = os.path.join(cache_dir, url.split('/')[-1])if os.path.exists(fname): # 检查文件是否存在sha1 = hashlib.sha1() # 计算文件的哈希值,初始化哈希对象# with确保文件在使用后正确关闭with open(fname, 'rb') as f: # 读取文件内容while True: # 循环读取文件内容并更新哈希对象data = f.read(1048576) # 读取1MB到dataif not data: # 为真跳出break# 将读取到的数据块更新到哈希对象中sha1.update(data)# 检查计算出的哈希值是否与预期的哈希值匹配if sha1.hexdigest() == sha1_hash:return fname # 命中缓存print(f'正在从{url}下载{fname}...')# 发送get请求并设置stream=True支持流式传输r = requests.get(url, stream=True, verify=True)with open(fname, 'wb') as f: # 写入模式f.write(r.content)return fname# folder=None是指解压后数据应存放的文件名,如未指定则默认使用去除扩展名后的文件名作为文件夹名
def download_extract(name, folder=None): # @save"""下载并解压zip/tar文件"""# 下载文件,并返回下载的完整路径fnamefname = download(name)# 获取下载文件所在的基本目录base_dir = os.path.dirname(fname)# 从文件名中分离出扩展名exe和数据目录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文件可以被解压缩'# 使用extractall方法将文件解压到基本目录,如果指定了folder参数,则返回base_dir和folder组合的路径# 否则返回去除扩展名后的文件名作为路径fp.extractall(base_dir)return os.path.join(base_dir, folder) if folder else data_dirdef download_all(): # @save"""下载DATA_HUB中的所有文件"""for name in DATA_HUB:download(name)# @save
DATA_HUB = dict() # 这是一个字典,用来存储数据集的信息。
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/' # 指向一个存储了多个数据集文件的服务器
访问和读取数据集
import numpy as np
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2l
下载并缓存Kaggle房屋数据集
DATA_HUB['kaggle_house_train'] = ( #@saveDATA_URL + 'kaggle_house_pred_train.csv','585e9cc93e70b39160e7921475f9bcd7d31219ce')DATA_HUB['kaggle_house_test'] = ( #@saveDATA_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]])
输出:
在每个样本中,第一个特征是ID, 这有助于模型识别每个训练样本。 虽然这很方便,但它不携带任何用于预测的信息。 因此,在将数据提供给模型之前,(我们将其从数据集中删除)。
# 删除train_data的第一列ID和最后一列房价;删除test_data的第一列索引
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))
# 查看一下
print(all_features)
输出:
总代码
import hashlib
import os
import tarfile
import zipfile
import requests
import pandas as pd# download传递的参数分别是数据集的名称、缓存文件夹的路径
def download(name, cache_dir=os.path.join('..', 'data')): # @save"""下载一个DATA_HUB中的文件,返回本地文件名"""# 检查变量name是否存在于名为DATA_HUB的字典中,如果是异常则给出消息提示assert name in DATA_HUB, f"{name} 不存在于 {DATA_HUB}"# 检查与name相对应的元组并解包赋值给url和sha1_hashurl, sha1_hash = DATA_HUB[name]os.makedirs(cache_dir, exist_ok=True)# 缓存的路径和目标目录,[-1]:url指向文件名fname = os.path.join(cache_dir, url.split('/')[-1])if os.path.exists(fname): # 检查文件是否存在sha1 = hashlib.sha1() # 计算文件的哈希值,初始化哈希对象# with确保文件在使用后正确关闭with open(fname, 'rb') as f: # 读取文件内容while True: # 循环读取文件内容并更新哈希对象data = f.read(1048576) # 读取1MB到dataif not data: # 为真跳出break# 将读取到的数据块更新到哈希对象中sha1.update(data)# 检查计算出的哈希值是否与预期的哈希值匹配if sha1.hexdigest() == sha1_hash:return fname # 命中缓存print(f'正在从{url}下载{fname}...')# 发送get请求并设置stream=True支持流式传输r = requests.get(url, stream=True, verify=True)with open(fname, 'wb') as f: # 写入模式f.write(r.content)return fname# folder=None是指解压后数据应存放的文件名,如未指定则默认使用去除扩展名后的文件名作为文件夹名
def download_extract(name, folder=None): # @save"""下载并解压zip/tar文件"""# 下载文件,并返回下载的完整路径fnamefname = download(name)# 获取下载文件所在的基本目录base_dir = os.path.dirname(fname)# 从文件名中分离出扩展名exe和数据目录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文件可以被解压缩'# 使用extractall方法将文件解压到基本目录,如果指定了folder参数,则返回base_dir和folder组合的路径# 否则返回去除扩展名后的文件名作为路径fp.extractall(base_dir)return os.path.join(base_dir, folder) if folder else data_dirdef download_all(): # @save"""下载DATA_HUB中的所有文件"""for name in DATA_HUB:download(name)# @save
DATA_HUB = dict() # 这是一个字典,用来存储数据集的信息。
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/' # 指向一个存储了多个数据集文件的服务器
# 第二个参数:表示数据集文件的哈希值,用哈希值验证文件的完整性
DATA_HUB['kaggle_house_train'] = (DATA_URL + 'kaggle_house_pred_train.csv','585e9cc9370b9160e7921475fbcd7d31219ce')
DATA_HUB['kaggle_house_test'] = (DATA_URL + 'kaggle_house_pred_test.csv', 'fal9780a7b011d9b009e8bff8e99922a8ee2eb90')
# 读取路径指向的csv文件
train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))print(train_data.shape) # 1460个样本,80个特征,1个标号label
print(test_data.shape) # 测试样本没有标号label
print(train_data.iloc[0:4,[0,1,2,3,-3,-2,-1]]) # 前面四行的某些列特征
输出:
数据预处理
如上所述,我们有各种各样的数据类型。 在开始建模之前,我们需要对数据进行预处理。 首先,我们将所有缺失的值替换为相应特征的平均值。然后,为了将所有特征放在一个共同的尺度上, 我们通过将特征重新缩放到零均值和单位方差来标准化数据:其中 𝜇 和 𝜎 分别表示均值和标准差。 现在,这些特征具有零均值和单位方差,即
和
直观地说,我们标准化数据有两个原因: 首先,它方便优化。 其次,因为我们不知道哪些特征是相关的, 所以我们不想让惩罚分配给一个特征的系数比分配给其他任何特征的系数更大。
# 若无法获得测试数据,则可根据训练数据计算均值和标准差
# all_features.dtypes 获取每个特征的数据类型
# all_features.dtypes != 'object' 返回一个布尔值的 Series,其中为 True 的位置表示对应的特征不是对象类型(即数值类型)
# .index 提取数值类型特征的索引,并在numeric_features中存储
print(all_features.dtypes) # 可以知道每一列分别为什么类型特征
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index
print(numeric_features)
# 对all_features中所有数值类型特征进行标准化处理
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)
输出:
接下来,我们处理离散值。 这包括诸如“MSZoning”之类的特征。我们用独热编码替换它们), 例如,“MSZoning”包含值“RL”和“Rm”。 我们将创建两个新的指示器特征“MSZoning_RL”和“MSZoning_RM”,其值为0或1。 根据独热编码,如果“MSZoning”的原始值为“RL”, 则:“MSZoning_RL”为1,“MSZoning_RM”为0。 pandas软件包会自动为我们实现这一点。
# “Dummy_na=True”将“na”(缺失值)视为有效的特征值,并为其创建指示符特征
# 未指定column时,pd.get_dummies函数默认转换所有的分类列,包括MSZoning、SaleType、SaleCondition
# pd.get_dummies每个分类变量都会被转换成多列,每个唯一值对应一列
# 理解意思:某列有五类值,就将此列等价于变成五列,然后对应的列置1,不存在的列置0
all_features = pd.get_dummies(all_features, dummy_na=True)
未改变时的数据特征:
# 这里仅验证看一下特征的形状
print(all_features.shape)
输出:
改变后:
all_features = pd.get_dummies(all_features, dummy_na=True)
print(all_features.shape)
输出:
可以看到此转换会将特征的总数量从79个(去掉ID)增加到331个。
最后,通过values属性,我们可以从pandas格式中提取NumPy格式,并将其转换为张量表示用于训练。
# 获取训练集的行数,即训练样本数量,并将其存储在n_train中
n_train = train_data.shape[0]
# [:n_train].values是选择前n_train作为训练集的特征将数据转换为Numpy数组
train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32)
test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32)
# 将SalePrice列单独提取为标签
train_labels = torch.tensor(train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32)
训练
首先,我们训练一个带有损失平方的线性模型。 显然线性模型很难让我们在竞赛中获胜,但线性模型提供了一种健全性检查,以查看数据中是否存在有意义的信息。 如果我们在这里不能做得比随机猜测更好,那么我们很可能存在数据处理错误。 如果一切顺利,线性模型将作为基线(baseline)模型, 让我们直观地知道最好的模型有超出简单的模型多少。
loss = nn.MSELoss()
in_features = train_features.shape[1]def get_net():net = nn.Sequential(nn.Linear(in_features,1))return net
房价就像股票价格一样,我们关心的是相对数量,而不是绝对数量。因此,我们更关心相对误差,而不是绝对误差 。 例如,如果我们在俄亥俄州农村地区估计一栋房子的价格时,假设我们的预测偏差了10万美元,然而那里一栋典型的房子的价值是12.5万美元,那么模型可能做得很糟糕。另一方面,如果我们在加州豪宅区的预测出现同样的10万美元的偏差,(在那里,房价中位数超过400万美元) 这可能是一个不错的预测。
(解决这个问题的一种方法是用价格预测的对数来衡量差异)。 事实上,这也是比赛中官方用来评价提交质量的误差指标。 即将转换为
。 这使得预测价格的对数与真实标签价格的对数之间出现以下均方根误差:
# rmse=Root Mean Squared Error,对数均方根误差
def log_rmse(net, features, labels):# 通过神经网络net对输入特征features进行前向传播得到预测值# 然后为了在取对数时进一步稳定该值,用torch.clamp()函数将小于1的值设置为1# 第三个参数:不设置上限,即预测可以无限大clipped_preds = torch.clamp(net(features), 1, float('inf'))rmse = torch.sqrt(loss(torch.log(clipped_preds),torch.log(labels)))# .item() 方法将rmse转换为Python标量返回return rmse.item()
我们的训练函数将借助Adam优化器,Adam优化器的主要吸引力在于它对初始学习率不那么敏感。
# weight_decay权重衰退
def train(net, train_features, train_labels, test_features, test_labels,num_epochs, learning_rate, weight_decay, batch_size):# 用于存储每一轮训练和测试集上的log rmse值train_ls, test_ls = [], []train_iter = d2l.load_array((train_features, train_labels), batch_size)# 这里使用的是Adam优化算法,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() # 更新模型参数# 将log_rmse函数返回的误差值追加到train_ls列表中就记录了每一轮迭代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折交叉验证有助于模型选择和超参数调整。定义一个函数,在 𝐾 折交叉验证过程中返回第 𝑖 折的数据。具体地说,它选择第 𝑖 个切片作为验证数据,其余部分作为训练数据。注意,这并不是处理数据的最有效方法,如果我们的数据集大得多,会有其他解决办法。
# 四个参数:表示将数据集分为多少个子集、当前折的索引、特征数据集、标签数据集
def get_k_fold_data(k, i, X, y):# 断言确保折数大于1,因为至少两个子集才能进行交叉验证assert k > 1# 每个子集(折)的大小=数据集的总行数除以折数,余数在最后一个子集处理fold_size = X.shape[0] // k# 初始化训练集X_train, y_train = None, Nonefor j in range(k):# 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]# 当前折的索引 j 与指定用于验证的索引 i 匹配,将该折的数据分配给验证集(X_valid 和 y_valid)if j == i:# 将该折的数据分配给验证集X_valid, y_valid = X_part, y_part# 如不匹配且训练集为空(第一次看到),则将该折的数据分配给训练集(X_train 和 y_train)elif X_train is None:X_train, y_train = X_part, y_part# 如不匹配且训练集不为空,则将该折的数据追加到训练集(X_train 和 y_train)中else:# 表示将X_train, X_part沿着第一个维度拼接起来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
在𝐾折交叉验证中训练𝐾次后,返回训练和验证误差的平均值。
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):# 做k次,每次拿到第i折,把数据data拿出来即拿到从训练集和验证集data = get_k_fold_data(k, i, X_train, y_train)# 每次循环都会创建一个新的模型实例,确保每折的评估是独立的net = get_net()# 调用train函数训练模型并返回训练损失列表和验证损失列表train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,weight_decay, batch_size)# 索引[-1]获取最后一个epoch的损失,即当前折的训练损失累加到train_l_sum train_l_sum += train_ls[-1]valid_l_sum += valid_ls[-1]if i == 0: # 如果当前是第i折# 第一个参数:用作x轴数据# 第二个参数:一个列表储存了每一轮训练后的训练损失和验证损失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折交叉验证往往对多次测试具有相当的稳定性。然而,如果我们尝试了不合理的超参数,我们可能会发现验证效果不再代表真正的误差。
#数据集被分成了5份,然后执行5次训练和验证过程,每次过程中,4份数据用于训练模型,剩下的一份用于
k, num_epochs, lr, weight_decay, batch_size = 5, 100, 5, 0, 64
# 分别包含每次迭代的训练集和验证集的log rmse值
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}')
我们关心的是平均验证log rmse
总代码
import hashlib
import os
import tarfile
import zipfile
import requests
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2ldef 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: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 fnamedef 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_dirdef download_all(): # @save"""下载DATA_HUB中的所有文件"""for name in DATA_HUB:download(name)def get_net():net = nn.Sequential(nn.Linear(in_features, 1))return net# rmse=Root Mean Squared Error,对数均方根误差
def log_rmse(net, features, labels):# 通过神经网络net对输入特征features进行前向传播得到预测值# 然后为了在取对数时进一步稳定该值,用torch.clamp()函数将小于1的值设置为1# 第三个参数:不设置上限,即预测可以无限大clipped_preds = torch.clamp(net(features), 1, float('inf'))rmse = torch.sqrt(loss(torch.log(clipped_preds),torch.log(labels)))# .item() 方法将rmse转换为Python标量返回return rmse.item()# weight_decay权重衰退
def train(net, train_features, train_labels, test_features, test_labels,num_epochs, learning_rate, weight_decay, batch_size):# 用于存储每一轮训练和测试集上的log rmse值train_ls, test_ls = [], []train_iter = d2l.load_array((train_features, train_labels), batch_size)# 这里使用的是Adam优化算法,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() # 更新模型参数# 将log_rmse函数返回的误差值追加到train_ls列表中就记录了每一轮迭代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# 四个参数:表示将数据集分为多少个子集、当前折的索引、特征数据集、标签数据集
def get_k_fold_data(k, i, X, y):# 断言确保折数大于1,因为至少两个子集才能进行交叉验证assert k > 1# 每个子集(折)的大小=数据集的总行数除以折数,余数在最后一个子集处理fold_size = X.shape[0] // k# 初始化训练集X_train, y_train = None, Nonefor j in range(k):# 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]# 当前折的索引 j 与指定用于验证的索引 i 匹配,将该折的数据分配给验证集(X_valid 和 y_valid)if j == i:# 将该折的数据分配给验证集X_valid, y_valid = X_part, y_part# 如不匹配且训练集为空(第一次看到),则将该折的数据分配给训练集(X_train 和 y_train)elif X_train is None:X_train, y_train = X_part, y_part# 如不匹配且训练集不为空,则将该折的数据追加到训练集(X_train 和 y_train)中else:# 表示将X_train, X_part沿着第一个维度拼接起来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):# 做k次,每次拿到第i折,把数据data拿出来即拿到从训练集和验证集data = get_k_fold_data(k, i, X_train, y_train)# 每次循环都会创建一个新的模型实例,确保每折的评估是独立的net = get_net()# 调用train函数训练模型并返回训练损失列表和验证损失列表train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,weight_decay, batch_size)# 索引[-1]获取最后一个epoch的损失,即当前折的训练损失累加到train_l_sumtrain_l_sum += train_ls[-1]valid_l_sum += valid_ls[-1]if i == 0: # 如果当前是第i折# 第一个参数:用作x轴数据# 第二个参数:一个列表储存了每一轮训练后的训练损失和验证损失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# @save
DATA_HUB = dict()
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'
DATA_HUB['kaggle_house_train'] = (DATA_URL + 'kaggle_house_pred_train.csv', '585e9cc9370b9160e7921475fbcd7d31219ce')
DATA_HUB['kaggle_house_test'] = (DATA_URL + 'kaggle_house_pred_test.csv', 'fal9780a7b011d9b009e8bff8e99922a8ee2eb90')
train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))# print(train_data.shape) # 1460个样本,80个特征,1个标号label
# print(test_data.shape) # 测试样本没有标号label
# print(train_data.iloc[0:4,[0,1,2,3,-3,-2,-1]]) # 前面四行的某些列特征
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))
# print(all_features.shape)# 若无法获得测试数据,则可根据训练数据计算均值和标准差
# all_features.dtypes 获取每个特征的数据类型
# all_features.dtypes != 'object' 返回一个布尔值的 Series,其中为 True 的位置表示对应的特征不是对象类型(即数值类型)
# .index 提取数值类型特征的索引,并在numeric_features中存储
# print(all_features.dtypes) # 可以知道每一列分别为什么类型特征
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index
# print(numeric_features)
# 对all_features中所有数值类型特征进行标准化处理
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)# “Dummy_na=True”将“na”(缺失值)视为有效的特征值,并为其创建指示符特征
# 未指定column时,pd.get_dummies函数默认转换所有的分类列,包括MSZoning、SaleType、SaleCondition
# pd.get_dummies每个分类变量都会被转换成多列,每个唯一值对应一列
# 理解意思:某列有五类值,就将此列等价于变成五列,然后对应的列置1,不存在的列置0
all_features = pd.get_dummies(all_features, dummy_na=True)# 获取训练集的行数,即训练样本数量,并将其存储在n_train中
n_train = train_data.shape[0]
# [:n_train].values是选择前n_train作为训练集的特征将数据转换为Numpy数组
train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32)
test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32)
# 将SalePrice列单独提取为标签
train_labels = torch.tensor(train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32)
loss = nn.MSELoss()
in_features = train_features.shape[1]# 数据集被分成了5份,然后执行5次训练和验证过程,每次过程中,4份数据用于训练模型,剩下的一份用于
k, num_epochs, lr, weight_decay, batch_size = 5, 100, 5, 0, 64
# 分别包含每次迭代的训练集和验证集的log rmse值
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}')
输出:
提交你的Kaggle预测
既然我们知道应该选择什么样的超参数, 我们不妨使用所有数据对其进行训练 (而不是仅使用交叉验证中使用的 1− 1 K \frac 1K K1 的数据)。 然后,我们通过这种方式获得的模型可以应用于测试集。 将预测保存在CSV文件中可以简化将结果上传到Kaggle的过程。
def train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size):net = get_net()# 返回两个值,一个包含每个epoch训练,log mose的列表,一个未在代码片段中使用的值train_ls, _ = train(net, train_features, train_labels, None, None,num_epochs, lr, weight_decay, batch_size)# 第一个参数和第二个参数:接收一个epoch数组和一个包含训练log rmse的列表作为输入d2l.plot(np.arange(1, num_epochs + 1), [train_ls], xlabel='epoch',ylabel='log rmse', xlim=[1, num_epochs], yscale='log')# 打印最后一个epoch训练log rmse来评估模型的最终训练性能print(f'训练log rmse:{float(train_ls[-1]):f}')# 将训练好的网络模型应用于测试特征preds = net(test_features).detach().numpy()# 将其重新格式化以导出到Kaggle# pd.Series()封装成一个Pandas的Series对象,以确保数据类型与DataFrame的列兼容。test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)# 用于将DataFrame保存为csv文件submission.to_csv('submission.csv', index=False)
如果测试集上的预测与 𝐾 倍交叉验证过程中的预测相似, 那就是时候把它们上传到Kaggle了。 下面的代码将生成一个名为submission.csv的文件。
train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size)
输出:
import hashlib
import os
import tarfile
import zipfile
import requests
import numpy as np
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2ldef 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: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 fnamedef 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_dirdef download_all(): # @save"""下载DATA_HUB中的所有文件"""for name in DATA_HUB:download(name)def get_net():net = nn.Sequential(nn.Linear(in_features, 1))return net# rmse=Root Mean Squared Error,对数均方根误差
def log_rmse(net, features, labels):# 通过神经网络net对输入特征features进行前向传播得到预测值# 然后为了在取对数时进一步稳定该值,用torch.clamp()函数将小于1的值设置为1# 第三个参数:不设置上限,即预测可以无限大clipped_preds = torch.clamp(net(features), 1, float('inf'))rmse = torch.sqrt(loss(torch.log(clipped_preds),torch.log(labels)))# .item() 方法将rmse转换为Python标量返回return rmse.item()# weight_decay权重衰退
def train(net, train_features, train_labels, test_features, test_labels,num_epochs, learning_rate, weight_decay, batch_size):# 用于存储每一轮训练和测试集上的log rmse值train_ls, test_ls = [], []train_iter = d2l.load_array((train_features, train_labels), batch_size)# 这里使用的是Adam优化算法,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() # 更新模型参数# 将log_rmse函数返回的误差值追加到train_ls列表中就记录了每一轮迭代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_lsdef train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size):net = get_net()# 返回两个值,一个包含每个epoch训练,log mose的列表,一个未在代码片段中使用的值train_ls, _ = train(net, train_features, train_labels, None, None,num_epochs, lr, weight_decay, batch_size)# 第一个参数和第二个参数:接收一个epoch数组和一个包含训练log rmse的列表作为输入d2l.plot(np.arange(1, num_epochs + 1), [train_ls], xlabel='epoch',ylabel='log rmse', xlim=[1, num_epochs], yscale='log')# 打印最后一个epoch训练log rmse来评估模型的最终训练性能print(f'训练log rmse:{float(train_ls[-1]):f}')# 将训练好的网络模型应用于测试特征preds = net(test_features).detach().numpy()# 将其重新格式化以导出到Kaggle# pd.Series()封装成一个Pandas的Series对象,以确保数据类型与DataFrame的列兼容。test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)# 用于将DataFrame保存为csv文件submission.to_csv('submission.csv', index=False)# @save
DATA_HUB = dict()
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'
DATA_HUB['kaggle_house_train'] = (DATA_URL + 'kaggle_house_pred_train.csv', '585e9cc9370b9160e7921475fbcd7d31219ce')
DATA_HUB['kaggle_house_test'] = (DATA_URL + 'kaggle_house_pred_test.csv', 'fal9780a7b011d9b009e8bff8e99922a8ee2eb90')
train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))# print(train_data.shape) # 1460个样本,80个特征,1个标号label
# print(test_data.shape) # 测试样本没有标号label
# print(train_data.iloc[0:4,[0,1,2,3,-3,-2,-1]]) # 前面四行的某些列特征
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))
# print(all_features.shape)# 若无法获得测试数据,则可根据训练数据计算均值和标准差
# all_features.dtypes 获取每个特征的数据类型
# all_features.dtypes != 'object' 返回一个布尔值的 Series,其中为 True 的位置表示对应的特征不是对象类型(即数值类型)
# .index 提取数值类型特征的索引,并在numeric_features中存储
# print(all_features.dtypes) # 可以知道每一列分别为什么类型特征
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index
# print(numeric_features)
# 对all_features中所有数值类型特征进行标准化处理
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)# “Dummy_na=True”将“na”(缺失值)视为有效的特征值,并为其创建指示符特征
# 未指定column时,pd.get_dummies函数默认转换所有的分类列,包括MSZoning、SaleType、SaleCondition
# pd.get_dummies每个分类变量都会被转换成多列,每个唯一值对应一列
# 理解意思:某列有五类值,就将此列等价于变成五列,然后对应的列置1,不存在的列置0
all_features = pd.get_dummies(all_features, dummy_na=True)# 获取训练集的行数,即训练样本数量,并将其存储在n_train中
n_train = train_data.shape[0]
# [:n_train].values是选择前n_train作为训练集的特征将数据转换为Numpy数组
train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32)
test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32)
# 将SalePrice列单独提取为标签
train_labels = torch.tensor(train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32)
loss = nn.MSELoss()
in_features = train_features.shape[1]num_epochs, lr, weight_decay, batch_size = 100, 5, 0, 64
train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size)
d2l.plt.show()
提交Kaggle
我们可以提交预测到Kaggle上,并查看在测试集上的预测与实际房价(标签)的比较情况。
①登录Kaggle网站,访问房价预测竞赛页面。
②点击“Submit Predictions”按钮。
③点击页面底部虚线框中的“Upload Submission File”按钮,选择要上传的预测文件。
④点击页面底部的“Submission”按钮,即可查看结果。
Kaggle注册链接
Kaggle登录链接
房价预测比赛页面(如下图 所示)的"Data"选项卡下可以找到数据集。我们可以通过下面的网址提交预测,并查看排名:
House Prices - Advanced Regression Techniques
这里是第一次提交(未优化)
1、用平均值替换缺失值总是好主意吗?提示:能构造一个不随机丢失值的情况吗?
用平均值替换缺失值并不总是一个好主意,因为这可能会导致数据失真或者模型表现下降。替代缺失值的方法应该根据数据的特点和缺失值产生的原因来选择。
比如,一个数据集中的某个属性代表的是某种物质的浓度,这种物质在某个特定温度下会分解,因此在这个温度下所有样本的该属性值都是缺失的。在这种情况下,如果直接用平均值替换缺失值,则可能会导致数据严重失真。
2、通过 𝐾 折交叉验证调整超参数,从而提高Kaggle的得分。
import hashlib
import os
import tarfile
import zipfile
import requests
import numpy as np
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2ldef 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: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 fnamedef 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_dirdef download_all(): # @save"""下载DATA_HUB中的所有文件"""for name in DATA_HUB:download(name)def get_net():net = nn.Sequential(nn.Linear(in_features, 1))return net# rmse=Root Mean Squared Error,对数均方根误差
def log_rmse(net, features, labels):# 通过神经网络net对输入特征features进行前向传播得到预测值# 然后为了在取对数时进一步稳定该值,用torch.clamp()函数将小于1的值设置为1# 第三个参数:不设置上限,即预测可以无限大clipped_preds = torch.clamp(net(features), 1, float('inf'))rmse = torch.sqrt(loss(torch.log(clipped_preds),torch.log(labels)))# .item() 方法将rmse转换为Python标量返回return rmse.item()# weight_decay权重衰退
def train(net, train_features, train_labels, test_features, test_labels,num_epochs, learning_rate, weight_decay, batch_size):# 用于存储每一轮训练和测试集上的log rmse值train_ls, test_ls = [], []train_iter = d2l.load_array((train_features, train_labels), batch_size)# 这里使用的是Adam优化算法,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() # 更新模型参数# 将log_rmse函数返回的误差值追加到train_ls列表中就记录了每一轮迭代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_lsdef train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size):net = get_net()# 返回两个值,一个包含每个epoch训练,log mose的列表,一个未在代码片段中使用的值train_ls, _ = train(net, train_features, train_labels, None, None,num_epochs, lr, weight_decay, batch_size)# 第一个参数和第二个参数:接收一个epoch数组和一个包含训练log rmse的列表作为输入d2l.plot(np.arange(1, num_epochs + 1), [train_ls], xlabel='epoch',ylabel='log rmse', xlim=[1, num_epochs], yscale='log')# 打印最后一个epoch训练log rmse来评估模型的最终训练性能print(f'训练log rmse:{float(train_ls[-1]):f}')# 将训练好的网络模型应用于测试特征preds = net(test_features).detach().numpy()# 将其重新格式化以导出到Kaggle# pd.Series()封装成一个Pandas的Series对象,以确保数据类型与DataFrame的列兼容。test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)# 用于将DataFrame保存为csv文件submission.to_csv('submission.csv', index=False)# 四个参数:表示将数据集分为多少个子集、当前折的索引、特征数据集、标签数据集
def get_k_fold_data(k, i, X, y):# 断言确保折数大于1,因为至少两个子集才能进行交叉验证assert k > 1# 每个子集(折)的大小=数据集的总行数除以折数,余数在最后一个子集处理fold_size = X.shape[0] // k# 初始化训练集X_train, y_train = None, Nonefor j in range(k):# 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]# 当前折的索引 j 与指定用于验证的索引 i 匹配,将该折的数据分配给验证集(X_valid 和 y_valid)if j == i:# 将该折的数据分配给验证集X_valid, y_valid = X_part, y_part# 如不匹配且训练集为空(第一次看到),则将该折的数据分配给训练集(X_train 和 y_train)elif X_train is None:X_train, y_train = X_part, y_part# 如不匹配且训练集不为空,则将该折的数据追加到训练集(X_train 和 y_train)中else:# 表示将X_train, X_part沿着第一个维度拼接起来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):# 做k次,每次拿到第i折,把数据data拿出来即拿到从训练集和验证集data = get_k_fold_data(k, i, X_train, y_train)# 每次循环都会创建一个新的模型实例,确保每折的评估是独立的net = get_net()# 调用train函数训练模型并返回训练损失列表和验证损失列表train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,weight_decay, batch_size)# 索引[-1]获取最后一个epoch的损失,即当前折的训练损失累加到train_l_sumtrain_l_sum += train_ls[-1]valid_l_sum += valid_ls[-1]if i == 0: # 如果当前是第i折# 第一个参数:用作x轴数据# 第二个参数:一个列表储存了每一轮训练后的训练损失和验证损失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# @save
DATA_HUB = dict()
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'
DATA_HUB['kaggle_house_train'] = (DATA_URL + 'kaggle_house_pred_train.csv', '585e9cc9370b9160e7921475fbcd7d31219ce')
DATA_HUB['kaggle_house_test'] = (DATA_URL + 'kaggle_house_pred_test.csv', 'fal9780a7b011d9b009e8bff8e99922a8ee2eb90')
train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))# print(train_data.shape) # 1460个样本,80个特征,1个标号label
# print(test_data.shape) # 测试样本没有标号label
# print(train_data.iloc[0:4,[0,1,2,3,-3,-2,-1]]) # 前面四行的某些列特征
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))
# print(all_features.shape)# 若无法获得测试数据,则可根据训练数据计算均值和标准差
# all_features.dtypes 获取每个特征的数据类型
# all_features.dtypes != 'object' 返回一个布尔值的 Series,其中为 True 的位置表示对应的特征不是对象类型(即数值类型)
# .index 提取数值类型特征的索引,并在numeric_features中存储
# print(all_features.dtypes) # 可以知道每一列分别为什么类型特征
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index
# print(numeric_features)
# 对all_features中所有数值类型特征进行标准化处理
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)# “Dummy_na=True”将“na”(缺失值)视为有效的特征值,并为其创建指示符特征
# 未指定column时,pd.get_dummies函数默认转换所有的分类列,包括MSZoning、SaleType、SaleCondition
# pd.get_dummies每个分类变量都会被转换成多列,每个唯一值对应一列
# 理解意思:某列有五类值,就将此列等价于变成五列,然后对应的列置1,不存在的列置0
all_features = pd.get_dummies(all_features, dummy_na=True)# 获取训练集的行数,即训练样本数量,并将其存储在n_train中
n_train = train_data.shape[0]
# [:n_train].values是选择前n_train作为训练集的特征将数据转换为Numpy数组
train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32)
test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32)
# 将SalePrice列单独提取为标签
train_labels = torch.tensor(train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32)
loss = nn.MSELoss()
in_features = train_features.shape[1]# 数据集被分成了5份,然后执行5次训练和验证过程,每次过程中,4份数据用于训练模型,剩下的一份用于
k, num_epochs, lr, weight_decay, batch_size = 5, 100, 10, 0, 32
# 分别包含每次迭代的训练集和验证集的log rmse值
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}')
train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size)
d2l.plt.show()
3、通过改进模型(例如,层、权重衰减和dropout)来提高分数。
import hashlib
import os
import tarfile
import zipfile
import requests
import numpy as np
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2ldef 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: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 fnamedef 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_dirdef download_all(): # @save"""下载DATA_HUB中的所有文件"""for name in DATA_HUB:download(name)def init_weights(m):if type(m) == nn.Linear:nn.init.normal_(m.weight, std=0.01)def get_net():net = nn.Sequential(nn.Flatten(),nn.Linear(in_features, 512),nn.ReLU(),nn.Linear(512, 1))net.apply(init_weights)return net# rmse=Root Mean Squared Error,对数均方根误差
def log_rmse(net, features, labels):# 通过神经网络net对输入特征features进行前向传播得到预测值# 然后为了在取对数时进一步稳定该值,用torch.clamp()函数将小于1的值设置为1# 第三个参数:不设置上限,即预测可以无限大clipped_preds = torch.clamp(net(features), 1, float('inf'))rmse = torch.sqrt(loss(torch.log(clipped_preds),torch.log(labels)))# .item() 方法将rmse转换为Python标量返回return rmse.item()# weight_decay权重衰退
def train(net, train_features, train_labels, test_features, test_labels,num_epochs, learning_rate, weight_decay, batch_size):# 用于存储每一轮训练和测试集上的log rmse值train_ls, test_ls = [], []train_iter = d2l.load_array((train_features, train_labels), batch_size)# 这里使用的是Adam优化算法,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() # 更新模型参数# 将log_rmse函数返回的误差值追加到train_ls列表中就记录了每一轮迭代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_lsdef train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size):net = get_net()# 返回两个值,一个包含每个epoch训练,log mose的列表,一个未在代码片段中使用的值train_ls, _ = train(net, train_features, train_labels, None, None,num_epochs, lr, weight_decay, batch_size)# 第一个参数和第二个参数:接收一个epoch数组和一个包含训练log rmse的列表作为输入d2l.plot(np.arange(1, num_epochs + 1), [train_ls], xlabel='epoch',ylabel='log rmse', xlim=[1, num_epochs], yscale='log')# 打印最后一个epoch训练log rmse来评估模型的最终训练性能print(f'训练log rmse:{float(train_ls[-1]):f}')# 将训练好的网络模型应用于测试特征preds = net(test_features).detach().numpy()# 将其重新格式化以导出到Kaggle# pd.Series()封装成一个Pandas的Series对象,以确保数据类型与DataFrame的列兼容。test_data['SalePrice'] = pd.Series(preds.reshape(1, -1)[0])submission = pd.concat([test_data['Id'], test_data['SalePrice']], axis=1)# 用于将DataFrame保存为csv文件submission.to_csv('submission.csv', index=False)# 四个参数:表示将数据集分为多少个子集、当前折的索引、特征数据集、标签数据集
def get_k_fold_data(k, i, X, y):# 断言确保折数大于1,因为至少两个子集才能进行交叉验证assert k > 1# 每个子集(折)的大小=数据集的总行数除以折数,余数在最后一个子集处理fold_size = X.shape[0] // k# 初始化训练集X_train, y_train = None, Nonefor j in range(k):# 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]# 当前折的索引 j 与指定用于验证的索引 i 匹配,将该折的数据分配给验证集(X_valid 和 y_valid)if j == i:# 将该折的数据分配给验证集X_valid, y_valid = X_part, y_part# 如不匹配且训练集为空(第一次看到),则将该折的数据分配给训练集(X_train 和 y_train)elif X_train is None:X_train, y_train = X_part, y_part# 如不匹配且训练集不为空,则将该折的数据追加到训练集(X_train 和 y_train)中else:# 表示将X_train, X_part沿着第一个维度拼接起来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):# 做k次,每次拿到第i折,把数据data拿出来即拿到从训练集和验证集data = get_k_fold_data(k, i, X_train, y_train)# 每次循环都会创建一个新的模型实例,确保每折的评估是独立的net = get_net()# 调用train函数训练模型并返回训练损失列表和验证损失列表train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,weight_decay, batch_size)# 索引[-1]获取最后一个epoch的损失,即当前折的训练损失累加到train_l_sumtrain_l_sum += train_ls[-1]valid_l_sum += valid_ls[-1]if i == 0: # 如果当前是第i折# 第一个参数:用作x轴数据# 第二个参数:一个列表储存了每一轮训练后的训练损失和验证损失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# @save
DATA_HUB = dict()
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'
DATA_HUB['kaggle_house_train'] = (DATA_URL + 'kaggle_house_pred_train.csv', '585e9cc9370b9160e7921475fbcd7d31219ce')
DATA_HUB['kaggle_house_test'] = (DATA_URL + 'kaggle_house_pred_test.csv', 'fal9780a7b011d9b009e8bff8e99922a8ee2eb90')
train_data = pd.read_csv(download('kaggle_house_train'))
test_data = pd.read_csv(download('kaggle_house_test'))# print(train_data.shape) # 1460个样本,80个特征,1个标号label
# print(test_data.shape) # 测试样本没有标号label
# print(train_data.iloc[0:4,[0,1,2,3,-3,-2,-1]]) # 前面四行的某些列特征
all_features = pd.concat((train_data.iloc[:, 1:-1], test_data.iloc[:, 1:]))
# print(all_features.shape)# 若无法获得测试数据,则可根据训练数据计算均值和标准差
# all_features.dtypes 获取每个特征的数据类型
# all_features.dtypes != 'object' 返回一个布尔值的 Series,其中为 True 的位置表示对应的特征不是对象类型(即数值类型)
# .index 提取数值类型特征的索引,并在numeric_features中存储
# print(all_features.dtypes) # 可以知道每一列分别为什么类型特征
numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index
# print(numeric_features)
# 对all_features中所有数值类型特征进行标准化处理
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)# “Dummy_na=True”将“na”(缺失值)视为有效的特征值,并为其创建指示符特征
# 未指定column时,pd.get_dummies函数默认转换所有的分类列,包括MSZoning、SaleType、SaleCondition
# pd.get_dummies每个分类变量都会被转换成多列,每个唯一值对应一列
# 理解意思:某列有五类值,就将此列等价于变成五列,然后对应的列置1,不存在的列置0
all_features = pd.get_dummies(all_features, dummy_na=True)# 获取训练集的行数,即训练样本数量,并将其存储在n_train中
n_train = train_data.shape[0]
# [:n_train].values是选择前n_train作为训练集的特征将数据转换为Numpy数组
train_features = torch.tensor(all_features[:n_train].values, dtype=torch.float32)
test_features = torch.tensor(all_features[n_train:].values, dtype=torch.float32)
# 将SalePrice列单独提取为标签
train_labels = torch.tensor(train_data.SalePrice.values.reshape(-1, 1), dtype=torch.float32)
loss = nn.MSELoss()
in_features = train_features.shape[1]# 数据集被分成了5份,然后执行5次训练和验证过程,每次过程中,4份数据用于训练模型,剩下的一份用于
k, num_epochs, lr, weight_decay, batch_size = 5, 100, 0.01, 300, 32
# 分别包含每次迭代的训练集和验证集的log rmse值
train_l, valid_l = k_fold(k, train_features, train_labels, num_epochs, lr,weight_decay, batch_size)train_and_pred(train_features, test_features, train_labels, test_data,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()
十行代码:
# 预测
import pandas as pd
from autogluon.tabular import TabularDataset, TabularPredictor# 训练
train_data = TabularDataset('./data/California house price/house-prices-advanced-regression-techniques/train.csv')id, label = 'Id', 'SalePrice'
predictor = TabularPredictor(label=label).fit(train_data.drop(columns=[id]))test_data = TabularDataset('./data/California house price/house-prices-advanced-regression-techniques/test.csv')
preds = predictor.predict(test_data.drop(columns=[id]))
submission = pd.DataFrame({id: test_data[id], label: preds})
submission.to_csv('./kaggle_submission/submission_4.csv', index=False)
后面两个代码均为测试,发现并没有那么好。
import hashlib
import os
import tarfile
import zipfile
import requests
import numpy as np
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2ldef 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: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 fnamedef 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_dirdef download_all(): # @save"""下载DATA_HUB中的所有文件"""for name in DATA_HUB:download(name)def init_weights(m):if isinstance(m, nn.Linear):nn.init.normal_(m.weight, std=0.01)def get_net():net = nn.Sequential(nn.Flatten(),nn.Linear(in_features, 512),nn.ReLU(),nn.Dropout(p=0.5), # 添加 Dropout 层nn.Linear(512, 256),nn.ReLU(),nn.Dropout(p=0.5), # 添加 Dropout 层nn.Linear(256, 128),nn.ReLU(),nn.Dropout(p=0.5), # 添加 Dropout 层nn.Linear(128, 1))net.apply(init_weights)return netdef log_rmse(net, features, labels):clipped_preds = torch.clamp(net(features), 1, float('inf'))rmse = torch.sqrt(loss(torch.log(clipped_preds),torch.log(labels)))return rmse.item()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)optimizer = torch.optim.Adam(net.parameters(),lr=learning_rate,weight_decay=weight_decay)scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.7)for epoch in range(num_epochs):net.train() # 确保模型处于训练模式for X, y in train_iter:optimizer.zero_grad()l = loss(net(X), y)l.backward()optimizer.step()scheduler.step() # 更新学习率net.eval() # 切换到评估模式with torch.no_grad():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_lsdef 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}')net.eval() # 切换到评估模式with torch.no_grad():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('submission.csv', index=False)def get_k_fold_data(k, i, X, y):assert k > 1fold_size = X.shape[0] // kX_train, y_train = None, Nonefor 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_partelif X_train is None:X_train, y_train = X_part, y_partelse: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()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# @save
DATA_HUB = dict()
DATA_URL = 'http://d2l-data.s3-accelerate.amazonaws.com/'
DATA_HUB['kaggle_house_train'] = (DATA_URL + 'kaggle_house_pred_train.csv', '585e9cc9370b9160e7921475fbcd7d31219ce')
DATA_HUB['kaggle_house_test'] = (DATA_URL + 'kaggle_house_pred_test.csv', 'fal9780a7b011d9b009e8bff8e99922a8ee2eb90')
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)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]k, num_epochs, lr, weight_decay, batch_size = 5, 100, 0.01, 300, 32
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}')
train_and_pred(train_features, test_features, train_labels, test_data,num_epochs, lr, weight_decay, batch_size)
d2l.plt.show()
输出:
import hashlib
import os
import tarfile
import zipfile
import requests
import numpy as np
import pandas as pd
import torch
from torch import nn
from d2l import torch as d2l# 数据下载和提取功能
def download(name, cache_dir=os.path.join('..', 'data')):"""下载一个DATA_HUB中的文件,返回本地文件名"""if name not in DATA_HUB:raise ValueError(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:for chunk in iter(lambda: f.read(1048576), b''):sha1.update(chunk)if sha1.hexdigest() == sha1_hash:return fnameprint(f'正在从 {url} 下载 {fname}...')response = requests.get(url, stream=True)response.raise_for_status()with open(fname, 'wb') as f:f.write(response.content)return fnamedef download_extract(name, folder=None):"""下载并解压zip/tar文件"""fname = download(name)base_dir = os.path.dirname(fname)ext = os.path.splitext(fname)[1]if ext == '.zip':with zipfile.ZipFile(fname, 'r') as zip_ref:zip_ref.extractall(base_dir)elif ext in ('.tar', '.gz'):with tarfile.open(fname, 'r') as tar_ref:tar_ref.extractall(base_dir)else:raise ValueError('仅支持zip和tar文件的解压缩')return os.path.join(base_dir, folder) if folder else base_dir# 初始化权重
def init_weights(m):if isinstance(m, nn.Linear):nn.init.normal_(m.weight, std=0.01)# 创建网络
def get_net():net = nn.Sequential(nn.Flatten(),nn.Linear(in_features, 1024), # 增加神经元数量nn.ReLU(),nn.Dropout(0.3), # 调整 Dropout 率nn.Linear(1024, 512), # 增加神经元数量nn.ReLU(),nn.Dropout(0.3), # 调整 Dropout 率nn.Linear(512, 256),nn.ReLU(),nn.Dropout(0.3), # 调整 Dropout 率nn.Linear(256, 1))net.apply(init_weights)return net# 计算对数均方根误差
def log_rmse(net, features, labels):clipped_preds = torch.clamp(net(features), 1, float('inf'))rmse = torch.sqrt(loss(torch.log(clipped_preds), torch.log(labels)))return rmse.item()# 训练模型
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)optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate, weight_decay=weight_decay)scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=num_epochs)for epoch in range(num_epochs):net.train()for X, y in train_iter:optimizer.zero_grad()l = loss(net(X), y)l.backward()optimizer.step()scheduler.step()net.eval()with torch.no_grad():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# 训练并预测
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:{train_ls[-1]:f}')net.eval()with torch.no_grad():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('submission.csv', index=False)# K折交叉验证数据获取
def get_k_fold_data(k, i, X, y):assert k > 1, 'k必须大于1'fold_size = X.shape[0] // kX_train, y_train = None, Nonefor 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_partelif X_train is None:X_train, y_train = X_part, y_partelse: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折交叉验证
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()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: {train_ls[-1]:.6f}, 验证log rmse: {valid_ls[-1]:.6f}')return train_l_sum / k, valid_l_sum / k# 数据准备
DATA_HUB = {'kaggle_house_train': ('http://d2l-data.s3-accelerate.amazonaws.com/kaggle_house_pred_train.csv', '585e9cc9370b9160e7921475fbcd7d31219ce'),'kaggle_house_test': ('http://d2l-data.s3-accelerate.amazonaws.com/kaggle_house_pred_test.csv','fal9780a7b011d9b009e8bff8e99922a8ee2eb90')
}
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()).fillna(0)
all_features = pd.get_dummies(all_features, dummy_na=True)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]# 设置训练参数
k, num_epochs, lr, weight_decay, batch_size = 5, 100, 0.01, 0, 32# 执行K折交叉验证
train_l, valid_l = k_fold(k, train_features, train_labels, num_epochs, lr, weight_decay, batch_size)
print(f'{k}-折验证: 平均训练log rmse: {train_l:.6f}, 平均验证log rmse: {valid_l:.6f}')# 训练模型并生成预测
train_and_pred(train_features, test_features, train_labels, test_data, num_epochs, lr, weight_decay, batch_size)
d2l.plt.tight_layout() # 调整子图参数,使之填充整个图像区域
d2l.plt.show()
输出:
4、如果我们没有像本节所做的那样标准化连续的数值特征,会发生什么?
可能导致模型训练不稳定、性能下降、泛化能力差:未标准化的特征可能具有不同的尺度,这可能导致某些特征在模型训练过程中权重过大或过小,使得模型的收敛速度变慢,甚至无法收敛,标准化可以使得以确保所有特征对模型的影响是均衡的,从而提高算法的性能、收敛速度以及泛化能力。
可能导致数值问题:如果数据的特征值范围非常广泛,可能会导致数值溢出或者精度问题。标准化可以减少这些问题的发生,确保计算的稳定性和准确性。
可能导致特征重要性误判:未标准化的特征可能会导致对特征重要性的误判。模型可能会错误地认为某些特征对目标变量的影响更大,而实际上这只是因为该特征的值范围较大而已。
相关文章:

深度学习--------------Kaggle房价预测
目录 下载和缓存数据集访问和读取数据集总代码 数据预处理训练K折交叉验证模型选择总代码提交你的Kaggle预测提交Kaggle 下载和缓存数据集 import hashlib import os import tarfile import zipfile import requests# download传递的参数分别是数据集的名称、缓存文件夹的路径…...
cpio 命令
前言 cpio(Copy In and Out)是一种在类 Unix 操作系统中处理归档文件的多功能工具。与 tar 不同,cpio 有其独特的优势和使用场景,特别是在与其他命令结合使用时。本文将带你了解 cpio 的基础知识、用法及实际示例。 什么是 cpio…...
TreeMap自定义排序
我们都知道TreeMap可以根据key按字典升序排序。但在某些场景下,我们需要自定义排序规则,为了代码优雅一些,我们也希望在stream中groupingBy时自定义排序规则,就可以参考本文的实现。 1. 使用TreeMap默认的排序规则(按…...
我的CSDN 512天创作纪念日-20240807
机缘 在 2023 年 3 月 13 日,我撰写了第一篇技术博客《软考高级-系统分析师-案例分析-系统维护与设计模式》。那一天,我决定将自己的实战项目经验和学习心得记录下来,与更多志同道合的朋友分享。成为一名专业 IT 作者的梦想,促使我…...

微服务-实现nacos的集群和Gateway网关的实现、认证校验、解决跨域
1. nacos的集群模式 1.1 分析 nacos在企业中的使用100%都是集群模式。需要掌握nacos集群的搭建 nacos的数据存放在derby本地磁盘中,nacos集群模式会导致数据库数据不一致,使用加一层思想,修改nacos的数据库,使用mysql数据库&…...

数据库中的约束,聚合函数以及联合查询
目录 数据库中的约束 not null unique default primary key foreign key 表的设计 聚合函数(查询) 分组 联表查询(多表查询) 内连接 外连接 左外连接 右外连接 自连接 子查询 合并查询 数据库中的约束 为了保证…...

【AI大模型】Ollama+OpenWebUI+llama3本地大模型
本地部署大模型 0.引言1.部署安装1.1部署工具1.2 概念介绍1.3 ollama安装后的基本使用1.4 大模型权重下载1.4.1 ollama在线下载1.4.2 huggingFace下载大模型权重及如何使用ollama进行调用 2.带有UI界面的使用3.参考 0.引言 (1)目的 本教程主要关于开源A…...
习题20240807
文章目录 题目 1: 泛型类题目 2: 泛型方法题目 3: 泛型接口题目 4: 泛型约束题目 5: 泛型集合题目6:题目7:题目8:题目9: 题目 1: 泛型类 编写一个泛型类 Box,它能够存储一个类型为 T 的值,并提供方法 SetI…...

src挖掘-记一次有趣的逻辑漏洞分享
漏洞挖掘-记一次有趣的逻辑漏洞挖掘 前言简述1、信息收集2、找功能点3、挖掘漏洞案例一:任意用户注册漏洞案例二-垂直越权导致管理员密码重置获得管理员后台权限漏洞总结 前言 此文章是小白的学习笔记,请不要利用文章内相关知识点进行非法渗透ÿ…...

【C++】STL | list (链表)详解及重要函数的实现
目录 前言 总代码 ListNode类框架的建立 (成员与模板) list类的框架 普通构造 与 empty_init(适合不同类型构造函数的小函数) list的迭代器 引子 operator、operator--(前置与后置) operator 与 operator! operator* 与 …...

警惕智能手机的“隐形眼”:如何保护我们的数字隐私堡垒
随着智能手机深入我们生活的方方面面,它变得无所不在,甚至无所不知。 但你是否意识到,你的手机可能正在悄无声息地“监听”你的一举一动? 从你的搜索习惯到日常对话,手机的个性化推荐系统正不断收集你的数据。 本文…...
人工智能算法工程师(高级)课程12-自然语言处理之NLP的语言模型-ELMo,transformer,BERT与代码详解
大家好,我是微学AI,今天给大家介绍一下人工智能算法工程师(高级)课程12-自然语言处理之NLP的语言模型-ELMo,transformer,BERT与代码详解。本课程面向高级人工智能算法工程师,深入讲解自然语言处理(NLP)中的关键语言模型技术,包括了EMLo和transformer架构。此外,课程还详细…...

PicGo + gitee 免费搭建个人图床
目录 1 图床概念2 使用gitee和PicGo搭建图床流程2.1 下载安装PicGo工具 3 图片上传错误处理3.1 PicGo客户端提示404错误信息图片上传失败3.2 PicGo客户端提示400错误信息图片上传失败 1 图床概念 "图床"是一个网络术语,它指的是一种用于存储和托管图片…...
组合数的低复杂度运算
题源 题目 F. 预期中位数 每次测试的时间限制:3 秒 每次测试的内存限制:256 兆字节 Arul 有一个长度为 n 的二进制数组* a。 他将取该数组中所有长度为 k(k 为奇数)的子序列并找到它们的中位数。 所有这些值的总和是多少…...

小型并网式光伏气象站:光伏电站的智能守护者
小型并网式光伏气象站以其独特的功能和优势,成为了电站高效运行的智能守护者。小型并网式光伏气象站通过精准的数据采集与分析,为光伏电站的运维管理提供了强有力的支持。 小型并网式光伏气象站能够实时监测并记录光伏电站周围环境的多种气象参数&#x…...
JavaScript 中的回调函数(callback)
JavaScript 中的回调函数(callback) JavaScript 中的回调函数(callback)是一个传递给另一个函数作为参数的函数,并且这个传递的函数可以在其他函数内部被调用执行。回调函数是异步编程的一个核心概念,特别…...

计算机毕业设计hadoop+spark+hive漫画推荐系统 动漫视频推荐系统 漫画分析可视化大屏 漫画爬虫 漫画推荐系统 漫画爬虫 知识图谱 大数据
HadoopSparkHive漫画推荐系统详细开题报告 一、引言 随着互联网技术的飞速发展,动漫和漫画产业的数据量急剧增长。用户面临着海量漫画作品的选择难题,如何从这些数据中高效地提取有价值的信息,为用户推荐符合其喜好的漫画作品,成…...

解决pycharm日志总是弹出“无法运行Git,未安装Git”的问题
需求分析 我电脑中安装了git,但是打开pycharm,右下角总是弹出 无法运行Git,未安装Git的日志。 解决方法 首先打开pycharm,按照以下路径,依次点击。 file -----settings-----version control -----Git----Git path(选择自己下载…...
threejs 节点材质系统 绑定attribute
新的 节点材质系统 绑定属性及使用 非常方便 不必重复声明 以instances为例 import {instancedBufferAttribute,instancedDynamicBufferAttribute,} from "three/tsl";声明一个 InstancedBufferAttribute 使用 instancedBufferAttribute包装后就可以在shader中直接使…...

Rabbitmq的几种工作模式
工具类 public class RabbitMQConnection {public static Connection getConnection() throws Exception{//1.创建connectionFactoryConnectionFactory connectionFactory new ConnectionFactory();//2.配置HostconnectionFactory.setHost("127.0.0.1");//3.设置Po…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...

STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...

如何做好一份技术文档?从规划到实践的完整指南
如何做好一份技术文档?从规划到实践的完整指南 🌟 嗨,我是IRpickstars! 🌌 总有一行代码,能点亮万千星辰。 🔍 在技术的宇宙中,我愿做永不停歇的探索者。 ✨ 用代码丈量世界&…...

SQL注入篇-sqlmap的配置和使用
在之前的皮卡丘靶场第五期SQL注入的内容中我们谈到了sqlmap,但是由于很多朋友看不了解命令行格式,所以是纯手动获取数据库信息的 接下来我们就用sqlmap来进行皮卡丘靶场的sql注入学习,链接:https://wwhc.lanzoue.com/ifJY32ybh6vc…...