【问题标题】: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 的数据框中不支持“插入”。 所以我的问题是:

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

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

【问题讨论】:

    标签: scala apache-spark apache-spark-sql


    【解决方案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 用于衡量对完整管道的影响通常对我来说已经足够了。一个问题是有很多活动部件需要单独测量这样的事情。
    猜你喜欢
    • 2018-07-13
    • 2014-03-31
    • 1970-01-01
    • 2019-11-27
    • 2019-03-07
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多