Pyspark-比较两个数据帧,删除完全匹配的行,将行与差异合并,然后将匹配的值清零

时间:2019-02-05 18:03:52

标签: apache-spark pyspark

所以我知道如何比较两个数据帧并使用减法删除匹配的行。很好。

我知道如何将不匹配的值结合起来,以创建两个表都不匹配的结果的新df。

我不知道该怎么做,然后使用pyspark以分布式方式匹配(并保留id col)的空值

示例:

df_as_list = [['id','name','monthly_sales'],
              [101,'John Snow', 1234.56],
              [102,'Daenerys Targaryen', 9294.96],
              [103,'Saul Goodman', 1274.57],
              [104,'Bobby Axelrob', 1123459.56],
              [105,'Joe Miller', 34.56],
              [106,'James Holden', 1.23]]
my_schema = df_as_list.pop(0)
df1 = spark.createDataFrame(df_as_list, my_schema)

df_as_list = [['id','name','monthly_sales'],
              [101,'John Snow', 777.56],
              [102,'Daenerys Targaryen', 9294.96],
              [103,'Saul Goodman', 1274.57],
              [104,'Bobby Axelrob', 1123459.56],
              [105,'Joe Miller', 34.56],
              [1106,'James Holden', 1.23]]
my_schema = df_as_list.pop(0)
df2 = spark.createDataFrame(df_as_list, my_schema)

df1.show()
df2.show()

所需的输出:

+---+------------------+-------------+
| id|              name|monthly_sales|
+---+------------------+-------------+
|101|                  |      1234.56|
|101|                  |       777.56|
+---+------------------+-------------+

1 个答案:

答案 0 :(得分:0)

一种方法是首先找到存在差异的id,并找出哪些列相等:

from functools import reduce

diffs = df1.join(df2, on="id")\
    .where(reduce(lambda a, b: a|b, [df1[c] != df2[c] for c in df1.columns]))\
    .select("id", *[(df1[c] == df2[c]).alias(c) for c in df1.columns if c != "id"])
diffs.show()
#+---+----+-------------+
#| id|name|monthly_sales|
#+---+----+-------------+
#|101|true|        false|
#+---+----+-------------+

条件reduce(lambda a, b: a|b, [df1[c] != df2[c] for c in df1.columns])将仅保留两个数据帧之间至少一列不同的行。

现在使用diffs加入两个DataFrame的并集,并使用布尔值确定是否要显示该列,或者使用null来显示它们是否相同。

from pyspark.sql.functions import when, col, lit

df1.union(df2).alias("u")\
    .join(diffs.alias("d"), on="id")\
    .select(
        "id", 
        *[
            when(
                col("d."+c), 
                lit(None)
            ).otherwise(col("u."+c)).alias(c) 
            for c in diffs.columns 
            if c != "id"
        ]
    )\
    .show()
#+---+----+-------------+
#| id|name|monthly_sales|
#+---+----+-------------+
#|101|null|       777.56|
#|101|null|      1234.56|
#+---+----+-------------+

您必须将null放在匹配的列中(而不是空字符串),因为该列的类型需要保持一致(除非您将所有内容都强制转换为字符串)。