在 Spark StringIndexer 中处理 NULL 值
Handling NULL values in Spark StringIndexer
我有一个包含一些分类字符串列的数据集,我想用双精度类型表示它们。我使用 StringIndexer 进行此转换并且它有效但是当我在另一个具有 NULL 值的数据集中尝试它时它给出 java.lang.NullPointerException
错误并且没有工作。
为了更好地理解这里是我的代码:
for(col <- cols){
out_name = col ++ "_"
var indexer = new StringIndexer().setInputCol(col).setOutputCol(out_name)
var indexed = indexer.fit(df).transform(df)
df = (indexed.withColumn(col, indexed(out_name))).drop(out_name)
}
那么如何用 StringIndexer 解决这个 NULL 数据问题呢?
或者是否有更好的解决方案将具有 NULL 值的字符串类型的分类数据转换为 double?
Spark >= 2.2
自 Spark 2.2 NULL
值可以用标准 handleInvalid
Param
:
处理
import org.apache.spark.ml.feature.StringIndexer
val df = Seq((0, "foo"), (1, "bar"), (2, null)).toDF("id", "label")
val indexer = new StringIndexer().setInputCol("label")
默认情况下(error
)会抛出异常:
indexer.fit(df).transform(df).show
org.apache.spark.SparkException: Failed to execute user defined function($anonfun: (string) => double)
at org.apache.spark.sql.catalyst.expressions.ScalaUDF.eval(ScalaUDF.scala:1066)
...
Caused by: org.apache.spark.SparkException: StringIndexer encountered NULL value. To handle or skip NULLS, try setting StringIndexer.handleInvalid.
at org.apache.spark.ml.feature.StringIndexerModel$$anonfun.apply(StringIndexer.scala:251)
...
但配置为 skip
indexer.setHandleInvalid("skip").fit(df).transform(df).show
+---+-----+---------------------------+
| id|label|strIdx_46a78166054c__output|
+---+-----+---------------------------+
| 0| a| 0.0|
| 1| b| 1.0|
+---+-----+---------------------------+
或keep
indexer.setHandleInvalid("keep").fit(df).transform(df).show
+---+-----+---------------------------+
| id|label|strIdx_46a78166054c__output|
+---+-----+---------------------------+
| 0| a| 0.0|
| 1| b| 1.0|
| 3| null| 2.0|
+---+-----+---------------------------+
Spark < 2.2
至于现在(Spark 1.6.1)这个问题还没有解决,但是有一个打开的 JIRA(SPARK-11569)。不幸的是,要找到可接受的行为并不容易。 SQL NULL 表示缺失/未知值,因此任何索引都毫无意义。
也许你能做的最好的事情就是使用 NA
actions 和 drop:
df.na.drop("column_to_be_indexed" :: Nil)
或填写:
df2.na.fill("__HEREBE_DRAGONS__", "column_to_be_indexed" :: Nil)
在使用索引器之前。
我有一个包含一些分类字符串列的数据集,我想用双精度类型表示它们。我使用 StringIndexer 进行此转换并且它有效但是当我在另一个具有 NULL 值的数据集中尝试它时它给出 java.lang.NullPointerException
错误并且没有工作。
为了更好地理解这里是我的代码:
for(col <- cols){
out_name = col ++ "_"
var indexer = new StringIndexer().setInputCol(col).setOutputCol(out_name)
var indexed = indexer.fit(df).transform(df)
df = (indexed.withColumn(col, indexed(out_name))).drop(out_name)
}
那么如何用 StringIndexer 解决这个 NULL 数据问题呢?
或者是否有更好的解决方案将具有 NULL 值的字符串类型的分类数据转换为 double?
Spark >= 2.2
自 Spark 2.2 NULL
值可以用标准 handleInvalid
Param
:
import org.apache.spark.ml.feature.StringIndexer
val df = Seq((0, "foo"), (1, "bar"), (2, null)).toDF("id", "label")
val indexer = new StringIndexer().setInputCol("label")
默认情况下(error
)会抛出异常:
indexer.fit(df).transform(df).show
org.apache.spark.SparkException: Failed to execute user defined function($anonfun: (string) => double)
at org.apache.spark.sql.catalyst.expressions.ScalaUDF.eval(ScalaUDF.scala:1066)
...
Caused by: org.apache.spark.SparkException: StringIndexer encountered NULL value. To handle or skip NULLS, try setting StringIndexer.handleInvalid.
at org.apache.spark.ml.feature.StringIndexerModel$$anonfun.apply(StringIndexer.scala:251)
...
但配置为 skip
indexer.setHandleInvalid("skip").fit(df).transform(df).show
+---+-----+---------------------------+
| id|label|strIdx_46a78166054c__output|
+---+-----+---------------------------+
| 0| a| 0.0|
| 1| b| 1.0|
+---+-----+---------------------------+
或keep
indexer.setHandleInvalid("keep").fit(df).transform(df).show
+---+-----+---------------------------+
| id|label|strIdx_46a78166054c__output|
+---+-----+---------------------------+
| 0| a| 0.0|
| 1| b| 1.0|
| 3| null| 2.0|
+---+-----+---------------------------+
Spark < 2.2
至于现在(Spark 1.6.1)这个问题还没有解决,但是有一个打开的 JIRA(SPARK-11569)。不幸的是,要找到可接受的行为并不容易。 SQL NULL 表示缺失/未知值,因此任何索引都毫无意义。
也许你能做的最好的事情就是使用 NA
actions 和 drop:
df.na.drop("column_to_be_indexed" :: Nil)
或填写:
df2.na.fill("__HEREBE_DRAGONS__", "column_to_be_indexed" :: Nil)
在使用索引器之前。