【深度学习实战】利用Linear Regression预测房价

本文参考了李沐老师的b站深度学习课程 课程链接,使用了线性回归模型,特别适合深度学习初学者。通过阅读本文,你将学会如何用PyTorch训练模型,并掌握一些实用的训练技巧。希望这些内容能对你的深度学习学习有所帮助。

安装pytorch

在命令行输入下面这段指令

pip install pytorch torchvision -i https://pypi.tuna.tsinghua.edu.cn/simple

导入数据集

数据集来自kaggle一个比赛(比赛链接),可以通过链接自己下载数据集:

训练数据集 http://d2l-data.s3-accelerate.amazonaws.com/kaggle_house_pred_train.csv

测试数据集 http://d2l-data.s3-accelerate.amazonaws.com/kaggle_house_pred_test.csv

也可以通过一下这段代码下载

                                                                                    
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)                                                              

通过pandas处理数据

import numpy as np # linear algebra                                             
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)          

train_data = pd.read_csv('/kaggle/input/kaggle_house_pred_train.csv')     
test_data = pd.read_csv('/kaggle/input/kaggle_house_pred_test.csv')       

train_data是训练集包含47439条数据,40个feature,还有一个是房价(label) 测试集只有也是47439条,40个feature。 

 在开始建模之前,我们需要对数据进行预处理。 首先,我们将所有缺失的值替换为相应特征的平均值。然后,为了将所有特征放在一个共同的尺度上, 我们通过将特征重新缩放到零均值和单位方差来标准化数据:

中μ和σ分别表示均值和标准差。 现在,这些特征具有零均值和单位方差,即  

直观地说,我们标准化数据有两个原因: 首先,它方便优化。 其次,因为我们不知道哪些特征是相关的, 所以我们不想让惩罚分配给一个特征的系数比分配给其他任何特征的系数更大。 

将缺失值替换为0,因为已经在上一步中进行了标准化,0在这个上下文中相当于均值


# train_data.loc[:, train_data.columns != 'Sold Price'] # 这行代码用于提取除'Sold Price'外的其他列
# 合并训练数据和测试数据,排除“Sold Price”列,因为这是我们预测的目标变量
all_features = pd.concat((train_data.loc[:, train_data.columns != 'Sold Price'], test_data.iloc[:, 1:]))

# 查看合并后的数据信息,以了解数据的整体情况
all_features.info()

# 将所有缺失的值替换为相应特征的平均值。通过将特征重新缩放到零均值和单位方差来标准化数据
# 首先,确定哪些特征是数值型的,因为我们将对这些特征进行标准化
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)

all_features = all_features[numeric_features[1:]] # 原本第一列是Id,去掉
all_features.info()
<class 'pandas.core.frame.DataFrame'>
Index: 79065 entries, 0 to 31625
Data columns (total 18 columns):
 #   Column                       Non-Null Count  Dtype  
---  ------                       --------------  -----  
 0   Year built                   79065 non-null  float64
 1   Lot                          79065 non-null  float64
 2   Bathrooms                    79065 non-null  float64
 3   Full bathrooms               79065 non-null  float64
 4   Total interior livable area  79065 non-null  float64
 5   Total spaces                 79065 non-null  float64
 6   Garage spaces                79065 non-null  float64
 7   Elementary School Score      79065 non-null  float64
 8   Elementary School Distance   79065 non-null  float64
 9   Middle School Score          79065 non-null  float64
 10  Middle School Distance       79065 non-null  float64
 11  High School Score            79065 non-null  float64
 12  High School Distance         79065 non-null  float64
 13  Tax assessed value           79065 non-null  float64
 14  Annual tax amount            79065 non-null  float64
 15  Listed Price                 79065 non-null  float64
 16  Last Sold Price              79065 non-null  float64
 17  Zip                          79065 non-null  float64
dtypes: float64(18)
memory usage: 11.5 MB

将numpy 转换成tensor


# 从pandas格式中提取NumPy格式,并将其转换为张量表示
n_train = train_data.shape[0]#shape获取行、列数,只取行数————获取训练集行数
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['Sold Price'].values.reshape(-1, 1),
                            dtype=torch.float32)

 设计模型


from torch import nn
from torch.utils.data import dataset, DataLoader, TensorDataset
from torch import optim
# 定义一个继承自nn.Module的模型类
class model(nn.Module):
    def __init__(self, in_features):
        super(model, self).__init__()
        ### 定义模型 [b,40] ==> [b,1]
        self.net = nn.Sequential(nn.Linear(in_features, 1))

    def forward(self, x):
        ##只有一层所以不需要激活函数
        return self.net(x)

获取数据集,实例化模型


# 将训练数据和标签封装为数据集
train_datasets = TensorDataset(train_features, train_labels)
# 创建数据加载器,用于迭代加载数据集中的数据
train_data = DataLoader(train_datasets, batch_size=64, shuffle=True)
# 同样的操作应用于测试数据
test_datasets = TensorDataset(test_features)
test_data = DataLoader(test_datasets, batch_size=64, shuffle=True)

# 获取输入特征的数量
in_features = train_features.shape[1]
# 实例化模型
model = model(in_features)
# 定义均方误差损失函数
loss = nn.MSELoss()
# 定义优化器,使用Adam算法
optimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=0.01)
# 再次获取输入特征的数量,用于下面的函数
in_features = train_features.shape[1]

 定义相关函数

1. 定义获取K折交叉验证数据的函数:它有助于模型选择和超参数调整。 我们首先需要定义一个函数,在K折交叉验证过程中返回第i折的数据(将一个数据集分成k折,k-1折作为训练级 ,1折作为验证集)。 具体地说,它选择第i个切片作为验证数据,其余部分作为训练数据。 注意,这并不是处理数据的最有效方法,如果我们的数据集大得多,会有其他解决办法。

# 定义获取K折交叉验证数据的函数
def get_k_fold_data(k, i, X, y):
    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], 0)
            y_train = torch.cat([y_train, y_part], 0)
    return X_train, y_train, X_valid, y_valid

2.房价就像股票价格一样,我们关心的是相对数量,而不是绝对数量。 因此,我们更关心相对误差y - \hat{y} / y\hat{}, 而不是绝对误差|y - y\hat{}|。 例如,如果我们在估计一栋房子的价格时, 假设我们的预测偏差了10万美元, 然而那里一栋典型的房子的价值是12.5万美元, 那么模型可能做得很糟糕。 另一方面,如果我们在加州豪宅区的预测出现同样的10万美元的偏差, (在那里,房价中位数超过400万美元) 这可能是一个不错的预测。

解决这个问题的一种方法是用价格预测的对数来衡量差异。 事实上,这也是比赛中官方用来评价提交质量的误差指标。 即将δ for |log⁡y−log⁡y^|≤δ 转换为e−δ≤y^y≤eδ。 这使得预测价格的对数与真实标签价格的对数之间出现以下均方根误差:

# 定义对数均方根误差函数
def log_rmse(preds, labels):
    clipped_preds = torch.clamp(preds, 1, float('inf'))
    rmse = torch.sqrt(loss(torch.log(clipped_preds), torch.log(labels)))
    return rmse.item()

训练模型


# 训练模型
for epochs in range(10):
    for batch_id, (x, y) in enumerate(train_data):
        # 获取K折交叉验证数据
        x_train, y_train, x_test, y_test = get_k_fold_data(5, 0, x, y)
        # 前向传播得到预测值
        pred = model(x_train)
        # 对预测值进行裁剪,确保其值在1到正无穷之间
        clipped_preds = torch.clamp(pred, 1, float('inf'))
        # 计算损失
        l = loss(torch.log(clipped_preds), torch.log(y_train))
        # 清零梯度
        optimizer.zero_grad()
        # 反向传播
        l.backward()
        # 更新参数
        optimizer.step()
        # 在测试数据上进行预测
        pred = model(x_test)
        # 打印当前批次的训练情况
        print(f'epoch {epochs + 1}, batch {batch_id}, valid log rmse {log_rmse(pred,y_test):f}')

# 在测试集上进行最终预测
pred = model(test_features)

结语

非常感谢您的阅读!我衷心希望这篇关于使用PyTorch进行线性回归模型训练的博客文章能够对您有所帮助。

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值