#训练---------------------------------------------------------------------------------
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
# 导入数据
train_data = pd.read_csv('/gemini/data-1/used_car_train_20200313.csv', sep=' ')
train_data.shape
# 合并数据
data = pd.concat([train_data, test_data])
data.shape
处理连续数据的onehot函数
OneHot 编码是一种常用的数据预处理技术,特别是在处理分类特征时。
1. 定义:
OneHot 编码是一种将分类变量转换为机器学习算法可以更好处理的格式的方法。它将每个类别标签转换为一个二进制向量。
2. 目的:
将分类数据转换为数值型数据,使得算法能够处理它们。这是因为大多数机器学习算法只能处理数值型数据。
3. 原理:
对于一个具有N个唯一类别的变量,OneHot 编码会生成N个二进制列。每个类别对应一个列,如果某个实例属于该类别,则对应的列值为1,否则为0。
4. 实现:
在Python中,可以使用pandas库中的get_dummies函数,或者在scikit-learn中使用OneHotEncoder来实现OneHot编码。
5. 优点:
简单易实现。
可以处理任何类型的分类变量,包括有序和无序的类别。
6. 缺点:
会显著增加数据的维度。如果一个特征有大量的类别,OneHot 编码后会生成大量的列。
可能会引入大量的噪声,特别是当某些类别的样本非常少时。
7. 处理有序数据:
对于有序的分类数据(如教育水平、收入等级等),使用OneHot 编码可能会丢失这些数据的顺序信息。在这种情况下,可能需要考虑其他编码方法,如标签编码(Label Encoding)。
8. 稀疏性:
OneHot 编码生成的向量通常是稀疏的,大多数元素都是0。这可以通过稀疏矩阵来有效存储。
9. 在模型中的应用:
在训练模型时,OneHot 编码后的数据可以直接输入到模型中,如决策树、随机森林、支持向量机等。
10. 预处理步骤:
通常在数据清洗和特征工程阶段进行OneHot 编码,作为数据预处理的一部分。
# 定义One-Hot编码函数
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
data = data.replace('-', '-1')
data.notRepairedDamage = data.notRepairedDamage.astype('float32')
data.loc[data['power']>600,'power'] = 600
# 处理离散数据
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
# 暂存处理后的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
# 删除ID
train_data.drop(['SaleID'], axis=1, inplace=True)
# 打乱
train_data = train_data.sample(frac=1)
train_data.shape
# 分离目标
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
train_data.columns
# 定义网络结构
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
# 定义网络
model = Network(train_data.shape[1], 256, 256, 256, 32)
model.to(config['device'])
# 使用Xavier初始化权重
for line in model.layers:
if type(line) == nn.Linear:
print(line)
nn.init.xavier_uniform_(line.weight)
# 将数据转化为tensor,并移动到cpu或cuda上
train_features = torch.tensor(train_data.values, dtype=torch.float32, device=config['device'])
train_num = train_features.shape[0]
train_labels = torch.tensor(train_target.values, dtype=torch.float32, device=config['device'])
validation_features = torch.tensor(validation_data.values, dtype=torch.float32, device=config['device'])
validation_num = validation_features.shape[0]
validation_labels = torch.tensor(validation_target.values, dtype=torch.float32, device=config['device'])
# 特征长度
train_features[1].shape
# 定义损失函数和优化器
criterion = nn.MSELoss()
criterion.to(config['device'])
optimizer = optim.Adam(model.parameters(), lr=config['learning_rate'])
数据分割
1. 训练集
训练集是用于训练机器学习模型的数据集。模型通过学习训练集中的示例来识别模式和关系。训练集通常包含特征(输入变量)和目标(输出变量)。
2. 测试集
测试集是用于评估模型性能的数据集。在模型训练完成后,使用测试集来检验模型的泛化能力,即模型在未见过的数据上的表现。测试集通常不参与模型的训练过程,以避免过拟合。
3. 验证集
验证集是可选的,用于在训练过程中调整模型参数,如选择模型结构、调整超参数等。它帮助我们选择最佳的模型配置,而不会影响最终测试集上的性能评估。
处理数据重要流程
- 先导入各种需要的库
- 将压缩的数据文件解压
- 将测试集和训练集文件连接在一块儿
- 进行数据清洗:.可判断与结果无关的数据可删除 ;数据中的无效数据进行删除或更改;根据数据之间的联系划分出离散数据和连续数据
# 开始训练
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')
x = np.arange(0, config['epoch'])
y1, y2 = zip(*mae_list)
plt.plot(x, y1, label='train')
plt.plot(x, y2, label='valid')
plt.legend()
plt.show()
#预测----------------------------------------------------------------------------------
import pandas as pd
import torch
from torch import nn
from settings import config
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
model = torch.load('model.pth', map_location=config['device'])
data = pd.read_csv('./one_hot_testB.csv')
data.shape
data.columns
data = data.drop(columns=['Unnamed: 0', 'price'])
test = data.drop(columns='SaleID')
test.shape
test = torch.tensor(test.values, dtype=torch.float32)
pred = model(test)
price = pd.DataFrame(pred.detach().cpu().numpy(), columns=['price'])
res = pd.concat([data.SaleID, price], axis=1)
res.to_csv('output.csv')
数据拟合
通过走梯度的负方向并以恰当的步长来调整各个数据的权重,来拟合数据,得到更准确的预测结果。