使用Pyspark合并两个数据框

时间:2019-06-03 10:34:39

标签: dataframe pyspark databricks

我有2个DF可以合并:

DF1->包含库存

Plant   Art_nr    Tot
A        X         5
B        Y         4

DF2 --Z包含未清交货

Plant    Art_nr   Tot
A        X        1
C        Z        3

我想获得DF3,其中Plant和Art_nr的每种组合: -如果DF1.Plant&Art_nr和DF2.Plant&Art_nr之间存在匹配,我得到DF1和DF2之间的区别 -如果DF1.Plant&Art_nr和DF2.Plant&Art_nr之间没有匹配项,则保留DF1和DF2中的原始值

DF3->

Plant    Art_nr   Total
A        X        4
B        Y        4
C        Z        3

我在DF1和DF2中创建了一个“ Concat”字段来串联Plant和Art_nr,并尝试使用完全连接+,当+时,但我找不到正确的语法

DF1.join(DF2, ["Concat"],"full").withColumn("Total",when(DF1.Concat.isin(DF2.Concat)), DF1.Tot - DF2.Tot).otherwise(when(not(DF1.Concat.isin(DF2.Concat)), DF1.Tot)).show()

关于我可以使用的替代功能或如何正确使用这些替代功能的任何建议?

3 个答案:

答案 0 :(得分:0)

使用Udf,看起来很冗长,但更加清晰

from pyspark.sql.types import IntegerType
from pyspark.sql.functions import udf, array

def score(arr):
    if arr[0] is None:
        return int(arr[1])
    elif arr[1] is None:
        return int(arr[0])
    return (int(arr[0])-int(arr[1]))

udf_final = udf(lambda arr: score(arr), IntegerType())

DF1.join(DF2,"full").withColumn("final_score",udf_final(array("Tot","Total")))

答案 1 :(得分:0)

您必须同时连接两个数据框,然后执行case (If-Else)表达式或coalesce函数。

这可以通过多种方式完成,这里仅举几个例子。

选项1::使用coalesce功能替代CASE-WHEN-NULL

from pyspark.sql.functions import coalesce, lit,abs

cond = [df1.Plant == df2.Plant, df1.Art_nr == df2.Art_nr]

df1.join(df2,cond,'full')  \
.select(coalesce(df1.Plant,df2.Plant).alias('Plant')
       ,coalesce(df1.Art_nr,df2.Art_nr).alias('Art_nr')
       ,abs(coalesce(df1.Tot,lit(0)) - coalesce(df2.Tot,lit(0))).alias('Tot')
       ).show()

选项2::在case内使用selectExpr()表达式

cond = [df1.Plant == df2.Plant, df1.Art_nr == df2.Art_nr]

df1.alias('a').join(df2.alias('b'),cond,'full')  \
.selectExpr("CASE WHEN a.Plant IS NULL THEN b.Plant ELSE a.Plant END AS Plant",
            "CASE WHEN a.Art_nr IS NULL THEN b.Art_nr ELSE a.Art_nr END AS Art_nr",
            "abs(coalesce(a.Tot,0) - coalesce(b.Tot,0))  AS Tot") \
.show()

#+-----+------+---+
#|Plant|Art_nr|Tot|
#+-----+------+---+
#|    A|     X|  4|
#|    B|     Y|  4|
#|    C|     Z|  3|
#+-----+------+---+

选项3:使用when().otherwise()

from pyspark.sql.functions import when,coalesce, lit,abs

cond = [df1.Plant == df2.Plant, df1.Art_nr == df2.Art_nr]

df1.join(df2,cond,'full')  \
.select(when(df1.Plant.isNull(),df2.Plant).otherwise(df1.Plant).alias('Plant')
       ,when(df1.Art_nr.isNull(),df2.Art_nr).otherwise(df1.Art_nr).alias('Art_nr')
       ,abs(coalesce(df1.Tot,lit(0)) - coalesce(df2.Tot,lit(0))).alias('Tot')
       ).show()

输出:

#+-----+------+---+
#|Plant|Art_nr|Tot|
#+-----+------+---+
#|    A|     X|  4|
#|    B|     Y|  4|
#|    C|     Z|  3|
#+-----+------+---+

答案 2 :(得分:0)

我可能会与groupBy进行合并,并进行一些重新格式化,以避免使用UDF并且没有大量代码。

from pyspark.sql.functions import *

DF3 = DF1.union(DF2.withColumn("Tot", col("Tot") * (-1)))
DF3 = DF3.groupBy("Plant", "Art_nr").agg(sum("Tot").alias("Tot"))
DF3 = DF3.withColumn("Tot", abs(col("Tot")))

我不确定100%是否没有我没有考虑的副作用以及是否符合您的需求。