我有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()
关于我可以使用的替代功能或如何正确使用这些替代功能的任何建议?
答案 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%是否没有我没有考虑的副作用以及是否符合您的需求。