【阿里天池算法学习赛】测测你的一见钟情指数/机器学习/深度学习/数据处理/Python基础

【阿里天池算法学习赛】测测你的一见钟情指数在这里插入图片描述

地址:https://tianchi.aliyun.com/competition/entrance/531825/introduction?spm=5176.12281973.0.0.4c883b74SwHDoH
性格判断,职业预测,恋爱指数……你一定在各种网页或微信公众号里接触过此类的测试小游戏。只需要回答几个简单的问题,长篇大论的分析文章就被甩到你脸前,说得头头是道,看起来也有那么几分道理。在信息时代的大背景下,利用数据分析来实现人格测试早已屡见不鲜。

赛题背景

“在2002年-2004年期间,Ray Fisman教授和Sheena Iyengar教授在筹备论文时,邀请志愿者参加闪电速配实验(相亲车轮战,每4分钟与一名相亲对象快速沟通,然后再换下一个相亲对象),提供一些相关的个人信息给相亲对象,并询问相亲对象给出是否愿意在不久的未来再次见面。本次学习赛的分析数据,记录了当时一见钟情相亲实验时,志愿者的相关信息及相亲结果。”

选手可以针对数据集不同字段间的相互影响进行分析,训练一个机器学习模型,去预测实验人身上一个或多个特性对其相亲成功与否的影响。也就是利用其它特征信息,预测数据集中的“match”字段的结果,1=成功,0=不成功。

解题思路:

丢弃缺失率大的数据、填充缺失率小的数据、线性降维+非线性降维、设计模型、训练、预测

1、数据预处理

def missing(data,threshold,dropna  = False):#  第三个参数为是否把有缺失数据的样本也删除
    percent_missing = data.isnull().sum() / len(data)
    # 统计缺失情况
    missing = pd.DataFrame({
    
    'column_name': data.columns, 
    						'percent_missing': percent_missing})
    # 要删除处理的数据						
    out = missing[missing['percent_missing']>threshold]
    # 把缺失率大于阈值的列删了
    data_new = data.drop(out['column_name'], axis=1).dropna() if dropna else
    		   data.drop(out['column_name'], axis=1)
    return data_new

这里我做了三轮处理,第一轮把缺失率大于百分之50的数据删除,第二轮均值填充缺失率小于百分之50的样本,第三轮做个缺失检查,把不能填充的样本整行删除。

data = pd.read_csv('./data/speed_dating_train.csv')
data = missing(data, 0.5)
data.fillna(data.mean(), inplace=True)
data = missing(data, 0, True)

2、数据降维

原始数据是有180多个特征,经过预处理后剩下130个特征,但往往很多特征与是否能匹配成功并没有关系,例如参加者的 id。有一些特征则和是否能匹配成功有着较高的相关性,例如收入等。
因为考虑到样本比较多,且恋爱本来就是比较玄幻的东西,所以非线性降维我用了皮尔逊相关系数把与label相关性的绝对值大于0.15的特征提取出来。

corr = data.corr('pearson')
# 这一行是用来创建一个布尔矩阵的,其中每个元素表示两个变量之间的相关系数是否大于0.15(绝对值)。如果是,那么对应的元素为True,否则为False。这样可以筛选出相关性较强的变量对
bool_matrix = (corr.abs() > 0.15)
# 这里使用的是条件选择,也就是只保留那些与’match’列相关系数大于0.15的列。这样可以减少数据框中的维度,只保留与目标变量(‘match’)相关性较强的变量。
data = data_new.loc[:, bool_matrix.loc['match']]

本来还打算PCA进行线性降维,但打印出来发现,剩下16个特征,所以我觉得不做也行

print(data.shape)

3、设计模型&训练

import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader
import pandas as pd

训练集/验证集

相亲匹配成功与匹配失败的样本分布不均,正负样本比约为1:5,所以要对训练集扩容,扩容方法我选择了简单的复制粘贴。

device = torch.device("cuda:0" if torch.cuda.is_available() else 'cpu')

# 训练集取前面6500个样本,剩下1700多个样本做验证集
train_data = data[0:6500]
test_data = data[6500:]
# 将训练集正样本复制4份
positive_samples = train_data[train_data['match'] == 1].copy()
positive_samples = pd.concat([positive_samples] * 4)
train_data = pd.concat([train_data, positive_samples])
# 对数据集进行打乱,保证样本顺序随机
train_data = train_data.sample(frac=1).reset_index(drop=True)

转换为tensor

train_X = train_data.drop('match', axis=1)
train_y = train_data['match']

test_X = test_data.drop('match', axis=1)
test_y = test_data['match']

test_X = torch.from_numpy(test_X.to_numpy()).float().to(device)
test_y = torch.from_numpy(test_y.to_numpy()).float().to(device)

train_X = torch.from_numpy(train_X.to_numpy()).float().to(device)
train_y = torch.from_numpy(train_y.to_numpy()).float().to(device)
# 打包成小批量随机梯度下降
dataset = TensorDataset(train_X, train_y)
dataloader = DataLoader(dataset, batch_size=30, shuffle=True)

模型设计/训练

# 三层神经网络,逻辑回归模型
model = nn.Sequential(
    nn.Linear(16, 64),
    nn.ReLU(),
    nn.Linear(64, 1),
    nn.Sigmoid()
).to(device)
# 优化器随机梯度下降
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 损失函数二元交叉熵
criterion = nn.BCELoss()
# 模型权重初始化
def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std=0.01)

model.apply(init_weights)
# 训练模型
epochs = 60
for epoch in range(epochs):
    for X, y in dataloader:
        # 前向传播,得到预测值
        y_pred = model(X)
        # 计算损失值
        loss = criterion(y_pred.squeeze(), y)
        # 反向传播,计算梯度
        loss.backward()
        # 更新参数
        optimizer.step()
        # 清零梯度
        optimizer.zero_grad()
        # 每10轮打印一次损失值
    if (epoch + 1) % 10 == 0:
        print(f'Epoch {
      
      epoch + 1}, Loss: {
      
      loss.item():.4f}')

4、测试模型

# 计算准确率函数
def accuracy(y_pred, y_true):
    y_pred = y_pred.squeeze()
    y_true = y_true.squeeze()
    correct = torch.eq(y_pred, y_true).float()
    acc = correct.sum() / len(correct)
    return acc

with torch.no_grad():  # 不需要计算梯度
    y_pred = model(test_X)
    y_pred = y_pred.round()  # 将预测值四舍五入为0或1
    acc = accuracy(y_pred, test_y)
    print(f'Accuracy: {
      
      acc:.4f}')

结果:

Epoch 20, Loss: 0.0105
Epoch 40, Loss: 0.0041
Epoch 60, Loss: 0.0017
Accuracy: 1.0000

5、保存数据&提交

# 同样的方法预处理data2
data2 = pd.read_csv('./data/speed_dating_test.csv')
data2 = missing(data, 0.5)
data2.fillna(data2.mean(), inplace=True)
data2 = missing(data2, 0, True)
data2 = torch.from_numpy(data2.to_numpy()).float().to(device)
# data2是没有'match'字段的,所以可以不用分离出来
predict_test = model(data2)
predict_test = predict_test.round().cpu()
predict_list = predict_test.squeeze().tolist()  # 将张量转换为列表
predict_int = [int(x) for x in predict_list]  # 将列表中的每个元素转换为int

# 提交要按照官方给出的格式,所以把sample导入进来,替换sample的'match'字段即可
save = pd.read_csv('data/sample_submission.csv')
save['match'] = predict_int
# 保存
save.to_csv('data/predict_submission.csv', index=False)  # index=False表示不写入行索引

提交文件,获得成绩与排名
提交成绩

猜你喜欢

转载自blog.csdn.net/Dec1steee/article/details/130160929
今日推荐