使用pyspark对列上的值求和
我有一个场景,我有两个表,一个表有天,另一个表有值。所以从有天数的表中,我需要将另一个表的值和天数相加。 数据帧使用pyspark对列上的值求和,pyspark,apache-spark-sql,Pyspark,Apache Spark Sql,我有一个场景,我有两个表,一个表有天,另一个表有值。所以从有天数的表中,我需要将另一个表的值和天数相加。 数据帧 dataframe1 df1 = spark.createDataFrame( [ ('ll',5) ('yy',6) ], ('x','days') ) dataframe2 df = spark.createDataFrame( [ ('ll','2020-01-05','
dataframe1
df1 = spark.createDataFrame(
[
('ll',5)
('yy',6)
],
('x','days')
)
dataframe2
df = spark.createDataFrame(
[
('ll','2020-01-05','1','10','50'),
('ll','2020-01-06','1','10'),
('ll','2020-01-07','1','10'),
('ll','2020-01-08','1','10'),
('ll','2020-01-09','1','10'),
('ll','2020-01-10','1','10'),
('ll','2020-01-11','1','20'),
('ll','2020-01-12','1','10'),
('ll','2020-01-05','2','30'),
('ll','2020-01-06','2','30'),
('ll','2020-01-07','2','30'),
('ll','2020-01-08','2','40'),
('ll','2020-01-09','2','30'),
('ll','2020-01-10','2','10'),
('ll','2020-01-11','2','10'),
('ll','2020-01-12','2','10'),
('yy','2020-01-05','1','20'),
('yy','2020-01-06','1','20'),
('yy','2020-01-07','1','20'),
('yy','2020-01-08','1','20'),
('yy','2020-01-09','1','20'),
('yy','2020-01-10','1','40'),
('yy','2020-01-11','1','20'),
('yy','2020-01-12','1','20'),
('yy','2020-01-05','2','40'),
('yy','2020-01-06','2','40'),
('yy','2020-01-07','2','40'),
('yy','2020-01-08','2','40'),
('yy','2020-01-09','2','40'),
('yy','2020-01-10','2','40'),
('yy','2020-01-11','2','60'),
('yy','2020-01-12','2','40')
],
('x','date','flag','value')
)
expected_dataframe = spark.createDataFrame(
[
('ll','2020-01-05','1','10','50'),
('ll','2020-01-06','1','10','50'),
('ll','2020-01-07','1','10','60'),
('ll','2020-01-08','1','10','60'),
('ll','2020-01-09','1','10','50'),
('ll','2020-01-10','1','10','40'),
('ll','2020-01-11','1','20','30'),
('ll','2020-01-12','1','10','10'),
('ll','2020-01-05','2','30','170'),
('ll','2020-01-06','2','30','140'),
('ll','2020-01-07','2','30','120'),
('ll','2020-01-08','2','40','100'),
('ll','2020-01-09','2','30','60'),
('ll','2020-01-10','2','10','30'),
('ll','2020-01-11','2','10','20'),
('ll','2020-01-12','2','10','10'),
('yy','2020-01-05','1','20','140'),
('yy','2020-01-06','1','20','140'),
('yy','2020-01-07','1','20','140'),
('yy','2020-01-08','1','20','120'),
('yy','2020-01-09','1','20','100'),
('yy','2020-01-10','1','40','80'),
('yy','2020-01-11','1','20','40'),
('yy','2020-01-12','1','20','20'),
('yy','2020-01-05','2','40','240'),
('yy','2020-01-06','2','40','260'),
('yy','2020-01-07','2','40','260'),
('yy','2020-01-08','2','40','220'),
('yy','2020-01-09','2','40','180'),
('yy','2020-01-10','2','40','140'),
('yy','2020-01-11','2','60','100'),
('yy','2020-01-12','2','40','40')
],
('x','date','flag','value','result')
预期结果
+---+----------+----+-----+------+
| x| date|flag|value|result|
+---+----------+----+-----+------+
| ll|2020-01-05| 1| 10| 50|
| ll|2020-01-06| 1| 10| 50|
| ll|2020-01-07| 1| 10| 60|
| ll|2020-01-08| 1| 10| 60|
| ll|2020-01-09| 1| 10| 50|
| ll|2020-01-10| 1| 10| 40|
| ll|2020-01-11| 1| 20| 30|
| ll|2020-01-12| 1| 10| 10|
| ll|2020-01-05| 2| 30| 170|
| ll|2020-01-06| 2| 30| 140|
| ll|2020-01-07| 2| 30| 120|
| ll|2020-01-08| 2| 40| 100|
| ll|2020-01-09| 2| 30| 60|
| ll|2020-01-10| 2| 10| 30|
| ll|2020-01-11| 2| 10| 20|
| ll|2020-01-12| 2| 10| 10|
| yy|2020-01-05| 1| 20| 140|
| yy|2020-01-06| 1| 20| 140|
| yy|2020-01-07| 1| 20| 140|
| yy|2020-01-08| 1| 20| 120|
| yy|2020-01-09| 1| 20| 100|
| yy|2020-01-10| 1| 40| 80|
| yy|2020-01-11| 1| 20| 40|
| yy|2020-01-12| 1| 20| 20|
| yy|2020-01-05| 2| 40| 240|
| yy|2020-01-06| 2| 40| 260|
| yy|2020-01-07| 2| 40| 260|
| yy|2020-01-08| 2| 40| 220|
| yy|2020-01-09| 2| 40| 180|
| yy|2020-01-10| 2| 40| 140|
| yy|2020-01-11| 2| 60| 100|
| yy|2020-01-12| 2| 40| 40|
+---+----------+----+-----+------+
代码
所以我需要基于天列的求和值列,也就是说,若天列是5,我需要求和5行值
我加入了两个表,并使用窗口函数,我试图解决,但我没有解决,也无法想出如何解决它。你能告诉我如何解决这个问题吗?首先你可以在
x
上加入,然后在你的行上创建一个行号()
,它将用于在大于天的地方挑选出来(将它们变成空值),然后在仅分区的窗口上求和
在所有行上广播求和
更新
:
对于Spark2.4+,您可以在收集列表之后使用更高阶的函数
和
。
我假设数据按照所提供的示例进行排序,如果不是这样,则需要添加额外的步骤来确保
from pyspark.sql import functions as F
from pyspark.sql.window import Window
w=Window().partitionBy("x","flag")
w1=Window().partitionBy("x","flag").orderBy(F.to_date("date","yyyy-dd-MM"))
df.join(df1,['x'])\
.withColumn("result", F.collect_list("value").over(w))\
.withColumn("rowNum", F.row_number().over(w1)-1)\
.withColumn("result", F.expr("""aggregate(transform(result,(x,i)->array(x,i)),0,(acc,x)-> \
IF((int(x[1])>=rowNum)and(int(x[1])<days+rowNum),int(x[0])+acc,acc))"""))\
.drop("flag","rowNum","days").show()
#+---+----------+-----+------+
#| x| date|value|result|
#+---+----------+-----+------+
#| ll|2020-01-05| 10| 50|
#| ll|2020-01-06| 10| 50|
#| ll|2020-01-07| 10| 60|
#| ll|2020-01-08| 10| 60|
#| ll|2020-01-09| 10| 50|
#| ll|2020-01-10| 10| 40|
#| ll|2020-01-11| 20| 30|
#| ll|2020-01-12| 10| 10|
#| ll|2020-01-05| 30| 160|
#| ll|2020-01-06| 30| 140|
#| ll|2020-01-07| 30| 120|
#| ll|2020-01-08| 40| 100|
#| ll|2020-01-09| 30| 60|
#| ll|2020-01-10| 10| 30|
#| ll|2020-01-11| 10| 20|
#| ll|2020-01-12| 10| 10|
#| yy|2020-01-05| 20| 140|
#| yy|2020-01-06| 20| 140|
#| yy|2020-01-07| 20| 140|
#| yy|2020-01-08| 20| 120|
#| yy|2020-01-09| 20| 100|
#| yy|2020-01-10| 40| 80|
#| yy|2020-01-11| 20| 40|
#| yy|2020-01-12| 20| 20|
#| yy|2020-01-05| 40| 240|
#| yy|2020-01-06| 40| 260|
#| yy|2020-01-07| 40| 260|
#| yy|2020-01-08| 40| 220|
#| yy|2020-01-09| 40| 180|
#| yy|2020-01-10| 40| 140|
#| yy|2020-01-11| 60| 100|
#| yy|2020-01-12| 40| 40|
#+---+----------+-----+------+
从pyspark.sql导入函数为F
从pyspark.sql.window导入窗口
w=Window().partitionBy(“x”,“标志”)
w1=窗口().分区依据(“x”,“标志”).订购依据(截止日期(“日期”,“yyyy-dd-MM”))
join(df1,['x'])\
.带列(“结果”,F.收集列表(“值”)。超过(w))\
.withColumn(“rowNum”,F.行编号()。在(w1)-1上方)\
.withColumn(“结果”,F.expr(“聚合”(转换(结果,(x,i)->数组(x,i)),0,(acc,x)->\
如果((int(x[1])>=rowNum)和(int(x[1]))如果我只有4行,但我的天数是5,那么一个查询,假设是标志1。因此,如果天数满足,我需要求和,如果天数不满足,我需要求和标志中的总行数。修改了预期结果新的结果列对我来说没有意义。前两行是50,后两行是60,然后它会逐渐减少。可以吗你要详细说明@Mohammad Murtaza Hashmi的公式,假设你在flag1部分有6天,你的天数是5天。第一行加起来是5行,第二行加起来是剩下的5行,但当你到第三行时,你只有4行,所以我们必须加起来是4行。因此,理想情况下,每行需要5个日期如果没有5行,则取所有可用行的值。我希望是这样helpful@Anji乐意帮忙,请接受答案关闭线程
from pyspark.sql import functions as F
from pyspark.sql.window import Window
w=Window().partitionBy("x","flag").orderBy(F.to_date("date","yyyy-dd-MM"))
w1=Window().partitionBy("x","flag")
df.join(df1, ['x'])\
.withColumn("rowNum", F.row_number().over(w))\
.withColumn("expected_result", F.sum(F.when(F.col("rowNum")>F.col("days")\
,F.lit(None)).otherwise(F.col("value")))\
.over(w1)).drop("days","rowNum").show()
#+---+----------+----+-----+---------------+
#| x| date|flag|value|expected_result|
#+---+----------+----+-----+---------------+
#| ll|2020-01-05| 1| 10| 50.0|
#| ll|2020-01-06| 1| 10| 50.0|
#| ll|2020-01-07| 1| 10| 50.0|
#| ll|2020-01-08| 1| 10| 50.0|
#| ll|2020-01-09| 1| 10| 50.0|
#| ll|2020-01-10| 1| 10| 50.0|
#| ll|2020-01-11| 1| 10| 50.0|
#| ll|2020-01-12| 1| 10| 50.0|
#| ll|2020-01-05| 2| 30| 150.0|
#| ll|2020-01-06| 2| 30| 150.0|
#| ll|2020-01-07| 2| 30| 150.0|
#| ll|2020-01-08| 2| 30| 150.0|
#| ll|2020-01-09| 2| 30| 150.0|
#| ll|2020-01-10| 2| 10| 150.0|
#| ll|2020-01-11| 2| 10| 150.0|
#| ll|2020-01-12| 2| 10| 150.0|
#| yy|2020-01-05| 1| 20| 120.0|
#| yy|2020-01-06| 1| 20| 120.0|
#| yy|2020-01-07| 1| 20| 120.0|
#| yy|2020-01-08| 1| 20| 120.0|
#+---+----------+----+-----+---------------+
#only showing top 20 rows
from pyspark.sql import functions as F
from pyspark.sql.window import Window
w=Window().partitionBy("x","flag")
w1=Window().partitionBy("x","flag").orderBy(F.to_date("date","yyyy-dd-MM"))
df.join(df1,['x'])\
.withColumn("result", F.collect_list("value").over(w))\
.withColumn("rowNum", F.row_number().over(w1)-1)\
.withColumn("result", F.expr("""aggregate(transform(result,(x,i)->array(x,i)),0,(acc,x)-> \
IF((int(x[1])>=rowNum)and(int(x[1])<days+rowNum),int(x[0])+acc,acc))"""))\
.drop("flag","rowNum","days").show()
#+---+----------+-----+------+
#| x| date|value|result|
#+---+----------+-----+------+
#| ll|2020-01-05| 10| 50|
#| ll|2020-01-06| 10| 50|
#| ll|2020-01-07| 10| 60|
#| ll|2020-01-08| 10| 60|
#| ll|2020-01-09| 10| 50|
#| ll|2020-01-10| 10| 40|
#| ll|2020-01-11| 20| 30|
#| ll|2020-01-12| 10| 10|
#| ll|2020-01-05| 30| 160|
#| ll|2020-01-06| 30| 140|
#| ll|2020-01-07| 30| 120|
#| ll|2020-01-08| 40| 100|
#| ll|2020-01-09| 30| 60|
#| ll|2020-01-10| 10| 30|
#| ll|2020-01-11| 10| 20|
#| ll|2020-01-12| 10| 10|
#| yy|2020-01-05| 20| 140|
#| yy|2020-01-06| 20| 140|
#| yy|2020-01-07| 20| 140|
#| yy|2020-01-08| 20| 120|
#| yy|2020-01-09| 20| 100|
#| yy|2020-01-10| 40| 80|
#| yy|2020-01-11| 20| 40|
#| yy|2020-01-12| 20| 20|
#| yy|2020-01-05| 40| 240|
#| yy|2020-01-06| 40| 260|
#| yy|2020-01-07| 40| 260|
#| yy|2020-01-08| 40| 220|
#| yy|2020-01-09| 40| 180|
#| yy|2020-01-10| 40| 140|
#| yy|2020-01-11| 60| 100|
#| yy|2020-01-12| 40| 40|
#+---+----------+-----+------+