田 | 描述 |
---|---|
销售ID | 交易ID,唯一编码 |
名字 | 汽车交易名称,已脱敏 |
regDate(注册日期) | 汽车注册日期,例如20160101,2016年01月01日 |
型 | 车型编码,已脱敏 |
品牌 | 汽车品牌,已脱敏 |
bodyType | 车身类型:豪华轿车:0,微型车:1,厢型车:2,大巴车:3,敞篷车:4,双门汽车:5,商务车:6,搅拌车:7 |
燃料类型 | 燃油类型:汽油:0,柴油:1,液化石油气:2,天然气:3,混合动力:4,其他:5,电动:6 |
变速器 | 变速箱:手动:0,自动:1 |
权力 | 发动机功率:范围 [ 0, 600 ] |
公里 | 汽车已行驶公里,单位万km |
notRepaired损坏 | 汽车有尚未修复的损坏:是:0,否:1 |
regionCode | 地区编码,已脱敏 |
卖方 | 销售方:个体:0,非个体:1 |
offerType | 报价类型:提供:0,请求:1 |
creatDate | 汽车上线时间,即开始售卖时间 |
价格 | 二手车交易价格(预测目标) |
v系列特征 | 匿名特征,包含v0-14在内15个匿名特征 |
一、导入数据
import pandas as pd
import numpy as np
from torch import nn, optim
import torch
import matplotlib.pyplot as plt
config = {
#超参数
'epoch': 10, #训练轮数
'batch_size': 512,
'learning_rate': 8e-3, #学习率
'device': 'cuda',
"num_cols": ['regDate', 'creatDate', 'power', 'kilometer', 'v_0', 'v_1', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10',
'v_11', 'v_12', 'v_13', 'v_14'],
"cate_cols": ['model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'seller', 'notRepairedDamage']
}
test_data = pd.read_csv('/gemini/data-1/used_car_testB_20200421.csv', sep=' ')
test_data.shape
(50000, 30)
# 导入数据
train_data = pd.read_csv('/gemini/data-1/used_car_train_20200313.csv', sep=' ')
train_data.shape
(150000, 31)
二、数据处理
1、 合并数据
data = pd.concat([train_data, test_data])
data.shape
/opt/conda/lib/python3.6/site-packages/ipykernel_launcher.py:2: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.
To accept the future behavior, pass 'sort=False'.
To retain the current behavior and silence the warning, pass 'sort=True'.
(200000, 31)
2、定义One-Hot编码函数
one-hot编码:每个唯一的分类值都被赋予一个唯一的二进制向量,也被称为‘独热’向量,因为在这个向量中,只有一个位置的元素是1(表示该类别的存在),其余所有位置的元素都是0
如, 猫,狗,鸟三分类中,猫为[1,0,0] 狗为[0,1,0] 鸟为[0,0,1]
def oneHotEncode(df, colNames):
for col in colNames:
dummies = pd.get_dummies(df[col], prefix=col)
df = pd.concat([df, dummies],axis=1)
df.drop([col], axis=1, inplace=True)
return df
data.columns
Index(['SaleID', 'bodyType', 'brand', 'creatDate', 'fuelType', 'gearbox',
'kilometer', 'model', 'name', 'notRepairedDamage', 'offerType', 'power',
'price', 'regDate', 'regionCode', 'seller', 'v_0', 'v_1', 'v_10',
'v_11', 'v_12', 'v_13', 'v_14', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6',
'v_7', 'v_8', 'v_9'],
dtype='object')
data = data.replace('-', '-1')
data.notRepairedDamage = data.notRepairedDamage.astype('float32')
data.loc[data['power']>600,'power'] = 600
3、深度学习-梯度下降
y =(x-3)**2+1 ,求y的最小值
给个任意初始值x,如 x = -1,我们想要找到x = 3,如何做呢。根据导数dy/dx,我们可以对x迭代。x = x - dy/dx ,由于我们 dy/dx 计算的值比较大,就相当于我们每次迭代 x 一步跨的很长。所以我们设定一个参数 lr (learning rate)也就是我们所说的"学习率"或者"步长"。
x = x-lr*dy/dx
(原文链接:https://blog.csdn.net/qq_49560248/article/details/123918044)
4、特征缩放(归一化)
使用原因:
使用单一指标对某事物进行评价并不合理,因此需要多指标综合评价方法。多指标综合评价方法,就是把描述某事物不同方面的多个指标综合起来得到一个综合指标,并通过它评价、比较该事物。
由于性质不同,不同评价指标通常具有不同的量纲和数量级。当各指标相差很大时,如果直接使用原始指标值计算综合指标,就会突出数值较大的指标在分析中的作用、削弱数值较小的指标在分析中的作用。
为消除各评价指标间量纲和数量级的差异、保证结果的可靠性,就需要对各指标的原始数据进行特征缩放(也有数据标准化、数据归一化的说法,但这些叫法不准确,所以不推荐).
由于量纲和数量级不同,所以需要特征缩放。特征缩放可以显著提升部分机器学习算法的性能,但它对部分算法没有帮助。
不使用特征缩放的缺点:
假如特征x1的数值是100左右,特征x2的数值是1左右,方程为y=w1x1 + w2x2 + b,那w1对y
的影响就更大,对Loss的影响也更大,损失函数关于w1的梯度也更大,而损函教关于u2的梯度却
很小,因此两个特征就不能使用相同的学习率。
不进行特征缩放的话,Error Surface就是一个椭圆,梯度下降时不一定是朝着最优点(圆心)速度
就慢。
如果进行了特征缩放,Error Surface会尽可能趋近于圆,因此梯度下降时会一直朝着最优点(圆
心),所以速度快。
特征缩放优点
提高模型的数值稳定性
缩放后,输入的x会变得较小,X较小会带来较小梯度
# 处理离散数据
for col in config['cate_cols']:
data[col] = data[col].fillna('-1')
data = oneHotEncode(data, config['cate_cols'])
# 处理连续数据
for col in config['num_cols']:
data[col] = data[col].fillna(0)
data[col] = (data[col]-data[col].min()) / (data[col].max()-data[col].min())
# 处理(可能)无关数据
data.drop(['name', 'regionCode'], axis=1, inplace=True)
data.columns
5、删除分离
Index(['SaleID', 'creatDate', 'kilometer', 'offerType', 'power', 'price',
'regDate', 'v_0', 'v_1', 'v_10',
...
'fuelType_6.0', 'fuelType_-1', 'gearbox_0.0', 'gearbox_1.0',
'gearbox_-1', 'seller_0', 'seller_1', 'notRepairedDamage_-1.0',
'notRepairedDamage_0.0', 'notRepairedDamage_1.0'],
dtype='object', length=336)
# 暂存处理后的test数据集
test_data = data[pd.isna(data.price)]
test_data.to_csv('./one_hot_testB.csv')
# 删除test数据(price is nan)
data.reset_index(inplace=True)
train_data = data
train_data = train_data.drop(data[pd.isna(data.price)].index)
train_data.shape
(150000, 337)
# 删除ID
train_data.drop(['SaleID'], axis=1, inplace=True)
# 打乱
train_data = train_data.sample(frac=1)
train_data.shape
Out [38]:
(150000, 336)
# 分离目标
train_target = train_data['price']
train_data.drop(['price', 'index'], axis=1, inplace=True)
# 分离出验证集,用于观察拟合情况
validation_data = train_data[:10000]
train_data = train_data[10000:]
validation_target = train_target[:10000]
train_target = train_target[10000:]
validation_data.shape, train_data.shape, validation_target.shape, train_target.shape
((10000, 334), (140000, 334), (10000,), (140000,))
train_data.columns
Index(['creatDate', 'kilometer', 'offerType', 'power', 'regDate', 'v_0', 'v_1',
'v_10', 'v_11', 'v_12',
...
'fuelType_6.0', 'fuelType_-1', 'gearbox_0.0', 'gearbox_1.0',
'gearbox_-1', 'seller_0', 'seller_1', 'notRepairedDamage_-1.0',
'notRepairedDamage_0.0', 'notRepairedDamage_1.0'],
dtype='object', length=334)
三、训练
1、训练集
更新参数
class Network(nn.Module):
def __init__(self, in_dim, hidden_1, hidden_2, hidden_3, hidden_4):
super().__init__()
self.layers = nn.Sequential(
nn.Linear(in_dim, hidden_1),
nn.BatchNorm1d(hidden_1),
nn.ReLU(),
nn.Linear(hidden_1, hidden_2),
nn.BatchNorm1d(hidden_2),
nn.ReLU(),
nn.Linear(hidden_2, hidden_3),
nn.BatchNorm1d(hidden_3),
nn.ReLU(),
nn.Linear(hidden_3, hidden_4),
nn.BatchNorm1d(hidden_4),
nn.ReLU(),
nn.Linear(hidden_4, 1)
)
def forward(self, x):
y = self.layers(x)
return y
2、验证集
选择训练出的参数中合适的
mae_list = []
for epoch in range(config['epoch']):
losses = []
model.train()
for i in range(0, train_num, config['batch_size']):
end = i + config['batch_size']
if i + config['batch_size'] > train_num-1:
end = train_num-1
mini_batch = train_features[i: end]
mini_batch_label = train_labels[i: end]
pred = model(mini_batch)
pred = pred.squeeze()
loss = criterion(pred, mini_batch_label)
if torch.isnan(loss):
break
mae = torch.abs(mini_batch_label-pred).sum()/(end-i)
losses.append(mae.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
model.eval()
pred = model(validation_features)
validation_mae = torch.abs(validation_labels-pred.squeeze()).sum().item()/validation_num
mae_list.append((sum(losses)/len(losses), validation_mae))
print(f"epoch:{epoch + 1} MAE: {sum(losses)/len(losses)}, Validation_MAE: {validation_mae}")
torch.save(model, 'model.pth')
3、测试集
测试性能