it-roy-ru.com

Удалить все записи, которые дублируются в кадре данных spark

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

Я попытался использовать dropDuplicates(col_name), но он будет отбрасывать только повторяющиеся записи, но сохранит одну запись в кадре данных. Что мне нужно, это удалить все записи, которые изначально содержали повторяющиеся записи. 

Я использую Spark 1.6 и Scala 2.10.

3
salmanbw

Я бы использовал оконные функции для этого. Допустим, вы хотите удалить повторяющиеся строки id:

import org.Apache.spark.sql.expressions.Window

df
  .withColumn("cnt", count("*").over(Window.partitionBy($"id")))
  .where($"cnt"===1).drop($"cnt")
  .show()
5
Raphael Roth

Это можно сделать, сгруппировав по столбцу (или столбцам), чтобы найти дубликаты, а затем агрегировать и фильтровать результаты.

Пример кадра данных df:

+---+---+
| id|num|
+---+---+
|  1|  1|
|  2|  2|
|  3|  3|
|  4|  4|
|  4|  5|
+---+---+

Группировка по столбцу id для удаления его дубликатов (последние две строки):

val df2 = df.groupBy("id")
  .agg(first($"num").as("num"), count($"id").as("count"))
  .filter($"count" === 1)
  .select("id", "num")

Это даст вам:

+---+---+
| id|num|
+---+---+
|  1|  1|
|  2|  2|
|  3|  3|
+---+---+

Альтернативно, это можно сделать с помощью join. Это будет медленнее, но если столбцов много, нет необходимости использовать first($"num").as("num") для каждого из них, чтобы сохранить их.

val df2 = df.groupBy("id").agg(count($"id").as("count")).filter($"count" === 1).select("id")
val df3 = df.join(df2, Seq("id"), "inner")
2
Shaido

Я добавил метод killDuplicates() в библиотеку с открытым исходным кодом spark-daria , которая использует решение @Raphael Roth. Вот как использовать код:

import com.github.mrpowers.spark.daria.sql.DataFrameExt._

df.killDuplicates(col("id"))

// you can also supply multiple Column arguments
df.killDuplicates(col("id"), col("another_column"))

Вот реализация кода:

object DataFrameExt {

  implicit class DataFrameMethods(df: DataFrame) {

    def killDuplicates(cols: Column*): DataFrame = {
      df
        .withColumn(
          "my_super_secret_count",
          count("*").over(Window.partitionBy(cols: _*))
        )
        .where(col("my_super_secret_count") === 1)
        .drop(col("my_super_secret_count"))
    }

  }

}

Возможно, вы захотите использовать библиотеку spark-daria, чтобы сохранить эту логику вне вашей кодовой базы.

0
Powers