基于DataFrame join写列

Posted

技术标签:

【中文标题】基于DataFrame join写列【英文标题】:Write column based on DataFrame join 【发布时间】:2018-06-03 17:20:52 【问题描述】:

假设我有两个 DataFrame -- df1df2 -- 都有 foobar 列。 foo 列是一个 CRC32 哈希值,如 123456bar 列是一个布尔字段,默认为 False

在 pyspark 中,比较两个 DataFrame 中 foo 的值的有效方法是什么,如果它们匹配,则将列 bar 写入 True

例如,给定以下两个 DataFrame:

# df1
foo    | bar
-------|------
123456 | False
444555 | False
666777 | False
888999 | False

# df2
foo    | bar
-------|------
938894 | False
129803 | False
666777 | False
888999 | False

我想要一个如下所示的新 DataFrame,其中两个 True 列的哈希值发生了变化:

# df3
foo    | bar
-------|------
938894 | True <---
129803 | True <---
666777 | False
888999 | False

任何指导将不胜感激。

2018 年 7 月 1 日更新

在成功使用接受的答案很长一段时间后,遇到了一种情况,使解决方案不太适合。如果连接中的一个 DataFrame 中的多行与连接中另一个 DataFrame 中的行具有相同的 foo 值,则会导致该共享值上的行的笛卡尔积增长。

在我的例子中,我有基于空字符串的 CRC32 哈希值,这导致哈希值 0。我还应该补充一点,我确实有一个唯一的字符串来匹配上面的行,在 id 下(可能有过于简单的情况),也许 这是要加入的事情

它会产生这样的情况:

# df1
id   |foo    | bar
-----|-------|------
abc  |123456 | False
def  |444555 | False
ghi  |0      | False
jkl  |0      | False

# df2
id   |foo    | bar
-----|-------|------
abc  |123456 | False
def  |999999 | False
ghi  |666777 | False
jkl  |0      | False

如果选择了答案,将会得到一个数据框,其中包含 更多 行:

# df3
id   |foo    | bar
-----|-------|------
abc  |123456 | False
def  |999999 | True <---
ghi  |0      | False
jkl  |0      | False
jkl  |0      | False # extra row add through join

我将保留选择的答案,因为它是对最初提出的问题的一个很好的答案。但是,对于如何处理 foo 列可能匹配的 DataFrame 的任何建议,我们将不胜感激。

2018 年 7 月 1 日的另一个更新,替代答案

如果没有加入 id 列,我已经把问题复杂化了。使用它时,根据fingerprint 列的直接比较,加入和编写transformed 列相对简单:

df2.alias("df2").join(df1.alias("df1"), df1.id == df2.id, 'left')\
    .select(f.col('df2.foo'), f.when(df1.fingerprint != df2.fingerprint, f.lit(True)).otherwise(f.col('df2.bar')).alias('bar'))\
    .show(truncate=False)

【问题讨论】:

【参考方案1】:

df2df1别名左连接 并使用when 函数来检查不匹配的逻辑应该会给你你想要的输出

df2.alias("df2").join(df1.alias("df1"), df1.foo == df2.foo, 'left')\
    .select(f.col('df2.foo'), f.when(f.isnull(f.col('df1.foo')), f.lit(True)).otherwise(f.col('df2.bar')).alias('bar'))\
    .show(truncate=False)

这应该给你

+------+-----+
|foo   |bar  |
+------+-----+
|129803|true |
|938894|true |
|888999|false|
|666777|false|
+------+-----+

【讨论】:

这就是生意!效果很好,非常感谢。选择带有when/otherwise 语句的列,然后选择aliasing 作为bar,这是理解我如何在其他上下文中使用它的关键。谢谢!【参考方案2】:

我建议使用左连接并编写代码,以便当数据为空时输出假,反之亦然。

【讨论】:

谢谢,我也有同样的想法,但无法想象语法。

以上是关于基于DataFrame join写列的主要内容,如果未能解决你的问题,请参考以下文章

基于不同类型spark 1.6列的Spark join dataframe

DataFrame[]中括号,通过列名取数据

风之子笔记写列

检查类型:如何检查某个东西是 RDD 还是 DataFrame?

DataFrame编程模型初谈与Spark SQL

尝试在 SQL Plus 查询中小写列时出错