3.4 分类变量编码
1. 背景知识
在统计学中,分类变量是指具有有限的、通常是固定数量值的变量,其变量值是定性的,表现为互不相容的类别或属性。若按每个分类变量值分组,则每个被观察的数据点或记录属于某一特定组。在计算机科学和一些数学分支中,分类变量被称为枚举类型。有时将分类变量的每一个可能值称为级别,与随机分类变量相关的概率分布称为分类分布。
回归分析时需要特别注意分类变量。与双值或连续变量不同,分类变量不能直接代入回归方程。例如,假设有一个名为race的变量,其编码为1=Hispanic、2=Asian、3=Black、4=White,那么在回归中直接代入race变量的数字值,将会得出线性效果,但这并不是分类本来的意义。因此,像这样的分类变量需要被编码成一系列指示变量,然后就可以将指示值输入到回归模型中。从数据库的角度来看,所谓分类变量编码,简单说就是为分类列的每个值创建一个新的分类编码列,然后将数据的类别指示值(通常就是0或1)赋给各个分类编码列。有多种编码系统用于分类编码,常见的包括one-hot、dummy、effects、orthogonal和Helmert等。MADlib当前支持one-hot和dummy编码技术。
•当需要用一组特定的预测变量与其他预测变量组做比较时,通常使用哑编码(dummy coding),与之比较的变量组称为参照组。
•one-hot编码与哑编码类似,两者的区别是前者为每种分类值建立数字类型的0/1指示列。在每行数据中(对应一个数据点)只有一个分类编码列的值可以为1。one-hot编码中没有参考类别。
2. 函数语法
3. 参数说明
encode_categorical_variables函数的参数说明如表3-6所示。
表3-6 encode_categorical_variables函数参数说明
(续表)
(续表)
4. 示例
(1)使用鲍鱼数据集的子集。
鲍鱼数据集(Abalone Dataset,参见https://archive.ics.uci.edu/ml/datasets/Abalone)是一个机器学习应用标准数据集,涉及根据鲍鱼个体的测量数据来预测鲍鱼的年龄(环的数量)。这是一个多分类(multi-class classification)问题,但也可以抽象为回归问题。该数据集有4177个观察值、8个输入变量和1个输出变量,每个类的观察值数量不均等。变量名包括性别(M, F, I)、长度、直径、高度、总重量、剥壳重量、内脏重量、壳重、环的数量。
drop table if exists abalone; create table abalone ( id serial, sex character varying, length double precision, diameter double precision, height double precision, rings int ); insert into abalone (sex, length, diameter, height, rings) values ('m', 0.455, 0.365, 0.095, 15), ('m', 0.35, 0.265, 0.09, 7), ('f', 0.53, 0.42, 0.135, 9), ('m', 0.44, 0.365, 0.125, 10), ('i', 0.33, 0.255, 0.08, 7), ('i', 0.425, 0.3, 0.095, 8), ('f', 0.53, 0.415, 0.15, 20), ('f', 0.545, 0.425, 0.125, 16), ('m', 0.475, 0.37, 0.125, 9), (null, 0.55, 0.44, 0.15, 19), ('f', 0.525, 0.38, 0.14, 14), ('m', 0.43, 0.35, 0.11, 10), ('m', 0.49, 0.38, 0.135, 11), ('f', 0.535, 0.405, 0.145, 10), ('f', 0.47, 0.355, 0.1, 10), ('m', 0.5, 0.4, 0.13, 12), ('i', 0.355, 0.28, 0.085, 7), ('f', 0.44, 0.34, 0.1, 10), ('m', 0.365, 0.295, 0.08, 7), (null, 0.45, 0.32, 0.1, 9);
(2)使用one-hot编码创建新表,通过对‘sex’列编码,替换‘f’‘m’和‘i’三个值,默认不对NULL编码。
结果:
(3)包含NULL值的one-hot编码,注意新增的‘sex_NULL’列。
结果:
(4)对源表中的所有列编码,并且指定‘id’列作为主键列,使得输出表中只包含主键和分类编码列。
结果:
源表有id、sex、length、diameter、height、rings六列,由于指定了id列为索引列,因此id列不被编码;length、diameter、height这三列是double precision类型,而编码只针对布尔、整数和文本数据类型,因此这三列也不被编码,对剩下的sex列的3个值、rings列的11个值进行编码,结果表共有包含id在内的15列。
(5)只对top n的分类值编码,把其他值分组到另一个杂项列中。top值或针对所有编码列,或按列指定。作为后者的一个例子,这里对‘sex’的值指定top 2、对‘rings’的值指定top 50%。
结果:
可以看到,结果表中对sex列的‘m’和‘f’两个值创建了编码列,其他值创建了一个杂项编码列;同样对rings列的10、7、9三个值创建了编码列,其他值创建了一个杂项编码列。
下面验证一下占前两位的sex值是‘m’和‘f’:
再验证一下rings取值占总记录数50%的值为10、7、9:
(6)如果希望在输出结果表里同时看到原始分类及其编码,可以在index参数中包含分类变量列。正如前面所讲,如果‘categorical_cols’参数值为‘*’,那么这种方法不可行,因为此情况下‘row_id’参数中指定的列根本就不会被编码。
结果:
(7)对于哑编码方式,我们将‘sex’中的‘i’值作为参考值,这里使用了‘value_to_drop’参数。
结果:
结果表中只有三列,分别是id列和sex值为‘m’‘f’的两个编码列。id为5、6、17的三行,编码的两列值都是0,因为这三行的sex值为‘i’,id为10、20的两行编码的两列值也都是0,因为这两行的sex值为空。
(8)为源表中的两个分类变量创建输出数组。
结果:
对比(4)的结果,这里用(4)的结果列构成了结果数组,注意结果数组元素的排列顺序,先按分类列的出现顺序sex、rings排序,再按sex、rings两列分类值的升序顺序。
查看带有数组元素索引的字典表。
(9)创建输出字典表。
结果:
查看字典表,该表定义输出表中的数字编码列。
(10)选择数据分布策略,例如随机分布。
查看输出表的数据分布策略。
(11)如果需要对FLOAT数据类型的变量进行编码,可以在函数调用中按以下方式进行显式数据类型转换。
结果: