如何按多列过滤数据框?
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
一次
随机播放 df1
和 df2
与大小无关
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 中其他数据帧中的多列匹配过滤数据帧