Преобразование строк данных в Scala с большим количеством столбцов - PullRequest
0 голосов
/ 08 февраля 2019

Я хотел бы изменить значение нескольких полей в строке кадра данных df.Обычно я делаю преобразование строки в строку, используя карту.Что-то вроде:

+---+---------+
|num|name     |
+---+---------+
|  1|Hydrogen |
|  2|Helium   |
+---+---------+
df.map(row=>{
      val name = row.getAs("name").toString.toUpperCase
      (row(0),name)
    })

Но теперь у меня есть кадр данных, который имеет очень сложную схему из многих столбцов, из которых я хотел бы изменить значение только некоторых столбцов.Изменение значения одного столбца зависит от других столбцов.Как я могу избежать записи всех значений столбцов (например, row.get(0), row.get(1) ... row.get(30)) в кортеже, а записывать только те, которые изменились?Рассмотрим df с этой схемой:

case class DFSchema(id: String, name: String, map1: Map[String, String], ... , map30[Sting, String])

Я хочу обновить ключи и значения df.select("map30") и изменить "name", только если id равно "city".Конечно, существует больше таких преобразований, которые нужно сделать в других столбцах (представленных в схеме как mapX.

. Я не рассматривал использование UDF для этой проблемы, даже если UDF возвращает структуру из многих столбцов,Я не знаю, как изменить несколько столбцов, используя withColumn(), так как он принимает только одно имя столбца. Однако решения, использующие UDF, одинаково приветствуются, так как они используют .map над строками.

Ответы [ 2 ]

0 голосов
/ 09 февраля 2019

Вы можете попробовать это:

   df.show(false)

    val newColumns = df.columns.map { x =>
      if (x == "name") {
        when(col("id") === "city", lit("miami")).otherwise(col("name")).as("name")
      } else if (x == "map30") {
        when(col("id") === "city", map(lit("h"), lit("update"), lit("n"), lit("new"))).otherwise(col("map30")).as("map30")
      } else {
        col(x).as(x)
      }
    }

    val cleanDf = df.select(newColumns: _*)

    cleanDf.show(false)
0 голосов
/ 08 февраля 2019

Вы можете попробовать что-то вроде этого:

val rules = Seq(
  "columnA" -> lit(20),
  "columnB" -> col("columnB").plus(col("columnC")),
  "columnC" -> col("columnC").minus(col("columnD")),
  "columnN" -> col("columnA").plus(col("columnB")).plus(col("columnC"))
)

def (inputDf: DataFrame): DataFrame = {
  rules.foldLeft(inputDf) {
    case (df, (columnName, ruleColumn)) => df.withColumn(columnName, ruleColumn)
  }
}

Здесь у нас есть rules, который представляет собой последовательность пар, где первое значение - это имя целевого столбца, который мы хотим изменить / добавить, иВторое - это правило, которое должно применяться с использованием зависимых столбцов.

Используя операцию foldLeft, мы применяем все правила ко входу DataFrame.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...