web-dev-qa-db-ja.com

Spark DataFrameでnull値を空の配列に変換します

Spark 1つの列が整数の配列であるデータフレームがあります。左外部結合から来ているため、列はnull可能です。すべてのnull値を空の配列に変換したいので、後でnullを処理する必要はありません。

私はそうすることができると思った:

val myCol = df("myCol")
df.withColumn( "myCol", when(myCol.isNull, Array[Int]()).otherwise(myCol) )

ただし、これにより次の例外が発生します。

Java.lang.RuntimeException: Unsupported literal type class [I [I@5ed25612
at org.Apache.spark.sql.catalyst.expressions.Literal$.apply(literals.scala:49)
at org.Apache.spark.sql.functions$.lit(functions.scala:89)
at org.Apache.spark.sql.functions$.when(functions.scala:778)

どうやら配列型はwhen関数でサポートされていません。 null値を変換する他の簡単な方法はありますか?

該当する場合、この列のスキーマは次のとおりです。

|-- myCol: array (nullable = true)
|    |-- element: integer (containsNull = false)
16
Daniel Siegmann

UDFを使用できます。

import org.Apache.spark.sql.functions.udf

val array_ = udf(() => Array.empty[Int])

WHENまたはCOALESCEと組み合わせる:

df.withColumn("myCol", when(myCol.isNull, array_()).otherwise(myCol))
df.withColumn("myCol", coalesce(myCol, array_())).show

最近のバージョンでは、array関数を使用できます。

import org.Apache.spark.sql.functions.{array, lit}

df.withColumn("foo", array().cast("array<integer>"))

stringから目的の型への変換が許可されている場合にのみ機能することに注意してください。

17
zero323

Zero323のアプローチに若干の変更を加えることで、Spark 2.3.1。

val df = Seq("a" -> Array(1,2,3), "b" -> null, "c" -> Array(7,8,9)).toDF("id","numbers")
df.show
+---+---------+
| id|  numbers|
+---+---------+
|  a|[1, 2, 3]|
|  b|     null|
|  c|[7, 8, 9]|
+---+---------+

val df2 = df.withColumn("numbers", coalesce($"numbers", array()))
df2.show
+---+---------+
| id|  numbers|
+---+---------+
|  a|[1, 2, 3]|
|  b|       []|
|  c|[7, 8, 9]|
+---+---------+
5
Jeremy

配列要素を入れたいデータ型がStringTypeからキャストできない場合に使用するUDFフリーの代替は次のとおりです。

_import pyspark.sql.types as T
import pyspark.sql.functions as F

df.withColumn(
    "myCol",
    F.coalesce(
        F.col("myCol"),
        F.from_json(F.lit("[]"), T.ArrayType(T.IntegerType()))
    )
)
_

IntegerType()は、複雑なデータ型のデータ型に置き換えることができます。

2
harppu