具有多个条目的分类变量转换为实体嵌入

数据挖掘 机器学习 xgboost 词嵌入 分类数据 嵌入
2022-02-19 18:06:04

我有大量(数万)类别的结构化数据,这些类别被组织成列。目标是将数据输入梯度提升机算法以进行特定预测。

一些列对同一个样本有多个条目,即,列 1 的样本 1 具有第 1 行的条目 1 和第 2 行的条目 2。这是一个例子:

df = pd.DataFrame({'pat': [1, 2, 3, 3, 3, 3], 'diag_type': ['D', 'OP', 'D', 'D', 'D', 'OP'],
                  'diag': ['D_1', 'OP_1', 'D_1', 'D_3', 'D_4', 'OP_2']})

    pat     diag_type   diag
0   1   D   D_1
1   2   OP  OP_1
2   3   D   D_1
3   3   D   D_3
4   3   D   D_4
5   3   OP  OP_2

由于我有这么多类别,我需要进行一些重组,我认为实体嵌入是最好的方法。但是,我还没有找到重组数据框的好方法。我考虑过进行某种虚拟编码,如this stackoverflow post中所示,例如:

d.get_dummies(df.set_index('pat')).sum(level=0)
    diag_type_D     diag_type_OP    diag_D_1    diag_D_3    diag_D_4    diag_OP_1   diag_OP_2
pat                             
1   1   0   1   0   0   0   0
2   0   1   0   0   0   1   0
3   3   1   1   1   1   0   1

但后来我仍然得到很多稀疏,这需要很长时间。有更好的方法吗?

3个回答

您为什么不尝试使用不同类型的编码?

当您具有高基数时,最典型的编码之一是目标编码。你可以在这个库中找到一个实现您可以在此处找到有关它是什么以及何时应用它的说明

如果每个分类列的基数(不同类别的数量)非常低,则应仅使用虚拟编码(也称为 one-hot-encoding)。否则,您最终将拥有太多列。我建议您检查每列的基数。如果基数很小(与数据集的行数相比),您可以进行 one-hot-encoding。如果某个列的基数很大,您必须为该列找到不同的编码,例如目标统计信息。

但是,我建议尝试使用 library catboost它是一个梯度提升库,自然可以很好地处理分类列(它为您选择编码)。它非常易于使用,如下所示:

from catboost import CatBoostRegressor
from catboost import Pool

train_data = Pool(X_train, y_train, cat_features = categorical_features)
eval_data=  Pool(X_eval, y_eval,  cat_features = categorical_features)
test_data =  Pool(X_test, y_test,  cat_features = categorical_features)

# Initialize CatBoostRegressor
model = CatBoostRegressor()
# Fit model
model.fit(train_data, eval_set = eval_data)
# Get predictions
preds = model.predict(test_data)

这里categorical_features是数据的所有分类特征的列名列表。确保还包括看似数字的列,但相邻的观测值没有语义关系。例如,包含 ID 值的列具有数值数据类型,但具有相似 ID 的两个对象通常并不意味着它们共享某些属性。因此,此 ID 列也应该像分类列一样编码。

如果您进行分类,还有一个分类器。

关于您对具有相同类别的多行的评论:

想象一下,您有一个水果数据库。一列包含名称:“Apple”、“Banana”、“Lemon”……另一列包含颜色:“red”、“yellow”、“yellow”……名称列对于模型来说毫无用处,没有什么可以概括的。每种水果的名字都不一样。但是,模型可能会使用颜色,因为在预测训练数据中没有的水果的属性时,它可能与训练数据中的某些水果具有相同的颜色。但它永远不会有相同的名称。

您还可以使用带有嵌入层的简单前馈 NN 来处理这些高基数特征

使用LabelEncoderor the OrdinalEncoderfrom sklearnorcategory-encoders包。您可以将编码值直接输入到Embedding图层中。