Spark / scala - можем ли мы создать новые столбцы из существующего значения столбца в кадре данных - PullRequest
0 голосов
/ 04 мая 2018

Я пытаюсь увидеть, сможем ли мы создать новые столбцы из значения в одном из столбцов в фрейме данных, используя spark / scala. У меня есть датафрейм со следующими данными

df.show()

+---+-----------------------+
|id |allvals                |
+---+-----------------------+
|1  |col1,val11|col3,val31  |
|3  |col3,val33|col1,val13  |
|2  |col2,val22             |
+---+-----------------------+

В приведенных выше данных col1 / col2 / col3 - имена столбцов, за которыми следует их значение. Имя и значение столбца разделяются ,. Каждый набор отделяется |.

Теперь я хочу добиться вот так

+---+----------------------+------+------+------+
|id |allvals               |col1  |col2  |col3  |
+---+----------------------+------+------+------+
|1  |col1,val11|col3,val31 |val11 |null  |val31 |
|3  |col3,val33|col1,val13 |val13 |null  |val13 |
|2  |col2,val22            |null  |val22 |null  |
+---+----------------------+------+------+------+

Ценю любую помощь.

Ответы [ 2 ]

0 голосов
/ 05 мая 2018

Вы можете преобразовать DataFrame, используя split, explode и groupBy/pivot/agg, следующим образом:

val df = Seq(
  (1, "col1,val11|col3,val31"),
  (2, "col3,val33|col1,val13"),
  (3, "col2,val22")
).toDF("id", "allvals")

import org.apache.spark.sql.functions._

df.withColumn("temp", split($"allvals", "\\|")).
  withColumn("temp", explode($"temp")).
  withColumn("temp", split($"temp", ",")).
  select($"id", $"allvals", $"temp".getItem(0).as("k"), $"temp".getItem(1).as("v")).
  groupBy($"id", $"allvals").pivot("k").agg(first($"v"))

// +---+---------------------+-----+-----+-----+
// |id |allvals              |col1 |col2 |col3 |
// +---+---------------------+-----+-----+-----+
// |1  |col1,val11|col3,val31|val11|null |val31|
// |3  |col2,val22           |null |val22|null |
// |2  |col3,val33|col1,val13|val13|null |val33|
// +---+---------------------+-----+-----+-----+
0 голосов
/ 04 мая 2018

Вы можете преобразовать столбец в Map с помощью udf:

import org.apache.spark.sql.functions._
import spark.implicits._

val df = Seq(
  (1, "col1,val11|col3,val31"), (2, "col3,val33|col3,val13"), (2, "col2,val22")
).toDF("id", "allvals")

val to_map = udf((s: String) => s.split('|').collect { _.split(",") match {
  case Array(k, v) => (k, v)
}}.toMap )

val dfWithMap = df.withColumn("allvalsmap", to_map($"allvals"))
val keys = dfWithMap.select($"allvalsmap").as[Map[String, String]].flatMap(_.keys.toSeq).distinct.collect

keys.foldLeft(dfWithMap)((df, k) => df.withColumn(k, $"allvalsmap".getItem(k))).drop("allvalsmap").show
// +---+--------------------+-----+-----+-----+
// | id|             allvals| col3| col1| col2|
// +---+--------------------+-----+-----+-----+
// |  1|col1,val11|col3,v...|val31|val11| null|
// |  2|col3,val33|col3,v...|val13| null| null|
// |  2|          col2,val22| null| null|val22|
// +---+--------------------+-----+-----+-----+

Вдохновлен этим ответом user6910411 .

...