前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【kaggle深度学习实战--保险数据集的回归-基于pytorch-Regression with an Insurance Dataset】

【kaggle深度学习实战--保险数据集的回归-基于pytorch-Regression with an Insurance Dataset】

作者头像
机器学习司猫白
发布2025-01-21 17:40:37
发布2025-01-21 17:40:37
9800
代码可运行
举报
文章被收录于专栏:机器学习实战机器学习实战
运行总次数:0
代码可运行

本文使用深度学习来预测表格数据

使用的模型为tabnet,因此需要安装相应的模块 !pip install pytorch-tabnet

TabNet 简介

TabNet 是由 Google Research 提出的一个深度学习模型,旨在高效处理表格数据(Tabular Data)。TabNet 的设计目标是为表格数据提供一种新的、更高效、更易解释的处理方法。与传统的机器学习模型(如决策树、随机森林、XGBoost 等)和神经网络(如 MLP)相比,TabNet 在处理表格数据时具有显著优势,尤其是在复杂性和可解释性方面。

  1. TabNet 的核心特点和优势 自注意力机制 (Attention Mechanism): TabNet 的核心创新之一是引入了 注意力机制,这种机制通常用于自然语言处理(NLP)和计算机视觉(CV)领域,在 TabNet 中,注意力机制帮助模型选择性地关注输入数据的不同特征。 TabNet 的注意力机制帮助模型决定哪些特征对于当前的任务是最重要的,从而能更好地对表格数据进行建模。这使得模型能够学习到特征之间的复杂依赖关系。
  2. 解释性 (Interpretability): TabNet 提供了较好的模型可解释性,尤其在需要理解模型做出预测原因的场景中。这主要得益于其注意力机制,用户可以通过分析模型的 “解释” 部分,了解模型是如何从输入特征中选择相关信息的。 在实际应用中,解释性对很多行业来说是一个重要需求,尤其在金融、医疗等领域,TabNet 在此方面的表现十分突出。
  3. 高效的稀疏性学习 (Sparse Learning): TabNet 通过稀疏注意力机制提高了计算效率,减少了不必要的计算。具体来说,它通过学习哪些特征组合是最重要的,减少了对无关特征的依赖,从而提高了模型的学习速度和泛化能力。 稀疏性能够有效降低模型的复杂度,提高训练和推理速度,特别适用于大规模数据集。
  4. 优秀的性能: 在多个标准数据集上,TabNet 在准确性和效率上都表现优异,尤其在一些复杂的表格数据任务上,TabNet 经常优于传统的模型,如梯度提升树(GBDT)等。 它特别适合于处理高维、复杂的表格数据,并且比传统模型更能充分利用数据中的深层特征。
  5. 模型训练和推理速度: TabNet 在训练时使用了动态特征选择和逐步决策机制,这使得其在训练时速度较快。 推理时,TabNet 通过稀疏的计算过程显著提高了计算效率,使得在大数据场景下仍能保持良好的速度。
TabNet 的工作原理

TabNet 的架构基于深度神经网络(DNN)和增强的自注意力机制,主要包括以下几个部分:

  1. 特征选择模块:

TabNet 的核心机制是通过 注意力机制 来选择重要的特征。这种注意力机制允许模型动态选择每个决策步骤中最重要的特征,从而进行有效的信息提取。

  1. 决策树模块:

TabNet 在决策时引入了类似决策树的概念,它通过多个阶段的选择和调整来做出最终的预测。每个决策阶段都会依据当前阶段的目标选择不同的特征子集进行处理。

  1. 稀疏激活 (Sparsity) 机制:

TabNet 通过稀疏激活机制提高了模型效率。稀疏激活是指只有少部分特征在每次计算中被激活,这样减少了计算量并提高了效率。

  1. 掩码与路由机制:

TabNet 采用掩码与路由机制(Masking and Routing),它通过学习如何将输入数据映射到一个更小的子集,以便进行后续的预测。 通过这种方式,TabNet 能够更高效地处理复杂数据并减少计算资源的消耗。

TabNet 的优势

适用于表格数据:TabNet 特别适用于处理表格数据,而不像一些深度学习模型(如 CNN 或 RNN)那样主要面向图像或文本数据。 可解释性:通过其自注意力机制,TabNet 提供了比传统深度学习模型(如标准的多层感知机)更高的可解释性。 高效性:TabNet 在计算上相对较为高效,尤其在处理稀疏数据时能有效提升速度。 性能:在多个表格数据集上,TabNet 在准确性上经常超过传统的模型,如 XGBoost 和 LightGBM,尤其在特征选择和高维数据的处理上具有优势。

项目简介

此挑战的目标是根据各种因素预测保险费。

数据集描述

本次比赛的数据集(训练和测试)是根据保险费预测数据集训练的深度学习模型生成的。特征分布与原始分布接近,但不完全相同。请随意使用原始数据集作为本次比赛的一部分,既可以探索差异,也可以看看将原始数据集纳入训练是否可以提高模型性能。 train.csv - 训练数据集;Premium Amount是目标变量 test.csv - 测试数据集;

源码

数据的探索

代码语言:javascript
代码运行次数:0
复制
import numpy as np 
import pandas as pd 
train_data = pd.read_csv('/kaggle/input/playground-series-s4e12/train.csv')
test_data = pd.read_csv('/kaggle/input/playground-series-s4e12/test.csv')
train_data.shape, test_data.shape

这里需要对数据集的数量,缺失值情况等进行查看,不多赘述这块的知识。

代码语言:javascript
代码运行次数:0
复制
numeric_columns = ['Age', 'Annual Income', 'Number of Dependents', 'Health Score', 'Previous Claims', 'Vehicle Age', 'Credit Score', 'Insurance Duration']
train_data[numeric_columns] = train_data[numeric_columns].fillna(train_data[numeric_columns].mean())

categorical_columns = ['Marital Status', 'Occupation', 'Customer Feedback']
train_data[categorical_columns] = train_data[categorical_columns].fillna('unknown')

numeric_columns = ['Age', 'Annual Income', 'Number of Dependents', 'Health Score', 'Previous Claims', 'Vehicle Age', 'Credit Score', 'Insurance Duration']
test_data[numeric_columns] = test_data[numeric_columns].fillna(test_data[numeric_columns].mean())

categorical_columns = ['Marital Status', 'Occupation', 'Customer Feedback']
test_data[categorical_columns] = test_data[categorical_columns].fillna('unknown')

以上是对缺失值进行的数据,test_data和train_data都是要进行同样操作的处理,要保证test_data和train_data的数据维度一致,这样构建的模型在预测test_data时能够正常预测。

代码语言:javascript
代码运行次数:0
复制
# 将 'Policy Start Date' 列转换为 datetime 类型
train_data['Policy Start Date'] = pd.to_datetime(train_data['Policy Start Date'])

# 提取年、月、日、时、分、秒
train_data['Year'] = train_data['Policy Start Date'].dt.year
train_data['Month'] = train_data['Policy Start Date'].dt.month
train_data['Day'] = train_data['Policy Start Date'].dt.day
train_data['Hour'] = train_data['Policy Start Date'].dt.hour
train_data['Minute'] = train_data['Policy Start Date'].dt.minute
train_data['Second'] = train_data['Policy Start Date'].dt.second

== 这里是对时间字段进行的操作,要转换为数值类型。test_data也要进行同样的操作。==

代码语言:javascript
代码运行次数:0
复制
# 遍历所有object类型的字段,查看这些字段的unique()值
for column in train_data.select_dtypes(include=['object']).columns:
    unique_values = train_data[column].unique()
    print(f"Unique values in '{column}': {unique_values}")

查看object类型字段的值,以确定后面的编码方式。

代码语言:javascript
代码运行次数:0
复制
# 创建教育水平的映射字典
education_mapping = {
    'High School': 1,
    "Bachelor's": 2,
    "Master's": 3,
    'PhD': 4
}
policy_type = {
    'Basic':1,
    'Comprehensive':2,
    'Premium':3
}
customer = {
    'unknown':0,
    'Poor':1,
    'Average':2,
    'Good':3
    
}
exercise = {
    'Rarely':1,
    'Monthly':2,
    'Weekly':3,
    'Daily':4   
}

# 使用映射字典进行序列编码
train_data['Education Level'] = train_data['Education Level'].map(education_mapping)
train_data['Policy Type'] = train_data['Policy Type'].map(policy_type)
train_data['Customer Feedback'] = train_data['Customer Feedback'].map(customer)
train_data['Exercise Frequency'] = train_data['Exercise Frequency'].map(exercise)

test_data['Education Level'] = test_data['Education Level'].map(education_mapping)
test_data['Policy Type'] = test_data['Policy Type'].map(policy_type)
test_data['Customer Feedback'] = test_data['Customer Feedback'].map(customer)
test_data['Exercise Frequency'] = test_data['Exercise Frequency'].map(exercise)
代码语言:javascript
代码运行次数:0
复制
from sklearn.preprocessing import OneHotEncoder
import pandas as pd

# 需要处理的列
columns_to_encode = [
    'Gender', 
    'Marital Status', 
    'Occupation', 
    'Location', 
    'Smoking Status', 
    'Property Type'
]

# 初始化one-hot编码器
encoder = OneHotEncoder(drop='first', sparse_output=False)

# 拆分编码器拟合和转换的步奏
train_encoded = encoder.fit_transform(train_data[columns_to_encode])
test_encoded = encoder.transform(test_data[columns_to_encode])

# 将编码后的数据转换为DataFrame,并与原始数据拼接
train_encoded_df = pd.DataFrame(train_encoded, columns=encoder.get_feature_names_out(columns_to_encode))
test_encoded_df = pd.DataFrame(test_encoded, columns=encoder.get_feature_names_out(columns_to_encode))

# 删除原始编码列,并在数据集中合并新编码的列
train_data_encoded = train_data.drop(columns=columns_to_encode).reset_index(drop=True)
test_data_encoded = test_data.drop(columns=columns_to_encode).reset_index(drop=True)

train_data_encoded = pd.concat([train_data_encoded, train_encoded_df], axis=1)
test_data_encoded = pd.concat([test_data_encoded, test_encoded_df], axis=1)

# 查看结果
train_data_encoded.shape, test_data_encoded.shape

以上就是编码的操作,对于有顺序的分类变量进行了映射,也可以使用序列编码,对于没有顺序的分类变量采用独热编码。

代码语言:javascript
代码运行次数:0
复制
# 划分好目标变量和特征
x = train_data_encoded.drop(['id', 'Premium Amount','Policy Start Date'], axis=1)
x_test_encoded = test_data_encoded.drop(['id',  'Policy Start Date'], axis=1).values
y = train_data_encoded['Premium Amount']
代码语言:javascript
代码运行次数:0
复制
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import torch
from pytorch_tabnet.tab_model import TabNetRegressor

# 检查 GPU 的数量
device = 'cuda' if torch.cuda.is_available() else 'cpu'
num_gpus = torch.cuda.device_count()
print(f"Using {num_gpus} GPUs on device: {device}")

# 数据准备:确保 X 和 y 是 NumPy 数组
X = train_data_encoded.drop(['id', 'Premium Amount', 'Policy Start Date'], axis=1).values
y = train_data_encoded['Premium Amount'].values

# 将 y 转换为二维数组
y = y.reshape(-1, 1)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 数据归一化(标准化)
from sklearn.preprocessing import StandardScaler

scaler_X = StandardScaler()
scaler_y = StandardScaler()

X_train = scaler_X.fit_transform(X_train)
X_test = scaler_X.transform(X_test)
y_train = scaler_y.fit_transform(y_train)
y_test = scaler_y.transform(y_test)

# 初始化 TabNet 模型
model = TabNetRegressor(device_name=device)

# 混合精度训练支持
scaler = torch.cuda.amp.GradScaler() if device == 'cuda' else None

# 多 GPU 分片数据
if num_gpus > 1:
    print(f"Using {num_gpus} GPUs with manual data partitioning...")
    
    # 将数据分成 num_gpus 份
    split_size = len(X_train) // num_gpus
    X_train_splits = [X_train[i * split_size:(i + 1) * split_size] for i in range(num_gpus)]
    y_train_splits = [y_train[i * split_size:(i + 1) * split_size] for i in range(num_gpus)]

    # 逐 GPU 分片训练
    for i, (X_split, y_split) in enumerate(zip(X_train_splits, y_train_splits)):
        print(f"Training on GPU {i}...")
        current_device = f'cuda:{i}'
        model = TabNetRegressor(device_name=current_device)
        model.fit(
            X_split, y_split,
            eval_set=[(X_test, y_test)],
            patience=20,               # 提高 early stopping 容忍度
            max_epochs=200,            # 增加最大训练轮数
            batch_size=8192,           # 增大 batch size
            virtual_batch_size=1024,   # 降低虚拟 batch size,减少显存占用
            num_workers=8,             # 增加 worker 数
            drop_last=True
        )
else:
    print("Training on a single GPU...")
    # 单 GPU 训练
    model.fit(
        X_train, y_train,
        eval_set=[(X_test, y_test)],
        patience=20,                  # 提高 early stopping 容忍度
        max_epochs=200,               # 增加最大训练轮数
        batch_size=8192,              # 增大 batch size
        virtual_batch_size=1024,      # 降低虚拟 batch size,减少显存占用
        num_workers=8,                # 增加 worker 数
        drop_last=True
    )

# 在测试集上预测
print("Model evaluation...")
y_pred = model.predict(X_test)

# 反归一化预测结果
y_pred = scaler_y.inverse_transform(y_pred)
y_test = scaler_y.inverse_transform(y_test)

# 评估模型性能
mse = mean_squared_error(y_test, y_pred)
print(f"Test MSE: {mse}")

# 准备真实数据的特征
print("Preparing prediction on real data...")
real_X = x_test_encoded.values
real_X = scaler_X.transform(real_X)  # 归一化特征数据

# 预测真实数据
real_y_pred = model.predict(real_X)

# 反归一化真实预测
real_y_pred = scaler_y.inverse_transform(real_y_pred)

# 获取真实数据的 id
id = test_data['id'].values

# 确保形状匹配
real_y_pred = real_y_pred.flatten()
if len(id) != len(real_y_pred):
    raise ValueError(f"Length mismatch: id ({len(id)}) and predictions ({len(real_y_pred)})")

# 创建结果 DataFrame
result_df = pd.DataFrame({
    'id': id,
    'Premium Amount': real_y_pred
})

# 保存结果为 CSV 文件
result_df.to_csv('predicted_results.csv', index=False)
print("Prediction results saved to 'predicted_results.csv'")

# 显示结果
print(result_df.head())

本次竞赛的数据集训练数据有120w,因此考虑要使用Gpu进行训练,其运行速度更快。

以上就是损失图像,可以看到效果还行。 batch_size和virtual_batch_size的含义

  1. batch_size(批量大小) batch_size 是指每次模型训练时使用的样本数量。每次更新模型参数时,使用这个数量的数据来计算梯度。 较小的 batch_size 更频繁地更新参数,但训练慢;较大的 batch_size 更新参数较少,但训练更快。
  2. virtual_batch_size(虚拟批量大小) virtual_batch_size 是在显存有限时,用来模拟一个更大 batch_size 的方法。 它通过 梯度累积 实现,即分多次处理小批量数据,累积它们的梯度,再更新一次模型参数。这样可以有效增加批量大小,而不增加显存占用。

batch_size 是每次处理的数据量。 virtual_batch_size 通过分批次累积梯度来模拟更大的 batch_size,帮助节省显存。

处理表格数据的神经网络比较少,除了上述这个,其实卷积神经网络也是可以处理时间序列数据,只需将卷积核进行改变即可。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-12-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本文使用深度学习来预测表格数据
    • TabNet 简介
    • TabNet 的工作原理
    • TabNet 的优势
  • 项目简介
  • 数据集描述
  • 源码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档