我想了解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,因此线性相关。
根据文档,这是为了保持列的独立性:
https://spark.apache.org/docs/1.5.2/api/java/org/apache/spark/ml/feature/OneHotEncoder.html将类别索引的列映射到另一列的单热编码器对于二进制向量,每行最多有一个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,它保存了所有类别。输出向量是稀疏。