我想了解Spark的OneHotEncoder默认丢弃最后一个类别的原因。
例如:
>>> fd = spark.createDataFrame( [(1.0, "a"), (1.5, "a"), (10.0, "b"), (3.2, "c")], ["x","c"])>>> ss = StringIndexer(inputCol="c",outputCol="c_idx")>>> ff = ss.fit(fd).transform(fd)>>> ff.show()+----+---+-----+| x| c|c_idx|+----+---+-----+| 1.0| a| 0.0|| 1.5| a| 0.0||10.0| b| 1.0|| 3.2| c| 2.0|+----+---+-----+
默认情况下,OneHotEncoder会丢弃最后一个类别:
>>> oe = OneHotEncoder(inputCol="c_idx",outputCol="c_idx_vec")>>> fe = oe.transform(ff)>>> fe.show()+----+---+-----+-------------+| x| c|c_idx| c_idx_vec|+----+---+-----+-------------+| 1.0| a| 0.0|(2,[0],[1.0])|| 1.5| a| 0.0|(2,[0],[1.0])||10.0| b| 1.0|(2,[1],[1.0])|| 3.2| c| 2.0| (2,[],[])|+----+---+-----+-------------+
当然,这种行为是可以改变的:
>>> oe.setDropLast(False)>>> fl = oe.transform(ff)>>> fl.show()+----+---+-----+-------------+| x| c|c_idx| c_idx_vec|+----+---+-----+-------------+| 1.0| a| 0.0|(3,[0],[1.0])|| 1.5| a| 0.0|(3,[0],[1.0])||10.0| b| 1.0|(3,[1],[1.0])|| 3.2| c| 2.0|(3,[2],[1.0])|+----+---+-----+-------------+
问题:
- 在什么情况下默认行为是可取的?
- 盲目调用
setDropLast(False)
可能会忽略哪些问题? - 作者在文档中提到的以下陈述是什么意思?
默认情况下不包括最后一个类别(可以通过dropLast配置),因为这样可以使向量条目之和为1,从而线性相关。
回答:
根据文档,这是为了保持列的独立性:
一个一热编码器,将一列类别索引映射到一列二进制向量,每行最多只有一个值为1,表示输入类别索引。例如,对于5个类别,输入值2.0将映射到输出向量[0.0, 0.0, 1.0, 0.0]。默认情况下不包括最后一个类别(可以通过OneHotEncoder!.dropLast配置),因为这样可以使向量条目之和为1,从而线性相关。因此,输入值4.0映射到[0.0, 0.0, 0.0, 0.0]。请注意,这与scikit-learn的OneHotEncoder不同,后者保留所有类别。输出向量是稀疏的。
https://spark.apache.org/docs/1.5.2/api/java/org/apache/spark/ml/feature/OneHotEncoder.html