Pyspark 如何循环数据帧并向每行添加数组

Pyspark 如何循环数据帧并向每行添加数组,pyspark,pyspark-dataframes,Pyspark,Pyspark Dataframes,我需要循环pyspark数据帧,并在活动月数中爆炸每一行。当我试图将数据放入配置单元时,我主要关心的是内存管理,以及在此过程中所消耗的时间 我用collect和“idx”,F.单调地增加id() 但这破坏了我代码的性能 输入 输出 EmpId effective_Month 1234 Jan-12 1234 Feb-12 1234 .... 1234 Oct-12 2345 Jan-12 2345 Feb-12 2345 .... 2345 Dec-12 通常,我建议尝试使用u

我需要循环pyspark数据帧,并在活动月数中爆炸每一行。当我试图将数据放入配置单元时,我主要关心的是内存管理,以及在此过程中所消耗的时间

我用collect和
“idx”,F.单调地增加id()
但这破坏了我代码的性能

输入

输出

EmpId effective_Month
1234  Jan-12
1234  Feb-12
1234  ....
1234  Oct-12
2345  Jan-12
2345  Feb-12
2345  ....
2345  Dec-12

通常,我建议尝试使用udf。我曾经遇到过类似的问题,但我认为解决方案仍然太复杂

相反,你可以改变你对这个问题的看法。当您知道所有
empid
min(date\u active)
max(date\u end)
时,您可以遍历所有月份,例如
'yyyy-mm-01'
,并将其保存为数据帧。 现在,您(广播-)将生成的数据帧与表中的每一行连接起来。最后,您只需要一个简单的过滤器,如:
在生效日期和结束日期之间的一个月内生效。
最后,您应该将
effective\u month
转换为您喜欢的字符串格式


如果广播表很小,那么广播连接非常快,因此运行时在这里应该不是问题。

您可以在数据帧API中解决此问题,如下所示

创建示例数据帧

  df = spark.createDataFrame([["123","2012-01-01","2012-10-01"],['234', '2012-01-01', '2012-05-01'],["345","2012-01-01","2012-11-01"]], ("age","date_active", "date_end"))

    +---+-----------+----------+
    |age|date_active|  date_end|
    +---+-----------+----------+
    |123| 2012-01-01|2012-10-01|
    |234| 2012-01-01|2012-05-01|
    |345| 2012-01-01|2012-11-01|
    +---+-----------+----------+
将数据类型从字符串更改为时间戳

df = df.withColumn('date_active', df['date_active'].cast('timestamp'))\
.withColumn('date_end', df['date_end'].cast('timestamp'))
使用下面的代码添加月份列

from pyspark.sql import functions as f

df.withColumn('month_diff', f.months_between('date_end', 'date_active')).withColumn("repeat", f.expr("split(repeat(',', month_diff), ',')"))\
.select("*", f.posexplode("repeat").alias("date", "val")).withColumn("date", f.expr("add_months(date_active, date)"))\
.withColumn('month', f.date_format('date','MMM')).select(['age', 'date_active', 'date_end', 'month']).show()


---+-----------+----------+-----+
|age|date_active|  date_end|month|
+---+-----------+----------+-----+
|123| 2012-01-01|2012-10-01|  Jan|
|123| 2012-01-01|2012-10-01|  Feb|
|123| 2012-01-01|2012-10-01|  Mar|
|123| 2012-01-01|2012-10-01|  Apr|
|123| 2012-01-01|2012-10-01|  May|
|123| 2012-01-01|2012-10-01|  Jun|
|123| 2012-01-01|2012-10-01|  Jul|
|123| 2012-01-01|2012-10-01|  Aug|
|123| 2012-01-01|2012-10-01|  Sep|
|123| 2012-01-01|2012-10-01|  Oct|
|234| 2012-01-01|2012-05-01|  Jan|
|234| 2012-01-01|2012-05-01|  Feb|
|234| 2012-01-01|2012-05-01|  Mar|
|234| 2012-01-01|2012-05-01|  Apr|
|234| 2012-01-01|2012-05-01|  May|
|345| 2012-01-01|2012-11-01|  Jan|
|345| 2012-01-01|2012-11-01|  Feb|
|345| 2012-01-01|2012-11-01|  Mar|
|345| 2012-01-01|2012-11-01|  Apr|
|345| 2012-01-01|2012-11-01|  May|
+---+-----------+----------+-----+

从pyspark.sql.types导入熊猫作为pd在dfMT.collect()中为f导入*hive_context=HiveContext(sc):d=[]MemberId=f.MemberId mth=f.months#c=int(mth,0)sd=f.FromDate ed=f.ToDate lst=[dt.strTime(“%2.2d-%2.2d%”(y,m),“%y-%m”)。strftime(“%b-%y”)在范围内(sd.year,ed.year+1)对于范围内的m(如果y==sd.year else 1,ed.month+1如果y==ed.year else 13),对于范围内的n(mth):d.append({“MemberId”:MemberId,“MonthName”:lst[n]})df=pd.DataFrame(d)spark\u df=hive\u context.createDataFrame(df)spark\u df.write.mode('append')。format('hive')。saveAsTable('test123'))可能重复的是
date\u active
date\u end
始终保证在同一年?也可能重复替换为column('month',f.date\u format('date','MMM'))和withColumn('month',f.date\u format('date','MMM-YY')。感谢Ravi的第一手代码运行得很好,并且成功了。谢谢你的建议。
from pyspark.sql import functions as f

df.withColumn('month_diff', f.months_between('date_end', 'date_active')).withColumn("repeat", f.expr("split(repeat(',', month_diff), ',')"))\
.select("*", f.posexplode("repeat").alias("date", "val")).withColumn("date", f.expr("add_months(date_active, date)"))\
.withColumn('month', f.date_format('date','MMM')).select(['age', 'date_active', 'date_end', 'month']).show()


---+-----------+----------+-----+
|age|date_active|  date_end|month|
+---+-----------+----------+-----+
|123| 2012-01-01|2012-10-01|  Jan|
|123| 2012-01-01|2012-10-01|  Feb|
|123| 2012-01-01|2012-10-01|  Mar|
|123| 2012-01-01|2012-10-01|  Apr|
|123| 2012-01-01|2012-10-01|  May|
|123| 2012-01-01|2012-10-01|  Jun|
|123| 2012-01-01|2012-10-01|  Jul|
|123| 2012-01-01|2012-10-01|  Aug|
|123| 2012-01-01|2012-10-01|  Sep|
|123| 2012-01-01|2012-10-01|  Oct|
|234| 2012-01-01|2012-05-01|  Jan|
|234| 2012-01-01|2012-05-01|  Feb|
|234| 2012-01-01|2012-05-01|  Mar|
|234| 2012-01-01|2012-05-01|  Apr|
|234| 2012-01-01|2012-05-01|  May|
|345| 2012-01-01|2012-11-01|  Jan|
|345| 2012-01-01|2012-11-01|  Feb|
|345| 2012-01-01|2012-11-01|  Mar|
|345| 2012-01-01|2012-11-01|  Apr|
|345| 2012-01-01|2012-11-01|  May|
+---+-----------+----------+-----+