Scala 删除spark数据框中重复的所有记录
我有一个spark数据框,里面有多列。我想找出并删除列中具有重复值的行(其他列可能不同) 我尝试使用Scala 删除spark数据框中重复的所有记录,scala,apache-spark,duplicates,apache-spark-sql,spark-dataframe,Scala,Apache Spark,Duplicates,Apache Spark Sql,Spark Dataframe,我有一个spark数据框,里面有多列。我想找出并删除列中具有重复值的行(其他列可能不同) 我尝试使用dropDuplicates(col\u name)但它只会删除重复的条目,但仍会在数据帧中保留一条记录。我需要的是删除最初包含重复条目的所有条目 我使用的是Spark 1.6和Scala 2.10。这可以通过按列分组来完成,以在中查找重复项,然后聚合并过滤结果 示例数据帧df: +---+---+ | id|num| +---+---+ | 1| 1| | 2| 2| | 3| 3|
dropDuplicates(col\u name)
但它只会删除重复的条目,但仍会在数据帧中保留一条记录。我需要的是删除最初包含重复条目的所有条目
我使用的是Spark 1.6和Scala 2.10。这可以通过按列分组来完成,以在中查找重复项,然后聚合并过滤结果 示例数据帧
df
:
+---+---+
| id|num|
+---+---+
| 1| 1|
| 2| 2|
| 3| 3|
| 4| 4|
| 4| 5|
+---+---+
按id
列分组以删除重复项(最后两行):
这将为您提供:
+---+---+
| id|num|
+---+---+
| 1| 1|
| 2| 2|
| 3| 3|
+---+---+
或者,也可以使用
连接来完成。这样会比较慢,但是如果有很多列,就不需要先使用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")
我会使用窗口函数来实现这一点。假设要删除重复的id
行:
import org.apache.spark.sql.expressions.Window
df
.withColumn("cnt", count("*").over(Window.partitionBy($"id")))
.where($"cnt"===1).drop($"cnt")
.show()
我在使用@Raphael Roth解决方案的开源库中添加了一个killDuplicates()
方法。下面是如何使用代码:
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库将此逻辑排除在代码库之外。如果我理解正确,您希望删除在单个列中重复的所有条目吗?或者在考虑多个列时它们是重复的?@shaido是的,这些列的所有条目都在单个列中重复。在scala中,如下所示,我想在Python中应该有类似的方法来实现这一点,希望这有助于-获取列名:val columns=df.schema.map(u.name)-在该列列表上运行foldLeft:columns.foldLeft(df)((acc,elem)=>acc.dropDuplicates(elem))我看到您删除了pyspark标记并添加了您正在使用Scala,因此我更改了答案以反映这一点。由于您正在检查分组列的计数==1,连接不能替换为first($“num”)。作为(“num”)
?它应该会产生相同的输出。@philantrovert这是一个很好的观点,我不确定我怎么会错过它。我更改了答案以考虑到这一点。@shaido您的解决方案也很有效,但我希望避免为这个问题创建另一个数据帧,这就是为什么接受raphael的解决方案ans@salmanbw但是第一种方法不会创建任何额外的数据帧?唯一的区别是,这个人使用groupBy
和agg
,而他使用窗口函数来获得结果。我尝试了随机生成数据,用户应该注意。persist可能是相关的。
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"))
}
}
}