如何按多列过滤数据框?

Posted

技术标签:

【中文标题】如何按多列过滤数据框?【英文标题】:How to filter a dataframe by multiple columns? 【发布时间】:2016-04-30 16:55:56 【问题描述】:

我有一个问题如下:

我有两个数据框

数据框 DF1:

ID, Name, age
1   name1  18
2   name2  20

数据帧 DF2:

ID, Name, age
1   name1 18
3   name3 19

我正在尝试过滤 DF2 以通过 ID 和名称排除 DF1 中包含的记录,以便我可以获得新的 DF2 之类的

ID, Name, age
3   name3  19

然后合并这两个数据框得到最终结果:

ID, Name, age
1   name1  18
2   name2  20
3   name3  19

要在 T-SQL 中执行此操作,我可以编写如下语句

INSERT INTO DF1 
SELECT ID, Name, age FROM DF2 WHERE NOT EXISTS
(SELECT 1 FROM DF1 WHERE DF1.ID = DF2.ID AND DF1.Name = DF2.Name)

但我发现 sparkSQL 的数据框中不支持“插入”。 所以我的问题是:

如何根据多列过滤数据框?

如何将两个数据框合并在一起? 我很感激任何解决方案。

【问题讨论】:

【参考方案1】:

UNION 后跟 DISTINCT

假设记录是唯一的,实现您想要的最简单的方法是使用 UNION 并在其后添加 DISTINCT

val df1 = Seq((1, "name1", 18), (2, "name2", 20)).toDF("ID", "Name", "age")
val df2 = Seq((1, "name1", 18), (3, "name3", 19)).toDF("ID", "Name", "age")

df1.unionAll(df2).distinct.show

// +---+-----+---+
// | ID| Name|age|
// +---+-----+---+
// |  1|name1| 18|
// |  2|name2| 20|
// |  3|name3| 19|
// +---+-----+---+

特点

只能访问df1 一次 随机播放 df1df2 与大小无关

EXCEPT 后跟 UNION

另一种方法是使用EXCEPT,后跟UNION

df1.unionAll(df2.except(df1)).show  // df2.distinct.except to drop duplicates

// +---+-----+---+
// | ID| Name|age|
// +---+-----+---+
// |  1|name1| 18|
// |  2|name2| 20|
// |  3|name3| 19|
// +---+-----+---+

属性

必须访问df1 两次 随机播放两个帧,与大小无关 (?) 可用于三帧 (df3.unionAll(df2.except(df1)))

LEFT OUTER JOIN 后接 SELECT 过滤器后接 UNION

最后,如果您只想部分匹配 LEFT OUTER JOIN 与过滤器后跟 UNION 应该可以解决问题:

df2.as("df2")
  .join(
    df1.select("id", "name").as("df1"),
    // join on id and name
    $"df1.id" === $"df2.id" && $"df1.name" === $"df2.name",
    "leftouter")
  // This could be replaced by .na.drop(...)
  .where($"df1.id".isNull && $"df1.Name".isNull)
  .select($"df2.id", $"df2.name", $"df2.age")
  .unionAll(df1)
  .show

// ---+-----+---+
// | ID| Name|Age|
// +---+-----+---+
// |  3|name3| 19|
// |  1|name1| 18|
// |  2|name2| 20|
// +---+-----+---+

属性

必须访问df1 两次 如果其中一个数据帧小到可以广播,则可能不需要 shuflle 可用于三个数据帧

【讨论】:

看到不同的解决方案后,我想知道它们的性能。哪种解决方案在性能方面最好,为什么? @JacekLaskowski 我自己一直在考虑这个问题,其中涉及到不同的权衡。假设我们只使用 2 个帧并且两者都很大,我会采用第一种方法,因为它必须只访问一次 df1(没有分支和合并)。如果涉及 3 个帧(我们合并的帧与减去的帧不同),那么这根本不适用。如果其中一个帧足够小可以广播以避免随机播放,则基于连接的解决方案将是更可取的。 @JacekLaskowski 说实话我不确定except。看起来它不能使用广播,所以当你想与第三帧合并时,我只会将它用作第一个解决方案的替代方案。 知道如何测量它吗?我会从 Web UI 和 SparkListener 开始,但也许还有更多专业工具/方式? @JacekLaskowski UI 用于简单案例,Docker + Munin 用于衡量对完整管道的影响通常对我来说已经足够了。一个问题是有很多活动部件需要单独测量这样的事情。

以上是关于如何按多列过滤数据框?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据 Spark Scala 中其他数据帧中的多列匹配过滤数据帧

如何在过滤器和 lambda 函数 pyspark 中使用多列

Pyspark:过滤多列上的行

如何按字符串过滤熊猫数据框?

在 Spark 数据框中过滤多列的最佳方法是啥?

如何在 Python 中按多列对 Pandas DataFrame 进行排序