李沐深度学习—4.10 预测房价笔记

李沐深度学习笔记



4.10 实战Kaggle比赛:预测房价

将大佬的代码依次解释,方便学习


一、数据集预处理

1,数据加载

我这里直接将训练数据和测试数据保存到了本地目录,直接使用pandas进行加载。

train_data = pd.read_csv('D:\\PytorchLearn\\pytorch_learning\\Project1\\data\\train.csv')
test_data = pd.read_csv('D:\\PytorchLearn\\pytorch_learning\\Project1\\data\\test.csv')

记载完成之后,打印他俩的形状并且将训练数据集和测试数据集的第一行到第四行,第一列到第四列还有最后三列打印

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

在这里插入图片描述

训练数据集的形状为 1460×81,测试数据集大小为1459×80
如上图所示,是因为测试数据集没有SalePrice列,即最终的结果。并且由上图可知,数据集中第一列为Id列,它对训练过程无用,所以应该删除。

2.删除ID列

这里首先使用了iloc将train_data 和 test_data的行全部保留,将train_data的列从第二列到倒数第二列保存(将最后一列删除),将test_data的第一列删除
最后使用concat方法将二者合并起来,默认按行合并(按列合并可使axis=1)

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

3.数据的处理

首先
选出不是文本数据的下标

numeric_features = all_features.dtypes[all_features.dtypes != 'object'].index

接着
将数值类型的数据依次取出
x遍历每一列,让x=(x-x.mean()/(s.std()),减去均值,除以方差

再将所有的nan替换为0

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)

然后
将文本数据里面的每一列中不同的类别提取出来,用one-hot编码替代它。
例如性别里边有男和女,则会将性别类分为性别_男,性别_女,其中每列的值要么为0,要么为1

all_features = pd.get_dummies(all_features, dummy_na=True)

最后
先将数据文件替换成tensor格式,这里的n_train表示训练数据的个数
然后将其转化为tensor格式,dtype弄成32为浮点数
最后将SalePrice列提取出来,并将其转化为一列。

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)

二、训练

1.定义网络

这里的Linear不关心输入行数,只关心列数。
这里的行数表示有多少个不同数据,列数表示有多少个特征需要学习

in_features = train_features.shape[1]

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

2.定义损失函数

这里选择了均方误差,而不是绝对误差(不是很理解,如果这样需要按照每个地区来划分快,而现在直接除了全部的y平均)
然后定义了一个取log函数
首先clamp要求了网络输出结果最小值为1,最大值为inf
然后y_hat 与 y取log再扔进均方损失,最后开根号。

loss = nn.MSELoss()
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()

3.训练函数

首先用train_iter将数据依次读出
然后训练完一次后将总损失加起来,存储在train_ls
最后返回损失

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则交叉验证

k则交叉验证,将数据划分为k个,k-1个作为训练数据集,将1个作为测试数据集,依次循环k次使每一份都作为了测试数据集。

1.数据集的划分

def get_k_fold_data(k, i, X, y):  # i表示第几个为测试集
    assert k > 1 # k必须大于1
    fold_size = X.shape[0] // k # 每一份数据的大小,//为整除
    X_train, y_train = None, None # 初始定义将其设为None 这俩用来存储划分好的k-1个训练集和1个测试集
    for j in range(k):
        idx = slice(j * fold_size, (j + 1) * fold_size) # 方便书写,不必每次写成X[j*fold_size:(j+1)*fold_size,:]
        X_part, y_part = X[idx, :], y[idx]
        if j == i: # 说明此时的X_part,y_part需要设置为测试集
            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)# X_train已经有值,则需要拼接起来
            y_train = torch.cat([y_train, y_part], 0)
    return X_train, y_train, X_valid, y_valid

2.k则交叉验证的实现

def k_fold(k, X_train, y_train, num_epochs, learning_rate, weight_decay,
           batch_size):
    train_l_sum, valid_l_sum = 0, 0  # 每次训练总损失,测试总损失
    for i in range(k):
        data = get_k_fold_data(k, i, X_train, y_train)  # 每次取出数据
        net = get_net()
        train_ls, valid_ls = train(net, *data, num_epochs, learning_rate,
                                   weight_decay, batch_size)# *data依次填充四个数据训练数据\结果,测试数据\结果
        train_l_sum += train_ls[-1]# 因为这里的train_ls valid_ls将每一次epochs的损失都加上了
        valid_l_sum += valid_ls[-1]# 所以最后一列即为一趟num——eposchs的结果,总损失只需要加它的最后一列即可 
        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 最后返回损失的平均值

三 测试

1.训练

这里的k,num_epochs,lr,weight_decay,batch_size都为超参数,可以自己调试得出最好的结果

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

2.完整的跑一次

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)

总结

以上就是本人对李沐深度学习4.10的笔记。
(本人小白一枚,错误的地方还望各位指正)

  • 44
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值