往往我们需要进行训练时,读取的特征是多种多样的,数值类型的变量可能只是其中的一部分(比如年龄),但是还会有一些其他类型的分类变量(比如性别,比如月份)。
而我们这里讨论的分类变量/特征是指任何特征类型,可分为两大类:
- 无序变量: 是指有两个或两个以上类别的变量,这些类别没有任何相关顺序。例如,如果将性别分为两组,即男性和女性,则可将其视为名义变量。
- 有序变量: 则有 “等级 “或类别,并有特定的顺序。例如,一个顺序分类变量可以是一个具有低、中、高三个不同等级的特征。顺序很重要。
计算机无法理解文本数据,因此我们需要将这些类别转换为数字。为了便于理解这里使用kaggle项目的一个数据index id bin_0 bin_1 bin_2 bin_3 bin_4 nom_0 nom_1 nom_2 nom_3 … nom_9 ord_0 ord_1 ord_2 ord_3 ord_4 ord_5 day month target 0 0 0 0 0 T Y Green Triangle Snake Finland … 2f4cb3d51 2 Grandmaster Cold h D kr 2 2 0 1 1 0 1 0 T Y Green Trapezoid Hamster Russia … f83c56c21 1 Grandmaster Hot a A bF 7 8 0 2 2 0 0 0 F Y Blue Trapezoid Lion Russia … ae6800dd0 1 Expert Lava Hot h R Jc 7 2 0 3 3 0 1 0 F Y Red Trapezoid Snake Canada … 8270f0d71 1 Grandmaster Boiling Hot i D kW 2 1 1 4 4 0 0 0 F N Red Trapezoid Lion Canada … b164b72a7 1 Grandmaster Freezing a R qP 7 8 0 这份输入数据中有 - 5个二元变量
- 10个无序变量
- 6个有序变量
- 2个循环变量
- 1个目标变量
编码
标签编码
让我们来看看数据集中的 ord_2 特征。它包括6个不同的类别: Cold、Hot、Lava Hot、Boiling Hot、Freezing 等。
计算机无法理解文本数据,因此我们需要将这些类别转换为数字。一个简单的方法是创建一个字典,将这些值映射为从 0 到 N-1 的数字,其中 N 是给定特征中类别的总数。
1 | # 映射字典 |
然后我们可以读取数据,并将这些类别转换为数字。
1 | import pandas as pd |
这种分类变量的编码方式被称为标签编码(Label Encoding)我们将每个类别编码为一个数字标签。
我们也可以使用 scikit-learn 中的 LabelEncoder 进行编码。
1 | import pandas as pd |
我们可以在许多基于树的模型中直接使用它:决策树、随机森林、XGBoost 、GBM、LightGBM等。
但是这种编码方式不能用于线性模型、支持向量机或神经网络,因为它们希望数据是标准化的。
二值化的稀疏矩阵
为了对分类数据的处理能适用于线性模型、支持向量机或神经网络。对于这些类型的模型,我们可以对数据进行二值化(binarize)处理。二值化不是二分类,我们可以通过特征拆解,将一个特征用多个特征表示,实现多分类。
1 | Freezing --> 0 --> 0 0 0 |
这只是将类别转换为数字,然后再转换为二值化表示。这样,我们就把一个特征分成了三个(在本例中)特征(或列)。如果我们有更多的类别,最终可能会分成更多的列。对应的特征 Feature 就可以由 Feature_0、Feature_1、Feature_2 表示。
| Feature | Feature_0 | Feature_1 | Feature_2 |
|---|---|---|---|
| Warm | 0 | 0 | 1 |
| Hot | 1 | 0 | 0 |
| Lava Hot | 1 | 0 | 1 |
| 由于我们只关注其中的非0值(对应特征为1 的值)所以将上述特征格式转换成稀疏矩阵会进一步减少内存使用。用 1 表示矩阵的一种方法是某种字典方法,其中键是行和列的索引,值是 1。 |
1 | (0, 2) 1 |
在大数据矩阵中,稀疏矩阵可以减少内存的效果会更加明显。
1 | import numpy as np |
因此,密集阵列需要 ~8000MB 或大约 8GB 内存。而稀疏阵列只占用 399MB 内存。当我们的特征中有越多零时,稀疏阵列对内存的降低效果越显著。
独热编码
二值化特征的稀疏表示比其密集表示所占用的内存要少得多,但对于分类变量来说,还有一种转换所占用的内存更少。这就是所谓的 “独热编码”。
独热编码也是一种二值编码,因为只有 0 和 1 两个值。但必须注意的是,它并不是二值表示法。我们可以通过下面的例子来理解它的表示法。
假设我们用一个向量来表示 ord_2 变量的每个类别。这个向量的大小与 ord_2 变量的类别数相同。在这种特定情况下,每个向量的大小都是 6,并且除了一个位置外,其他位置都是 0。让我们来看看这个特殊的向量表。
| Category | Fea_0 | Fea_1 | Fea_2 | Fea_3 | Fea_4 | Fea_5 |
|---|---|---|---|---|---|---|
| Freezing | 0 | 0 | 0 | 0 | 0 | 1 |
| Warm | 0 | 0 | 0 | 0 | 1 | 0 |
| Cold | 0 | 0 | 0 | 1 | 0 | 0 |
| Boiling Hot | 0 | 0 | 1 | 0 | 0 | 0 |
| Hot | 0 | 1 | 0 | 0 | 0 | 0 |
| Lava Hot | 1 | 0 | 0 | 0 | 0 | 0 |
| 使用热独编码相比二值化编码,在进行稀疏化后,可以更加节省内存,还是以之前的例子,我们表示 Warm、Hot、Lava Hot 这三个类别的稀疏表示如下: |
1 | (1, 4) 1 |
二值化中示例的更大的数据,我们来看看变化
1 | import numpy as np |
这里的密集阵列大小约为 8GB,稀疏阵列在二值化时是300MB,使用热独编码的稀疏矩阵只有 8MB。
罕见类
有时候
罕见类是指在数据集中出现次数少于一定阈值的类别。