为什么Spark的OneHotEncoder默认删除最后一个类别?

Cor*_*rey 11 machine-learning bigdata apache-spark pyspark one-hot-encoding

我想了解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|
+----+---+-----+
Run Code Online (Sandbox Code Playgroud)

默认情况下,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,[],[])|
+----+---+-----+-------------+
Run Code Online (Sandbox Code Playgroud)

当然,这种行为可以改变:

>>> 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])|
+----+---+-----+-------------+
Run Code Online (Sandbox Code Playgroud)

题::

  • 在什么情况下,默认行为是可取的?
  • 盲目打电话可能会忽视哪些问题setDropLast(False)
  • 作者对文档中的以下陈述的含义是什么?

默认情况下不包括最后一个类别(可通过dropLast配置),因为它使向量条目总和为1,因此线性相关.

Rom*_*uin 6

根据文档,它是保持列独立的:

一键编码器,将一类类别索引映射到一列二进制矢量,每行最多有一个单一的单值指示输入类别索引。例如,对于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

  • 哈哈,最懒惰,愿意写一些东西的要点。如果有人查找此答案,这里有更多信息。类别特征导致有效的拦截。如果您包括一个通用截距项,则最小化器可以在截距中添加例如0.5,在所有类别中添加-0.5,以获得相同的成本函数值。为避免这种退化,请删除拦截器并包括所有类别。 (3认同)