李沐深度学习笔记
文章目录
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]])
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的笔记。
(本人小白一枚,错误的地方还望各位指正)