OneHotEncoding 丢失了 Lasso 回归的列标识

Posted

技术标签:

【中文标题】OneHotEncoding 丢失了 Lasso 回归的列标识【英文标题】:OneHotEncoding losing column identity for Lasso Regression 【发布时间】:2021-03-11 21:29:27 【问题描述】:

我有一个干净的住房数据集,其中包含大约 75 个总特征和 1 个目标变量。 为了使用 lasso 回归来选择 75 个特征中最相关的,我只能对分类特征使用标签编码,因为它保留了列标识,如下所示:

# Label Encoding all other categorical features:

for x in categorical_features:
    labels_ordered=house_df.groupby([x])['SalePrice'].mean().sort_values().index  # SalePrice is target variable
    labels_ordered=k:i for i,k in enumerate(labels_ordered,0)
    house_df[x]=house_df[x].map(labels_ordered)

# After splitting into train/test and fitting the lasso
feature_sel_model = SelectFromModel(Lasso(alpha=0.005, random_state=0))
feature_sel_model.fit(X_train, y_train)

# Checking the array of selected and rejected features
feature_sel_model.get_support()

O/P: array([ True,  True, False, False, False, False, False, False, False,
       False,  True, False, False, False, False,  True,  True, False,
        True, False, False, False, False, False, False, False, False,
        True,  True, False,  True, False,  True, False, False, False,
        True, False,  True,  True, False,  True, False, False,  True,
       False, False, False, False, False, False,  True, False, False,
        True, False, False, False,  True,  True,  True, False, False,
        True, False, False, False, False, False, False, False, False,
       False, False,  True])


# Making a list of the selected features
selected_feat = X_train.columns[(feature_sel_model.get_support())]

# let's print some stats
print('total features: '.format((X_train.shape[1])))
print('selected features: '.format(len(selected_feat)))

O/P: total features: 75
selected features: 22

需要列标识才能使用lasso回归的输出并从原始数据集中去除不相关的特征。

我的问题是分类特征有多个标签而不是序数,所以使用 sklearn 的 OneHotEncoding 实际上是最好的编码方法,但会创建一个复杂的矩阵,破坏列标识。如何使用 OHE 的输出(这是一个 np.array,所有编码变量都被带到矩阵的左侧)来馈送到套索回归器?还是我应该坚持标签编码?

【问题讨论】:

【参考方案1】:

首先,在使用 Lasso 来衡量特征重要性时,您应该缩放数字特征(我在示例中使用了 MinMaxScaler)。

使用pandas.get_dummies()

# One Hot Encoding 
ohe_df = pd.get_dummies(house_df, columns=list_cat_of_cols)

# split into train/test and do other stuff
...

使用 sklearn 中的 OneHotEncoder

OneHotEncoder 有一个方法get_feature_names() 通过调用ohe.get_feature_names(cat_cols),它将返回编码分类列的标签。

我建议阅读文档以获得进一步的解释。

例子:

import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder, MinMaxScaler
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import Lasso
from sklearn.compose import ColumnTransformer

df = pd.DataFrame('A1': ['a','a','b','a','c','b'],
                   'A2': ['x', 'y', 'y', 'y', 'x', 'x'],
                   'B': [1,2,3,1,5,2],
                   'C': [1.19,2.21,3.51,1.23,5.12,2.49])
X = df.drop(columns=['C'])
y = df['C']

cat_cols = ['A1', 'A2']
other_cols = X.drop(columns=cat_cols).columns

ct = ColumnTransformer([('ohe', OneHotEncoder(sparse=False), cat_cols)], remainder=MinMaxScaler())
encoded_matrix = ct.fit_transform(X)

encoded_cols = ct.named_transformers_.ohe.get_feature_names(cat_cols)
all_features = np.concatenate([encoded_cols, other_cols])
print('all_features:', all_features)

feature_sel_model = SelectFromModel(Lasso(alpha=0.05))
feature_sel_model.fit(encoded_matrix, y)
feature_mask = feature_sel_model.get_support()
print('selected_features:', all_features[feature_mask])

输出:

all_features: ['A1_a' 'A1_b' 'A1_c' 'A2_y' 'B']
selected_features: ['A1_b' 'B']

如果在测试数据上使用相同的编码器,您应该使用OneHotEncoder。更多信息在这里:https://***.com/a/56567037/7623492

【讨论】:

嗨,马克-谢谢。我很少使用 getdummies 作为各种来源,我对此提出了建议,并推荐 sklearn.ohe 用于“可扩展部署”。你怎么看?【参考方案2】:

例如,如果特定列具有类别 A、B、C 和 D,这将扩展为 4 列,A 为 0/1,B 为 0/1,依此类推。运行回归后,如果例如 A 和 B 被丢弃(系数为 0),则意味着 A 和 B 的信息在最终模型中没有用,而 C 和 D 的信息是。

如果我们再次拟合模型,仅使用 C、D 的二元列再次进行预测,则效果非常好,因为类别为 A、B 的样本不会被定义为非 C 或非 D。

所以这取决于做套索的目的是什么。如果是预测,也就是选择变量,重新拟合成一个线性模型(或者套索),那么传递numpy数组就可以了。

如果您想识别所谓的重要特征,您可能需要查看保留的内容并推断其含义。

【讨论】:

以上是关于OneHotEncoding 丢失了 Lasso 回归的列标识的主要内容,如果未能解决你的问题,请参考以下文章

OneHotEncoding 训练数据和测试数据之间的映射问题

在我的索引数据集上遇到 OneHotEncoding 错误

onehotencoding中的ValueError

如何在预测时从测试数据中处理onehotencoding后的类别不匹配?

为啥我在 Sklearn 管道中的 OneHotEncoding 后得到的列比预期的多?

lasso为啥每次结果不一样