所以我知道如何比较两个数据帧并使用减法删除匹配的行。很好。
我知道如何将不匹配的值结合起来,以创建两个表都不匹配的结果的新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|
+---+------------------+-------------+
答案 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
放在匹配的列中(而不是空字符串),因为该列的类型需要保持一致(除非您将所有内容都强制转换为字符串)。