在尝试使用pyspark的OneHotEncoder
(https://spark.apache.org/docs/2.1.0/ml-features.html#onehotencoder)为分类特征生成一热编码矢量时看到一个奇怪的问题,其中一热矢量似乎缺少某些类别(或者可能格式奇怪)显示时?)。
现在回答了这个问题(或提供了 答案)后,下面的详细信息似乎与理解问题并不完全相关
具有以下形式的数据集
1. Wife's age (numerical)
2. Wife's education (categorical) 1=low, 2, 3, 4=high
3. Husband's education (categorical) 1=low, 2, 3, 4=high
4. Number of children ever born (numerical)
5. Wife's religion (binary) 0=Non-Islam, 1=Islam
6. Wife's now working? (binary) 0=Yes, 1=No
7. Husband's occupation (categorical) 1, 2, 3, 4
8. Standard-of-living index (categorical) 1=low, 2, 3, 4=high
9. Media exposure (binary) 0=Good, 1=Not good
10. Contraceptive method used (class attribute) 1=No-use, 2=Long-term, 3=Short-term
实际数据类似于
wife_age,wife_edu,husband_edu,num_children,wife_religion,wife_working,husband_occupation,SoL_index,media_exposure,contraceptive
24,2,3,3,1,1,2,3,0,1
45,1,3,10,1,1,3,4,0,1
来源:https://archive.ics.uci.edu/ml/datasets/Contraceptive+Method+Choice。
在对数据进行了其他一些预处理之后,然后尝试通过...将分类和二进制(仅出于实践目的)特征编码为1hot向量。
for inds in ['wife_edu', 'husband_edu', 'husband_occupation', 'SoL_index', 'wife_religion', 'wife_working', 'media_exposure', 'contraceptive']:
encoder = OneHotEncoder(inputCol=inds, outputCol='%s_1hot' % inds)
print encoder.k
dataset = encoder.transform(dataset)
产生的行看起来像
Row(
....,
numeric_features=DenseVector([24.0, 3.0]), numeric_features_normalized=DenseVector([-1.0378, -0.1108]),
wife_edu_1hot=SparseVector(4, {2: 1.0}),
husband_edu_1hot=SparseVector(4, {3: 1.0}),
husband_occupation_1hot=SparseVector(4, {2: 1.0}),
SoL_index_1hot=SparseVector(4, {3: 1.0}),
wife_religion_1hot=SparseVector(1, {0: 1.0}),
wife_working_1hot=SparseVector(1, {0: 1.0}),
media_exposure_1hot=SparseVector(1, {0: 1.0}),
contraceptive_1hot=SparseVector(2, {0: 1.0})
)
我对稀疏矢量格式的理解是SparseVector(S, {i1: v1}, {i2: v2}, ..., {in: vn})
表示一个长度为S的矢量,其中所有值都是0,期望索引i1,...具有对应的值v1,...,vn({ {3}})。
基于此,看来在 this 情况下的SparseVector实际上表示矢量中的最高索引(而不是大小)。此外,结合所有功能(通过pyspark的VectorAssembler
)并检查所得dataset.head(n=1)
向量的数组版本是否显示
input_features=SparseVector(23, {0: -1.0378, 1: -0.1108, 4: 1.0, 9: 1.0, 12: 1.0, 17: 1.0, 18: 1.0, 19: 1.0, 20: 1.0, 21: 1.0})
indicates a vector looking like
indices: 0 1 2 3 4... 9 12 17 18 19 20 21
[-1.0378, -0.1108, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0]
我认为应该不可能有一个大于等于3个连续1s的序列(如在上述向量的尾部附近可以看到的那样),因为这将表明一个热门向量(例如中间向量) 1)的大小仅为1,对于任何数据功能都没有意义。
对于机器学习的东西来说是新手,所以这里可能对一些基本概念感到困惑,但是有人知道这里会发生什么吗?
答案 0 :(得分:0)
在pyspark文档(https://spark.apache.org/docs/2.1.0/api/python/pyspark.ml.html#pyspark.ml.feature.OneHotEncoder)中发现了这一点:
...具有5个类别,输入值2.0将映射到[0.0,0.0,1.0,0.0]的输出向量。 默认情况下不包括最后一个类别(可通过dropLast进行配置),因为它使向量项的总和为1,因此线性相关。因此输入值4.0映射为[0.0,0.0,0.0,0.0]。
可以在此处(http://www.algosome.com/articles/dummy-variable-trap-regression.html和此处(https://stats.stackexchange.com/q/290526/167299)中找到有关为什么要进行最后一类丢弃的更多讨论。
我对任何类型的机器学习都是相当陌生的,但基本上(对于回归模型而言)删除最后一个分类值是为了避免发生称为dummy variable trap
的事情,其中“自变量是多重共线性的,在这种情况下,两个或多个变量高度相关;简单来说,一个变量可以从其他变量中预测出来”(因此,基本上,您将具有冗余功能(我认为这对加权a不利。 ML模型))。
例如。当[isBoy, isGirl, unspecified]
的编码可以传达有关某人性别的相同信息时,则不需要[isBoy, isGirl]
的1hot编码,此处为[1,0]=isBoy
,[0,1]=isGirl
和[0,0]=unspecified
。
此链接(http://www.algosome.com/articles/dummy-variable-trap-regression.html)提供了一个很好的例子,结论是
伪变量陷阱的解决方案是删除分类变量之一(或者删除截距常量)-如果存在m个类别,则在模型中使用m-1,则可以忽略掉值被认为是参考值,其余类别的拟合值表示此参考的更改。
**注意:在寻找原始问题的答案时,找到了类似的SO帖子(Why does Spark's OneHotEncoder drop the last category by default?)。但是,我认为,由于提到的帖子是关于为什么的行为,而本帖子即将与最初发生的事情相混淆,因此当前的帖子值得存在>,以及当前的问题标题在粘贴到Google时找不到所提到的帖子的事实。