Kaggle知识点:类别变量处理与精度对比

共 5024字,需浏览 11分钟

 ·

2024-05-16 17:30

   
来源:Coggle数据科学

本文约1200字,建议阅读4分钟

本文将使用埃姆斯爱荷华州房屋数据集进行房价分析。


在这个例子中,我们将比较使用不同的编码策略来处理分类特征时,HistGradientBoostingRegressor 的训练时间和预测性能。具体来说,我们将评估以下几种方法:

  • 删除分类特征;
  • 使用 OneHotEncoder;
  • 使用 OrdinalEncoder,将分类特征视为有序、等距的量;
  • 使用 OrdinalEncoder,并依赖于 HistGradientBoostingRegressor 估计器的原生类别支持。

我们将使用埃姆斯爱荷华州房屋数据集进行工作,该数据集包含数值和分类特征,其中房屋销售价格是目标变量。

步骤1:加载数据集

    
from sklearn.datasets import fetch_openml
X, y = fetch_openml(data_id=42165, as_frame=True, return_X_y=True)
# Select only a subset of features of X to make the example faster to runcategorical_columns_subset = [ "BldgType", "GarageFinish", "LotConfig", "Functional", "MasVnrType", "HouseStyle", "FireplaceQu", "ExterCond", "ExterQual", "PoolQC",]
numerical_columns_subset = [ "3SsnPorch", "Fireplaces", "BsmtHalfBath", "HalfBath", "GarageCars", "TotRmsAbvGrd", "BsmtFinSF1", "BsmtFinSF2", "GrLivArea", "ScreenPorch",]
X = X[categorical_columns_subset + numerical_columns_subset]X[categorical_columns_subset] = X[categorical_columns_subset].astype("category")
categorical_columns = X.select_dtypes(include="category").columnsn_categorical_features = len(categorical_columns)n_numerical_features = X.select_dtypes(include="number").shape[1]
print(f"Number of samples: {X.shape[0]}")print(f"Number of features: {X.shape[1]}")print(f"Number of categorical features: {n_categorical_features}")print(f"Number of numerical features: {n_numerical_features}")


步骤2:基准模型(删除类别变量)

    
from sklearn.compose import make_column_selector, make_column_transformerfrom sklearn.ensemble import HistGradientBoostingRegressorfrom sklearn.pipeline import make_pipeline
dropper = make_column_transformer( ("drop", make_column_selector(dtype_include="category")), remainder="passthrough")hist_dropped = make_pipeline(dropper, HistGradientBoostingRegressor(random_state=42))


步骤3:OneHot类别变量

from sklearn.preprocessing import OneHotEncoder
one_hot_encoder = make_column_transformer( ( OneHotEncoder(sparse_output=False, handle_unknown="ignore"), make_column_selector(dtype_include="category"), ), remainder="passthrough",)
hist_one_hot = make_pipeline( one_hot_encoder, HistGradientBoostingRegressor(random_state=42))

步骤4:Ordinal类别变量

    
import numpy as np
from sklearn.preprocessing import OrdinalEncoder
ordinal_encoder = make_column_transformer( ( OrdinalEncoder(handle_unknown="use_encoded_value", unknown_value=np.nan), make_column_selector(dtype_include="category"), ), remainder="passthrough", # Use short feature names to make it easier to specify the categorical # variables in the HistGradientBoostingRegressor in the next step # of the pipeline. verbose_feature_names_out=False,)
hist_ordinal = make_pipeline( ordinal_encoder, HistGradientBoostingRegressor(random_state=42))


步骤5:原生类别支持

    
hist_native = HistGradientBoostingRegressor(    random_state=42, categorical_features="from_dtype")


步骤6:对比模型速度和精度

    
from sklearn.model_selection import cross_validate
scoring = "neg_mean_absolute_percentage_error"n_cv_folds = 3
dropped_result = cross_validate(hist_dropped, X, y, cv=n_cv_folds, scoring=scoring)one_hot_result = cross_validate(hist_one_hot, X, y, cv=n_cv_folds, scoring=scoring)ordinal_result = cross_validate(hist_ordinal, X, y, cv=n_cv_folds, scoring=scoring)native_result = cross_validate(hist_native, X, y, cv=n_cv_folds, scoring=scoring)


我们可以观察到,使用独热编码的模型明显最慢。这是可以预期的,因为独热编码为每个类别值(对于每个分类特征)创建了一个额外的特征,因此在拟合过程中需要考虑更多的分裂点。

理论上,我们预期原生处理分类特征的速度会略慢于将类别视为有序量('Ordinal'),因为原生处理需要对类别进行排序。

通常情况下,可以预期使用独热编码的数据会导致更差的预测结果,特别是当树的深度或节点数量受限时:使用独热编码的数据,需要更多的分裂点,即更深的树,才能恢复相当于原生处理中的一个单一分裂点所能获得的等效分裂。

当类别被视为有序量时,这一点同样适用:如果类别为A..F,最佳分裂是ACF - BDE,则独热编码模型将需要3个分裂点(左节点中的每个类别一个),而非原生模型将需要4个分裂:1个分裂来隔离A,1个分裂来隔离F,以及2个分裂来从BCDE中隔离C。

代码链接:https://scikit-learn.org/stable/auto_examples/ensemble/plot_gradient_boosting_categorical.html


编辑:黄继彦

浏览 15
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报