kaggleIntermediateMachineLearningCategoricalVariables
在本教程中,您将了解什么是分类变量,以及处理此类数据的三种方法。
简介
分类变量仅接受有限数量的值。
- 假设有一项调查询问您多久吃一次早餐,并提供四个选项:“从不”、“很少”、“大多数日子”或“每天”。在这种情况下,数据是分类的,因为回复属于一组固定的类别。
- 如果人们回答了一项关于他们拥有什么品牌的汽车的调查,回复将分为“本田”、“丰田”和“福特”等类别。在这种情况下,数据也是分类的。
如果您尝试在未预先处理这些变量的情况下将其插入到大多数 Python 机器学习模型中,则会收到错误。在本教程中,我们将比较三种可用于准备分类数据的方法。
三种方法
1) 删除分类变量
处理分类变量最简单的方法是将其从数据集中移除。这种方法只有在列不包含有用信息的情况下才有效。
2) 序数编码
序数编码 将每个唯一值分配给不同的整数。

这种方法假设类别具有一定的顺序:“从不”(0) < “很少”(1) < “大多数日子”(2) < “每天”(3)。
此假设在本例中是合理的,因为类别的排序是毋庸置疑的。并非所有分类变量的值都有明确的顺序,但我们将这些有明确顺序的变量称为序数变量。对于基于树的模型(例如决策树和随机森林),序数编码可以很好地处理序数变量。
3) 独热编码
独热编码会创建新的列,指示原始数据中每个可能值的存在(或不存在)。为了理解这一点,我们将通过一个示例来说明。

在原始数据集中,“颜色”是一个包含三个类别的分类变量:“红色”、“黄色”和“绿色”。相应的独热编码为每个可能值对应一列,原始数据集中的每一行对应一行。如果原始值为“红色”,我们就在“红色”列中置 1;如果原始值为“黄色”,我们就在“黄色”列中置 1,以此类推。
与序数编码不同,独热编码不假设类别的顺序。因此,如果分类数据中没有明确的顺序(例如,“红色”既不比“黄色”多也不少),这种方法会特别有效。我们将没有内在排序的分类变量称为名义变量。
如果分类变量的取值数量较多(即,通常不会将其用于取值超过 15 个不同值的变量),独热编码通常效果不佳。
示例
与上一篇教程一样,我们将使用墨尔本住房数据集。
我们不会重点介绍数据加载步骤。您可以假设您已经拥有 X_train、X_valid、y_train 和 y_valid 中的训练和验证数据。
import pandas as pd |
我们将使用下面的 head() 方法预览训练数据。
X_train.head() |
| Type | Method | Regionname | Rooms | Distance | Postcode | Bedroom2 | Bathroom | Landsize | Lattitude | Longtitude | Propertycount | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 12167 | u | S | Southern Metropolitan | 1 | 5.0 | 3182.0 | 1.0 | 1.0 | 0.0 | -37.85984 | 144.9867 | 13240.0 |
| 6524 | h | SA | Western Metropolitan | 2 | 8.0 | 3016.0 | 2.0 | 2.0 | 193.0 | -37.85800 | 144.9005 | 6380.0 |
| 8413 | h | S | Western Metropolitan | 3 | 12.6 | 3020.0 | 3.0 | 1.0 | 555.0 | -37.79880 | 144.8220 | 3755.0 |
| 2919 | u | SP | Northern Metropolitan | 3 | 13.0 | 3046.0 | 3.0 | 1.0 | 265.0 | -37.70830 | 144.9158 | 8870.0 |
| 6043 | h | S | Western Metropolitan | 3 | 13.3 | 3020.0 | 3.0 | 1.0 | 673.0 | -37.76230 | 144.8272 | 4217.0 |
接下来,我们获取训练数据中所有分类变量的列表。
我们通过检查每列的数据类型(或dtype)来实现这一点。“object”dtype 表示该列包含文本(理论上也可能包含其他内容,但这对我们的目的而言并不重要)。对于此数据集,包含文本的列表示分类变量。
# Get list of categorical variables |
定义函数来衡量每种方法的质量
我们定义了一个函数 score_dataset() 来比较三种处理分类变量的不同方法。该函数报告随机森林模型的平均绝对误差 (MAE)。通常,我们希望 MAE 尽可能低!
from sklearn.ensemble import RandomForestRegressor |
方法 1 的得分(删除分类变量)
我们使用 select_dtypes() 方法删除 object 列。
drop_X_train = X_train.select_dtypes(exclude=['object']) |
方法 2(序数编码)的得分
Scikit-learn 有一个 OrdinalEncoder 类,可用于获取序数编码。我们循环遍历分类变量,并将序数编码器分别应用于每一列。
from sklearn.preprocessing import OrdinalEncoder |
在上面的代码单元中,我们将每一列的每个唯一值随机分配给一个不同的整数。这是一种比提供自定义标签更简单的常用方法;但是,如果我们为所有序数变量提供更合理的标签,则可以预期性能会进一步提升。
方法 3(独热编码)的得分
我们使用 scikit-learn 中的 OneHotEncoder 类来获取独热编码。您可以使用许多参数来自定义其行为。
- 我们设置
handle_unknown='ignore'以避免在验证数据包含训练数据中未表示的类时出现错误,并且 - 设置
sparse=False可确保编码后的列以 NumPy 数组(而不是稀疏矩阵)的形式返回。
要使用编码器,我们只需提供想要进行独热编码的分类列。例如,要对训练数据进行编码,我们需要提供 X_train[object_cols]。(下方代码单元中的 object_cols 是包含分类数据的列名列表,因此 X_train[object_cols] 包含训练集中的所有分类数据。)
from sklearn.preprocessing import OneHotEncoder |
哪种方法最佳?
在本例中,删除分类列(方法 1)的效果最差,因为它的 MAE 得分最高。至于其他两种方法,由于返回的 MAE 得分值非常接近,因此似乎没有哪一种方法比另一种方法更有优势。
通常情况下,独热编码(方法 3)通常效果最佳,而删除分类列(方法 1)通常效果最差,但具体情况会有所不同。
结论
世界上充满了分类数据。如果您知道如何使用这种常见的数据类型,您将成为一名更高效的数据科学家!
