0


使用结构化表格数据对比深度学习和GBDT模型

在数据科学的世界里,深度学习方法无疑是最先进的研究。每天都有许多新的变化被发明和实现,特别是在自然语言处理(NLP)和计算机视觉(CV)领域,深度学习在近年来取得了巨大的进步。这种趋势也可以在Kaggle比赛中观察到。在这些NLP和CV任务竞赛中,最近获胜的解决方案是利用深度学习模型。

然而,深度学习模型真的比GBDT(梯度提升决策树)这样的“传统”机器学习模型更好吗?我们知道,正如上面提到的,深度学习模型在NLP和CV中要好得多,但在现实生活中,我们仍然有很多表格数据,我们是否可以确认,即使在结构化数据集上,深度学习模型也比GBDT模型表现得更好?为了回答这个问题,本文使用Kaggle的家庭保险数据集来比较每个模型的性能。我知道我们不能仅仅通过一个数据集就得出哪个模型更好的结论,但这将是一个很好的起点来查看比较。此外,我将使用TabNet,这是一个相对较新的表格数据深度学习模型来进行比较。

这个实验的笔记本可以在我的kaggle代码中找到(https://www.kaggle.com/kyosukemorita/deep-learning-vs-gbdt-model-on-tabular-data)。这篇文章将省略对每个算法的解释,因为已经有很多这样的算法了:)

代码片段

如上所述,本实验使用了家庭保险数据集。这个数据集包括2007年到2012年的家庭保险政策数据,有超过100个特征,关于家庭特征,业主的人口统计等,在这个数据中有超过25万行。利用这个数据集,这个实验试图预测一份家庭保险政策是否会失效。不幸的是,并没有给出这个数据集中所有变量的细节,但是做这个实验已经足够好了。

现在我将通过这个实验的代码。这是最低限度的,应该是显而易见的。

首先,导入库。

import os
import numpy as np
import pandas as pd
import warnings
import time
from datetime import datetime
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import torch
from pytorch_tabnet.pretraining import TabNetPretrainer
from pytorch_tabnet.tab_model import TabNetClassifier
from sklearn.metrics import accuracy_score, f1_score, confusion_matrix, roc_auc_score
import xgboost as xgb
from tensorflow import keras
from tensorflow.keras import layers
import matplotlib.pyplot as plt

warnings.filterwarnings("ignore")

然后,创建一个计时函数,

def timer(myFunction):
    def functionTimer(*args, **kwargs):
        start_time = time.time()
        result = myFunction(*args, **kwargs)
        end_time = time.time()
        computation_time = round(end_time - start_time, 2)
        print("{} is excuted".format(myFunction.__name__))
        print('Computation took: {:.2f} seconds'.format(computation_time))
        return result
    return functionTimer

这样我们就可以追踪函数运行的时间。

现在,这是数据集的预处理。这个过程包括

  1. 排除缺失值
  2. 清除目标变量
  3. 为分类变量创建虚拟变量
  4. 创建年龄特征
  5. 处理其他缺失值
@timer
def prepareInputs(df: "pd.dataFrame") -> "pd.dataFrame":
    """Prepare the input for training

    Args:
        df (pd.DataFrame): raw data
        
    Process:
        1. Exclude missing values
        2. Clean the target variable
        3. Create dummy variables for categorical variables
        4. Create age features
        5. Impute missing value
    
    Return: pd.dataFrame
    """
    
    # 1. Exclude missing values
    df = df[df["POL_STATUS"].notnull()]
    
    # 2. Clean the target variable
    df = df[df["POL_STATUS"] != "Unknown"]
    df["lapse"] = np.where(df["POL_STATUS"] == "Lapsed", 1, 0)
    
    # 3. Create dummy variables for categorical variables
    categorical_cols = ["CLAIM3YEARS", "BUS_USE", "AD_BUILDINGS",
                        "APPR_ALARM", "CONTENTS_COVER", "P1_SEX",
                        "BUILDINGS_COVER", "P1_POLICY_REFUSED", 
                        "APPR_LOCKS", "FLOODING",
                        "NEIGH_WATCH", "SAFE_INSTALLED", "SEC_DISC_REQ",
                        "SUBSIDENCE", "LEGAL_ADDON_POST_REN", 
                        "HOME_EM_ADDON_PRE_REN","HOME_EM_ADDON_POST_REN", 
                        "GARDEN_ADDON_PRE_REN", "GARDEN_ADDON_POST_REN", 
                        "KEYCARE_ADDON_PRE_REN", "KEYCARE_ADDON_POST_REN", 
                        "HP1_ADDON_PRE_REN", "HP1_ADDON_POST_REN",
                        "HP2_ADDON_PRE_REN", "HP2_ADDON_POST_REN", 
                        "HP3_ADDON_PRE_REN", "HP3_ADDON_POST_REN", 
                        "MTA_FLAG", "OCC_STATUS", "OWNERSHIP_TYPE",
                        "PROP_TYPE", "PAYMENT_METHOD", "P1_EMP_STATUS",
                        "P1_MAR_STATUS"
                        ]
    
    for col in categorical_cols:
        dummies = pd.get_dummies(df[col], 
                                 drop_first = True,
                                 prefix = col
                                )
        df = pd.concat([df, dummies], 1)
    
    # 4. Create age features
    df["age"] = (datetime.strptime("2013-01-01", "%Y-%m-%d") - pd.to_datetime(df["P1_DOB"])).dt.days // 365
    df["property_age"] = 2013 - df["YEARBUILT"]
    df["cover_length"] = 2013 - pd.to_datetime(df["COVER_START"]).dt.year
    
    # 5. Impute missing value
    df["RISK_RATED_AREA_B_imputed"] = df["RISK_RATED_AREA_B"].fillna(df["RISK_RATED_AREA_B"].mean())
    df["RISK_RATED_AREA_C_imputed"] = df["RISK_RATED_AREA_C"].fillna(df["RISK_RATED_AREA_C"].mean())
    df["MTA_FAP_imputed"] = df["MTA_FAP"].fillna(0)
    df["MTA_APRP_imputed"] = df["MTA_APRP"].fillna(0)

    return df

为了训练和评估模型,我将分割数据集。

# Split train and test
@timer
def splitData(df: "pd.DataFrame", FEATS: "list"):
    """Split the dataframe into train and test
    
    Args:
        df: preprocessed dataframe
        FEATS: feature list
        
    Returns:
        X_train, y_train, X_test, y_test
    """
    
    train, test = train_test_split(df, test_size = .3, random_state = 42)
    train, test = prepareInputs(train), prepareInputs(test)
    
    return train[FEATS], train["lapse"], test[FEATS], test["lapse"]

用深度学习模型训练数字特征需要标准化。这个函数完成了这项工作。

# Standardise the data sets
@timer
def standardiseNumericalFeats(X_train, X_test):
    """Standardise the numerical features
    
    Returns:
        Standardised X_train and X_test
    """

    numerical_cols = [
        "age", "property_age", "cover_length", "RISK_RATED_AREA_B_imputed", 
        "RISK_RATED_AREA_C_imputed", "MTA_FAP_imputed", "MTA_APRP_imputed",
        "SUM_INSURED_BUILDINGS", "NCD_GRANTED_YEARS_B", "SUM_INSURED_CONTENTS", 
        "NCD_GRANTED_YEARS_C", "SPEC_SUM_INSURED", "SPEC_ITEM_PREM", 
        "UNSPEC_HRP_PREM", "BEDROOMS", "MAX_DAYS_UNOCC", "LAST_ANN_PREM_GROSS"
    ]

    for col in numerical_cols:
        scaler = StandardScaler()

        X_train[col] = scaler.fit_transform(X_train[[col]])
        X_test[col] = scaler.transform(X_test[[col]])
        
    return X_train, X_test

现在所有的预处理都完成了。下面,我将展示每个模型的训练代码。

XGBoost

@timer
def trainXgbModel(X_train, y_train, X_test, y_test, FEATS, ROUNDS) -> "XGBoost model obj":
    """Train XGBoost model
    
    Arg:
        ROUNDS: Number of training rounds
    
    Return:
        Model object
    """
    
    params = {
                'eta': 0.02,
                'max_depth': 10,
                'min_child_weight': 7,
                'subsample': 0.6,
                'objective': 'binary:logistic',
                'eval_metric': 'error',
                'grow_policy': 'lossguide'
            }
    
    dtrain, dtest = xgb.DMatrix(X_train, y_train, feature_names=FEATS), xgb.DMatrix(X_test, y_test, feature_names=FEATS)

    EVAL_LIST = [(dtrain, "train"),(dtest, "test")]

    xgb_model = xgb.train(params,dtrain,ROUNDS,EVAL_LIST)
    
    return xgb_model

MLP (1D-CNN)

@timer
def trainD1CnnModel(X_train, y_train):
    """Train D1-CNN model
    
    Return:
        keras model obj
    """

    d1_cnn_model = keras.Sequential([
        layers.Dense(4096, activation='relu'),
        layers.Reshape((256, 16)),
        layers.BatchNormalization(),
        layers.Dropout(0.2),
        layers.Conv1D(filters=16, kernel_size=5, strides=1, activation='relu'),
        layers.MaxPooling1D(pool_size=2),
        layers.Flatten(),
        layers.Dense(16, activation='relu'),
        layers.Dense(1, activation='sigmoid'),
    ])

    d1_cnn_model.compile(
        optimizer=keras.optimizers.Adam(learning_rate=3e-3),
        loss='binary_crossentropy',
        metrics=[keras.metrics.BinaryCrossentropy()]
    )

    early_stopping = keras.callbacks.EarlyStopping(
        patience=25,
        min_delta=0.001,
        restore_best_weights=True,
    )

    d1_cnn_model.fit(
        X_train, y_train,
        batch_size=10000,
        epochs=5000,
        callbacks=[early_stopping],
        validation_data=(X_test, y_test),
    )
    
    return d1_cnn_model

TabNet

@timer
def trainTabNetModel(X_train, y_train, pretrainer):
    """Train TabNet model
    
    Args:
        pretrainer: pretrained model. If not using this, use None
        
    Return:
        TabNet model obj
    """
    
    tabNet_model = TabNetClassifier(
                                   n_d=16,
                                   n_a=16,
                                   n_steps=4,
                                   gamma=1.9,
                                   n_independent=4,
                                   n_shared=5,
                                   seed=42,
                                   optimizer_fn = torch.optim.Adam,
                                   scheduler_params = {"milestones": [150,250,300,350,400,450],'gamma':0.2},
                                   scheduler_fn=torch.optim.lr_scheduler.MultiStepLR
                                  )

    tabNet_model.fit(
        X_train = X_train.to_numpy(),
        y_train = y_train.to_numpy(),
        eval_set=[(X_train.to_numpy(), y_train.to_numpy()),
                  (X_test.to_numpy(), y_test.to_numpy())],
        max_epochs = 100,
        batch_size = 256,
        patience = 10,
        from_unsupervised = pretrainer
        )
    
    return tabNet_model

TabNet 使用预训练

预训练部分

@timer
def tabNetPretrain(X_train):
    """Pretrain TabNet model

    Return:
        TabNet pretrainer obj
    """
    tabnet_params = dict(n_d=8, n_a=8, n_steps=3, gamma=1.3,
                             n_independent=2, n_shared=2,
                             seed=42, lambda_sparse=1e-3,
                             optimizer_fn=torch.optim.Adam,
                             optimizer_params=dict(lr=2e-2,
                                                   weight_decay=1e-5
                                                  ),
                             mask_type="entmax",
                             scheduler_params=dict(max_lr=0.05,
                                                   steps_per_epoch=int(X_train.shape[0] / 256),
                                                   epochs=200,
                                                   is_batch_level=True
                                                  ),
                             scheduler_fn=torch.optim.lr_scheduler.OneCycleLR,
                             verbose=10
                        )

    pretrainer = TabNetPretrainer(**tabnet_params)

    pretrainer.fit(
        X_train=X_train.to_numpy(),
        eval_set=[X_train.to_numpy()],
        max_epochs = 100,
        patience = 10, 
        batch_size = 256, 
        virtual_batch_size = 128,
        num_workers = 1, 
        drop_last = True)

    return pretrainer

TabNet训练可以通过上面的“trainTabNetModel”函数来完成。

训练完成后,我们需要对测试集做出预测并进行评估。

预测

# Make predictions
def makePredictions(X_test, xgb_model, d1_cnn_model, tabNet_model):
    """Make predictions

    Return:
        Predictions from each models
    """

    y_xgb_pred = xgb_model.predict(xgb.DMatrix(X_test, feature_names=FEATS))
    y_d1_cnn_pred = d1_cnn_model.predict(X_test).reshape(1, -1)[0]
    y_tabNet_pred = tabNet_model.predict_proba(X_test.to_numpy())[:,1]

    return [y_xgb_pred, y_d1_cnn_pred, y_tabNet_pred]

指标评估

# Evaluation
def evaluate(y_xgb_pred, y_d1_cnn_pred, y_tabNet_pred) -> None:
    """Evaluate the predictions

    Process:
        Print ROC AUC and F1 score of each models
    """

    preds = {"XGBoost":y_xgb_pred, "D1 CNN":y_d1_cnn_pred, "TabNet":y_tabNet_pred}

    for key in preds:
        print("The ROC AUC score of "+ str(key) +" model is " +
              str(round(roc_auc_score(y_test, preds[key]), 4))
             )

    for key in preds:
        print("The F1 score of "+ str(key) +" model at threshold = 0.27 is " +
              str(round(f1_score(y_test, np.where(preds[key] > 0.27, 1, 0)), 4))
             )

可视化

# Plot prediction distribution
def plotPredictionDistribution(y_xgb_pred, y_d1_cnn_pred, y_tabNet_pred) -> None:
    """Plot histogram of predicted probability distributions of each model
    """

    preds = {"XGBoost":y_xgb_pred, "D1 CNN":y_d1_cnn_pred, "TabNet":y_tabNet_pred}

    for key in preds:
        plt.hist(preds[key], bins = 100)
        plt.title(f"Predicted probability distribution of {key}")
        plt.show()

最后,这里是要在上面运行的主要脚本。

ROUNDS = 500

FEATS = [
         "CLAIM3YEARS_Y", "BUS_USE_Y", "AD_BUILDINGS_Y",
         "CONTENTS_COVER_Y", "P1_SEX_M", "P1_SEX_N", "BUILDINGS_COVER_Y", 
         "P1_POLICY_REFUSED_Y", "APPR_ALARM_Y", "APPR_LOCKS_Y", "FLOODING_Y", 
         "NEIGH_WATCH_Y", "SAFE_INSTALLED_Y", "SEC_DISC_REQ_Y", "SUBSIDENCE_Y", 
         "LEGAL_ADDON_POST_REN_Y", "HOME_EM_ADDON_PRE_REN_Y", 
         "HOME_EM_ADDON_POST_REN_Y", "GARDEN_ADDON_PRE_REN_Y",
         "GARDEN_ADDON_POST_REN_Y", "KEYCARE_ADDON_PRE_REN_Y", 
         "KEYCARE_ADDON_POST_REN_Y", "HP1_ADDON_PRE_REN_Y", "HP1_ADDON_POST_REN_Y", 
         "HP2_ADDON_PRE_REN_Y", "HP2_ADDON_POST_REN_Y", "HP3_ADDON_PRE_REN_Y", 
         "HP3_ADDON_POST_REN_Y", "MTA_FLAG_Y", "OCC_STATUS_LP",
         "OCC_STATUS_PH", "OCC_STATUS_UN", "OCC_STATUS_WD",
         "OWNERSHIP_TYPE_2.0", "OWNERSHIP_TYPE_3.0", "OWNERSHIP_TYPE_6.0", 
         "OWNERSHIP_TYPE_7.0", "OWNERSHIP_TYPE_8.0", "OWNERSHIP_TYPE_11.0", 
         "OWNERSHIP_TYPE_12.0", "OWNERSHIP_TYPE_13.0", "OWNERSHIP_TYPE_14.0", 
         "OWNERSHIP_TYPE_16.0", "OWNERSHIP_TYPE_17.0", 
         "OWNERSHIP_TYPE_18.0", "PROP_TYPE_2.0", "PROP_TYPE_3.0", "PROP_TYPE_4.0", 
         "PROP_TYPE_7.0", "PROP_TYPE_9.0", "PROP_TYPE_10.0", 
         "PROP_TYPE_16.0", "PROP_TYPE_17.0", "PROP_TYPE_18.0", "PROP_TYPE_19.0", 
         "PROP_TYPE_20.0", "PROP_TYPE_21.0", "PROP_TYPE_22.0", "PROP_TYPE_23.0", 
         "PROP_TYPE_24.0", "PROP_TYPE_25.0", "PROP_TYPE_26.0", "PROP_TYPE_27.0", 
         "PROP_TYPE_29.0", "PROP_TYPE_30.0", "PROP_TYPE_31.0", 
         "PROP_TYPE_32.0", "PROP_TYPE_37.0", "PROP_TYPE_39.0", 
         "PROP_TYPE_40.0", "PROP_TYPE_44.0", "PROP_TYPE_45.0", "PROP_TYPE_47.0", 
         "PROP_TYPE_48.0", "PROP_TYPE_51.0", "PROP_TYPE_52.0", "PROP_TYPE_53.0", 
         "PAYMENT_METHOD_NonDD", "PAYMENT_METHOD_PureDD", "P1_EMP_STATUS_C", 
         "P1_EMP_STATUS_E", "P1_EMP_STATUS_F", "P1_EMP_STATUS_H", "P1_EMP_STATUS_I", 
         "P1_EMP_STATUS_N", "P1_EMP_STATUS_R", "P1_EMP_STATUS_S", "P1_EMP_STATUS_U", 
         "P1_EMP_STATUS_V", "P1_MAR_STATUS_B", "P1_MAR_STATUS_C", "P1_MAR_STATUS_D", 
         "P1_MAR_STATUS_M", "P1_MAR_STATUS_N", "P1_MAR_STATUS_O", "P1_MAR_STATUS_P", 
         "P1_MAR_STATUS_S", "P1_MAR_STATUS_W", 
         "age", "property_age", "cover_length", "RISK_RATED_AREA_B_imputed", 
         "RISK_RATED_AREA_C_imputed", "MTA_FAP_imputed", "MTA_APRP_imputed",
         "SUM_INSURED_BUILDINGS", "NCD_GRANTED_YEARS_B", "SUM_INSURED_CONTENTS", 
         "NCD_GRANTED_YEARS_C", "SPEC_SUM_INSURED", "SPEC_ITEM_PREM", 
         "UNSPEC_HRP_PREM", "BEDROOMS", "MAX_DAYS_UNOCC", "LAST_ANN_PREM_GROSS"
        ]

print("Reading the data")
df = pd.read_csv("../input/home-insurance/home_insurance.csv")

print("Preprocessing the data")
X_train, y_train, X_test, y_test = splitData(df, FEATS)
X_train, X_test = standardiseNumericalFeats(X_train, X_test)

print("The ratio of lapse class in training set is " +
      str(round(y_train.sum()/len(y_train) * 100, 2)) +
      "%"
     )

print("The ratio of lapse class in test set is " +
      str(round(y_test.sum()/len(y_test) * 100, 2)) +
      "%"
     )

print("Training XGBoost model")
xgb_model = trainXgbModel(X_train, y_train, X_test, y_test, FEATS, ROUNDS)

print("Training MLP model")
d1_cnn_model = trainD1CnnModel(X_train, y_train)

print("Training TabNet model")
tabNet_model = trainTabNetModel(X_train, y_train, None)

print("Making predictions")
y_xgb_pred, y_d1_cnn_pred, y_tabNet_pred = makePredictions(X_test, xgb_model, d1_cnn_model, tabNet_model)

print("Evaluation of the model")
evaluate(y_xgb_pred, y_d1_cnn_pred, y_tabNet_pred)

print("Prediction distribution")
plotPredictionDistribution(y_xgb_pred, y_d1_cnn_pred, y_tabNet_pred)

上面是代码片段。现在,我们将在下面的部分中看到这个实验的结果。

模型的性能

如上所述,本文比较了经过和不经过预处理的XGBoost、MLP和TabNet的模型性能。采用ROC曲线下面积(AUC)评分和F1评分对模型进行评价。F1得分以0.27为阈值计算,因为我假设过期保险的分布与训练分布相似。下面是它的摘要。

可以看出,就模型的精度而言,XGBoost模型是最好的,其他模型也相差不远。我已经使用了with和without pretraining的TabNet模型。经过预训练的TabNet结果应该更好,但是在这个数据集中,它得到的结果比没有进行预训练的结果略差。我不确定确切的原因是什么,但我猜这可以通过适当的超参数改进。

当我们研究每个模型的预测分布时,我们可以观察到XGBoost和TabNet模型之间有一定程度的相似性。我想这可能是因为TabNet也使用了类似树的算法。MLP模型的形状与其他模型有很大的不同。

在训练时间方面,MLP模型是最快的。我用过GPU,所以这是我得到这个结果的主要原因。与其他机型相比,TabNet两种机型都花费了相当长的时间。当涉及到超参数调优时,这将产生很大的差异。在这个实验中,我没有做任何超参数调优,而是使用任意参数。虽然MLP的训练时间几乎是XGBoost模型的1/3,但它需要优化的参数数量很容易超过XGBoost的10倍,所以如果我正在进行超参数优化,它可能需要比使用超参数优化的XGBoost模型的训练时间更长。

可解释性

可解释性对于一些机器学习模型业务用例是非常重要的。例如,能够解释为什么一个模型在金融/银行业中做出特定的决策是至关重要的。假设我们正在部署一个可以用于贷款批准的模型,并且客户想知道他的申请被拒绝的原因。银行不能告诉他我们不知道,因为这个行业有强大的监管机构。

模型的可解释性是MLP模型的缺点之一。虽然我们仍然可以使用一些方法(如使用SHAP)来评估哪些特性对做出预测做出了贡献,但如果我们能够快速检查特性的重要性列表,那将会更有用。在这里我将只比较XGBoost和TabNe特性的重要性。

XGBoost模型最重要的5个特性是:

  • Marital status — Partner
  • Payment method — Non-Direct debit
  • Option “Emergencies” included after 1st renewal
  • Building coverage — Self-damage
  • Option “Replacement of keys” included before 1st renewal

TabNet模型的前5个重要特征是:

  • Property type 21 (Detail not given)
  • “HP1” included before 1st renewal
  • Payment method — Pure Direct debit
  • Type of membership 6 (Detail not given)
  • Insurance cover length in years

令人惊讶的是,这两种模式的重要特征截然不同。XGBoost的重要特性对我来说更“可以理解和期待”——例如,如果客户有合作伙伴,这个人应该在财务上更负责,因此,家庭保险不太可能失效。另一方面,我想说,TabNet的重要特性没有那么直观。最重要的特性是“属性类型21”,这里没有给出这个特性的细节,所以我们不知道这个属性类型的特殊之处。第二重要的功能是在第一次更新之前就包含了“HP1”,我们不知道“HP1”是什么。也许,这就是TabNet的优势所在。由于它是一个深度学习模型,它可以探索特征之间不明显的关系,并使用最优的特征集,特别是像这次,没有给出所有特征的细节。

实际业务中部署的模型选择

当我们想要在现实生活中使用机器学习模型时,我们需要选择部署模型的最佳方式,通常会有一些权衡。例如,当我们建立几个像这次这样的模型,并且这些模型的精度非常相似时,集成它们可能会提高精度。如果这个整体策略很好地提高了10%的F1分数,那么采取这个策略是绝对必要的,但是如果这个改进只有1%,我们还想采取这个策略吗?可能不是,对吧?-由于多运行一个模型会增加计算成本,所以通常如果多部署一个模型的好处超过了计算成本,我们可以采用这个集成策略,否则,它在业务方面不是最优的。

此外,关于模型的可解释性,XGBoost模型使用了所有115个特性,而TabNet模型只使用了16个特性(预先训练的模型只使用了4个特性)。这是一个巨大的差异,理解这些差异也很重要。正如我上面提到的,在一些实际的业务用例中,了解这些特性的贡献是非常重要的。所以有时候,虽然准确率很高,但如果模型不能解释它为什么做出那个决定,就很难说服人们在现实生活中使用它,尤其是在非常敏感的业务中。

考虑到以上两点,在本例中,我们认为XGBoost模型优于其他深度学习模型。在精度方面,XGBoost模型比其他模型稍好一些(我没有尝试集成所有模型的预测,但让我们假设,它没有提高精度——我可能是错的)。就可解释性而言,如上所述,XGBoost模型的特性重要性列表在某种程度上是我们可以理解的(我们可以看到它背后的一些逻辑),而且在某种程度上是我们所期望的。

总结

本实验比较了XGBoost、MLP和TabNet在表格数据上的模型性能。这里我们使用家庭保险数据集来预测它的效果。从本次实验的结果来看,XGBoost模型在准确率(F1评分和ROC AUC评分)方面略优于其他深度学习模型,但由于本次实验使用GPU, MLP模型完成训练的速度最快。此外,通过查看XGBoost模型和TabNet模型的特性重要性列表,我们比较了它们的可解释性。XGBoost模型的特性重要性列表在某种程度上更容易理解和预期,另一方面,TabNet模型的特性重要性列表就不那么直观了。我认为这是由于算法的结构——深度学习模型,从本质上来说,探索的是特征之间不明显的关系,通常很难被人理解。通过这个简单的实验,我们证实了尽管近年来深度学习模型的改进令人印象深刻,而且肯定是最先进的,但在表格数据上,GBDT模型仍然和那些深度学习模型一样好,有时甚至比它们更好,特别是当我们想在现实生活中部署机器学习模型的时候。

作者:Kyosuke Morita

原文地址:https://towardsdatascience.com/deep-learning-vs-gbdt-model-on-tabular-data-with-code-snippet-e4b3dd525552

deephub翻译组

标签:

“使用结构化表格数据对比深度学习和GBDT模型”的评论:

还没有评论