CountFrequencyEncoder#

计数编码和频率编码是两种分类编码技术,它们在Kaggle的数据科学竞赛中常用于数据预处理,即使它们的预测价值并不立即明显。

计数编码包括将分类特征的类别替换为其计数,这些计数是从训练集中估计的。例如,在变量颜色中,如果有10个观测值是蓝色,5个观测值是红色,那么蓝色将被替换为10,红色将被替换为5。

频率编码包括用分类数据的频率替换其标签,该频率也从训练集中估计。然后,在变量城市中,如果伦敦出现在10%的观察中,布里斯托尔出现在1%的观察中,伦敦将被替换为0.1,布里斯托尔将被替换为0.01。

机器学习中的计数和频率编码#

当我们认为数据集中类别的表示具有某种预测价值时,我们会使用计数编码或频率编码。老实说,我能想到的计数编码可能有用的唯一例子是在销售预测或销售数据分析场景中,其中产品的计数或项目的计数代表了其受欢迎程度。换句话说,我们可能更有可能销售一个计数高的产品。

计数编码和频率编码对于具有高基数的分类变量是合适的,因为这些类型的分类编码会导致所谓的碰撞:在相似数量的观察中出现的类别将被替换为相似的,如果不是相同的值,从而减少了变异性。

当然,这可能会导致将两个原本不同的类别放在同一个类别中,从而造成信息的丢失。但从另一方面来说,如果我们使用计数编码或频率编码,我们有理由相信计数或频率是预测性能的良好指标,或者以某种方式捕捉数据洞察,因此具有相似计数的类别会显示出相似的模式或行为。

使用 Feature-engine 进行计数和频率编码#

The CountFrequencyEncoder() 用训练集中每个类别出现的次数或百分比替换分类特征的类别。

通过 CountFrequencyEncoder() 我们可以自动编码数据集中的所有分类特征,或者仅编码其中的一部分,方法是在设置编码器时将变量名称以列表形式传递给 variables 参数。

默认情况下,CountFrequencyEncoder() 只会对分类数据进行编码。如果我们想要编码数值,我们需要通过将参数 ignore_format 设置为 True 来明确表示。

计数和频率编码与未见类别#

当我们学习从字符串到数字的映射时,无论是通过计数编码还是其他编码技术,如序数编码或目标编码,我们都是通过观察训练集中的类别来进行的。因此,我们不会有仅在测试集中出现的类别的映射。这些被称为“未见类别”。

当遇到未见过的类别时,CountFrequencyEncoder() 默认会忽略它们,这意味着未见过的类别将被替换为缺失值。我们可以指示编码器在遇到新类别时引发错误,或者选择将未见过的类别编码为零。

计数编码 vs 其他编码方法#

计数和频率编码,类似于序数编码,与独热编码、特征哈希或二进制编码相反,不会增加数据集的维度。从一个分类变量中,我们得到一个数值特征。

Python 示例#

让我们通过使用泰坦尼克号数据集来研究 CountFrequencyEncoder() 的功能。我们将首先加载库和函数,加载数据集,然后将其拆分为训练集和测试集。

from sklearn.model_selection import train_test_split
from feature_engine.datasets import load_titanic
from feature_engine.encoding import CountFrequencyEncoder

X, y = load_titanic(
    return_X_y_frame=True,
    handle_missing=True,
    predictors_only=True,
    cabin="letter_only",
)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=0,
)

print(X_train.head())

我们看到了包含预测变量的结果数据框如下:

      pclass     sex        age  sibsp  parch     fare cabin embarked
501        2  female  13.000000      0      1  19.5000     M        S
588        2  female   4.000000      1      1  23.0000     M        S
402        2  female  30.000000      1      0  13.8583     M        C
1193       3    male  29.881135      0      0   7.7250     M        Q
686        3  female  22.000000      0      0   7.7250     M        Q

该数据集有三个明显的分类特征:cabin(舱位)、embarked(登船港口)和 sex(性别),此外,pclass(乘客等级)也可以作为分类特征处理。

计数编码#

我们将首先使用计数来编码这三个分类变量,也就是说,用每个类别在训练数据集中出现的次数来替换字符串。

encoder = CountFrequencyEncoder(
encoding_method='count',
variables=['cabin', 'sex', 'embarked'],
)

encoder.fit(X_train)

通过 fit(),计数编码器学习每个类别的计数。我们可以按如下方式检查这些计数:

encoder.encoder_dict_

我们在以下输出中看到每个类别的计数,针对这三个变量中的每一个:

{'cabin': {'M': 702,
  'C': 71,
  'B': 42,
  'E': 32,
  'D': 32,
  'A': 17,
  'F': 15,
  'G': 4,
  'T': 1},
 'sex': {'male': 581, 'female': 335},
 'embarked': {'S': 652, 'C': 179, 'Q': 83, 'Missing': 2}}

现在,我们可以继续对变量进行编码:

train_t = encoder.transform(X_train)
test_t = encoder.transform(X_test)

print(train_t.head())

我们看到生成的数据框,其中分类特征现在被替换为与类别计数相对应的整数值:

      pclass  sex        age  sibsp  parch     fare  cabin  embarked
501        2  335  13.000000      0      1  19.5000    702       652
588        2  335   4.000000      1      1  23.0000    702       652
402        2  335  30.000000      1      0  13.8583    702       179
1193       3  581  29.881135      0      0   7.7250    702        83
686        3  335  22.000000      0      0   7.7250    702        83

我们现在可以使用编码后的数据帧来训练机器学习模型。

频率编码#

现在让我们执行频率编码。我们将对2个分类变量和1个数值变量进行编码,因此,我们需要设置编码器忽略变量的类型:

encoder = CountFrequencyEncoder(
encoding_method='frequency',
variables=['cabin', 'pclass', 'embarked'],
ignore_format=True,
)

现在,我们将频率编码器拟合到训练集并立即进行转换,然后我们对测试集进行转换:

t_train = encoder.fit_transform(X_train)
t_test = encoder.transform(X_test)

test.head()

在以下输出中,我们看到了转换后的数据框,其中分类特征现在被编码为其频率:

        pclass     sex        age  sibsp  parch     fare     cabin  embarked
1139  0.543668    male  38.000000      0      0   7.8958  0.766376   0.71179
533   0.205240  female  21.000000      0      1  21.0000  0.766376   0.71179
459   0.205240    male  42.000000      1      0  27.0000  0.766376   0.71179
1150  0.543668    male  29.881135      0      0  14.5000  0.766376   0.71179
393   0.205240    male  25.000000      0      0  31.5000  0.766376   0.71179

通过 fit(),编码器学习每个类别的频率,这些频率存储在其 encoder_dict_ 参数中。我们可以这样检查它们:

encoder.encoder_dict_

encoder_dict_ 中,我们找到了每个变量的每个唯一类别的频率,以便进行编码。这样,我们可以将原始值映射到新值。

{'cabin': {'M': 0.7663755458515283,
   'C': 0.07751091703056769,
   'B': 0.04585152838427948,
   'E': 0.034934497816593885,
   'D': 0.034934497816593885,
   'A': 0.018558951965065504,
   'F': 0.016375545851528384,
   'G': 0.004366812227074236,
   'T': 0.001091703056768559},
'pclass': {3: 0.5436681222707423,
   1: 0.25109170305676853,
   2: 0.2052401746724891},
'embarked': {'S': 0.7117903930131004,
   'C': 0.19541484716157206,
   'Q': 0.0906113537117904,
   'Missing': 0.002183406113537118}}

我们现在可以使用这些数据框来训练机器学习算法。

通过 inverse_transform 方法,我们可以将编码后的数据框转换回其原始表示形式,也就是说,我们可以用原始的分类值替换编码。

其他资源#

在下面的笔记本中,你可以找到更多关于 CountFrequencyEncoder() 功能的详细信息,以及带有编码变量的示例图:

有关此方法和其他特征工程方法的更多详细信息,请查看以下资源:

../../_images/feml.png

机器学习的特征工程#

../../_images/fetsf.png

时间序列预测的特征工程#











我们的书:

../../_images/cookbook.png

Python 特征工程手册#














我们的书籍和课程都适合初学者和更高级的数据科学家。通过购买它们,您正在支持 Feature-engine 的主要开发者 Sole。