Spark dataframe заменяет значения определенных столбцов в строке на Null - PullRequest
0 голосов
/ 29 августа 2018

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

//old_df is the existing Dataframe 
val key_cols = List("id", "key_number")
val non_key_cols = old_df.columns.toList.filterNot(key_cols.contains(_))

val key_col_df = old_df.select(key_cols.head, key_cols.tail:_*)
val non_key_cols_df = old_df.select(non_key_cols.head, non_key_cols.tail:_*)
val list_cols = List.fill(non_key_cols_df.columns.size)("NULL")
val rdd_list_cols = spark.sparkContext.parallelize(Seq(list_cols)).map(l => Row(l:_*))
val list_df = spark.createDataFrame(rdd_list_cols, non_key_cols_df.schema)

val new_df = key_col_df.crossJoin(list_df)

Этот подход был хорош, когда у меня есть только столбцы строкового типа в old_df. Но у меня есть несколько столбцов типа double и типа int, которые выдают ошибку, потому что rdd - это список пустых строк.

Чтобы избежать этого, я попробовал list_df как пустой фрейм данных со схемой как non_key_cols_df, но результат crossJoin - это пустой фрейм данных, который, как я считаю, состоит в том, что один фрейм данных пуст.

Мое требование состоит в том, чтобы non_key_cols представлял собой однострочный фрейм данных с Null, чтобы я мог сделать crossJoin с key_col_df и сформировать необходимый new_df.

Кроме того, любой другой более простой способ обновить все столбцы, кроме ключевых столбцов данных, до нуля, решит мою проблему. Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Ответ Shaido имеет небольшой недостаток - тип столбца будет потерян. Может быть исправлено с использованием схемы, например:

val nonKeyCols = df.schema.fields.filterNot(f => keyCols.contains(f.name))
val df2 = nonKeyCols.foldLeft(df)((df, c) => df.withColumn(c.name, lit(null).cast(c.dataType)))
0 голосов
/ 29 августа 2018

crossJoin - дорогостоящая операция, поэтому, если возможно, вы хотите ее избежать. Более простым решением было бы перебрать все неключевые столбцы и вставить ноль с lit(null). Используя foldLeft, это можно сделать следующим образом:

val keyCols = List("id", "key_number")
val nonKeyCols = df.columns.filterNot(keyCols.contains(_))

val df2 = nonKeyCols.foldLeft(df)((df, c) => df.withColumn(c, lit(null)))

Пример ввода:

+---+----------+---+----+
| id|key_number|  c|   d|
+---+----------+---+----+
|  1|         2|  3| 4.0|
|  5|         6|  7| 8.0|
|  9|        10| 11|12.0|
+---+----------+---+----+

даст:

+---+----------+----+----+
| id|key_number|   c|   d|
+---+----------+----+----+
|  1|         2|null|null|
|  5|         6|null|null|
|  9|        10|null|null|
+---+----------+----+----+
...