一、背景
欧图集团是世界上最大的电子商务公司之一,在20多个国家设有子公司,包括美国,德国和法国。我们每天在全球销售数百万种产品,数千种产品被添加到我们的产品线中。
对我们产品性能的一致分析至关重要。然而,由于我们的全球基础设施多样化,许多相同的产品分类不同。因此,我们产品分析的质量在很大程度上取决于准确聚类类似产品的能力。分类越好,我们可以对我们的产品范围产生更多的见解。
在这次比赛中,我们为200000多个产品提供了93个功能的数据集。目标是建立一个能够区分我们主要产品类别的预测模型。
二、数据分析
数据量大概有60000多个,每一个数据有93个特征,一共可以分为Class_1-Class_9这9个类。测试数据大概有140000多个。
三、代码实现
(1)Dataset
依旧是用Dataset去完成读取数据的操作。
这里值得注意的是,因为本数据集的标签项不是1,2,3的数值,而是CALSS_1这种数据,故而需要有一个函数,将读取进来的标签转变为纯数值。
读取所有的标签,通过一个for循环,依次对每个标签做处理。处理的原则是通过index方式将读取的标签和给出的标签做对比,假设读取数据的标签是Class_1,那么对应的 target_labels里Class_1的值是0,所以最后输出0,以此类推
def labels2id(labels):
target_id = []
target_labels = ['Class_1','Class_2','Class_3','Class_4','Class_5','Class_6','Class_7','Class_8','Class_9']
for label in labels:
target_id.append(target_labels.index(label))
return target_id
class OttoDataset(Dataset):
def __init__(self, filepath):
xy = pd.read_csv(filepath) # 通过路径读取文件地址
labels = xy['target'] # 记录标签项
self.len = xy.shape[0]
self.x_data = torch.tensor(np.array(xy)[:, 1:-1].astype(float)) # 读取除了最后一项(标签项)的所有数据
self.y_data = labels2id(labels)
def __getitem__(self, index):
return self.x_data[index], self.y_data[index]
def __len__(self):
return self.len
(2)Module
因为有93个feature所以线性层的第一层的横坐标一定是93,通过4层线性层,激活层采用ReLU。最后一层不采用非线性变化,因为最后要采用CE交叉熵损失函数,他包括softmax-log-NLLLoss三层,所以再输入softmax时,一定是线性数据。
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.l1 = torch.nn.Linear(93, 64)
self.l2 = torch.nn.Linear(64, 32)
self.l3 = torch.nn.Linear(32, 16)
self.l4 = torch.nn.Linear(16, 9)
self.relu = torch.nn.ReLU()
def forward(self, x): # 正向传播
x = self.relu(self.l1(x))
x = self.relu(self.l2(x))
x = self.relu(self.l3(x))
return self.l4(x)
def predict(self, x):
with torch.no_grad():
x = self.relu(self.l1(x))
x = self.relu(self.l2(x))
x = self.relu(self.l3(x))
x = self.relu(self.l4(x))
_, predicted = torch.max(x, dim=1)
y = pd.get_dummies(predicted)
return y
(3)train
做法和以前的一样,只是最后打印的时候,每300次数据打印一次均损失。
def train(epoch):
running_loss = 0.0
for batch_idx, data in enumerate(train_loader):
inputs, target = data
inputs = inputs.float()
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, target)
loss.backward()
optimizer.step()
running_loss += loss.item()
if batch_idx % 300 == 299:
print('[%d,%5d] loss:%.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
running_loss = 0.0
(4)保存
步骤是:
读取数据(提出非ID数据)->输入预测函数,得到结果->构造符合题目要求的预测结果数据(重建columns,插入ID列)
def predict_save():
test_data = pd.read_csv('otto/test.csv')
test_inputs = torch.tensor(np.array(test_data)[:, 1:].astype(float))
out = model.predict(test_inputs.float())
labels = ['Class_1', 'Class_2', 'Class_3', 'Class_4', 'Class_5', 'Class_6',
'Class_7', 'Class_8', 'Class_9']
out.columns = labels
out.insert(0, 'id', test_data['id'])
output = pd.DataFrame(out)
output.to_csv('my_predict.csv', index=False)
return output
(5)主函数训练
train_dataset = OttoDataset('otto/train.csv')
train_loader = DataLoader(dataset=train_dataset, batch_size=64, shuffle=True, num_workers=0)
model = Net()
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr = 0.03, momentum=0.5)
if __name__ =='__main__':
for epoch in range(1000):
train(epoch)
predict_save()
四、测试结果