Просто используйте списки:
Следуйте инструкциям, чтобы получить df1 (убедитесь, что в столбце trans_date
указан DateType ())
from pyspark.sql import functions as f, Window
from datetime import timedelta
df = df.withColumn('trans_date', f.to_date('trans_date'))
max_date = df.select(f.max('trans_date').alias('max_date')).first().max_date
# datetime.date(2019, 9, 11)
df1 = df.withColumn('balance', f.round(f.sum('amount').over(Window.partitionBy('user_id')),2))
Затем используйте списки для создания спискакортежа с тремя элементами (range_name, range_start_date, range_end_date)
dranges = [
('days_{}_{}'.format(i*30+1,(i+1)*30), max_date-timedelta(days=(i+1)*30), max_date-timedelta(days=i*30+1))
for i in range(5)
]
dranges
#[('days_1_30', datetime.date(2019, 8, 12), datetime.date(2019, 9, 10)),
# ('days_31_60', datetime.date(2019, 7, 13), datetime.date(2019, 8, 11)),
# ('days_61_90', datetime.date(2019, 6, 13), datetime.date(2019, 7, 12)),
# ('days_91_120', datetime.date(2019, 5, 14), datetime.date(2019, 6, 12)),
# ('days_121_150', datetime.date(2019, 4, 14), datetime.date(2019, 5, 13))]
"""will need to adjust the first element since it does not follow the same rules as other ranges:"""
dranges[0] = ('days_0_30', dranges[0][1], max_date)
Теперь используйте понимание списка для генерации этих новых столбцов:
df2 = df1.select('*', *[
f.when((df1.trans_date >= d[1]) & (df1.trans_date <= d[2]), df1.balance).otherwise(None).alias(d[0])
for d in dranges
])
df2.show()
+-------+------+----------+-------+---------+----------+----------+-----------+------------+
|user_id|amount|trans_date|balance|days_0_30|days_31_60|days_61_90|days_91_120|days_121_150|
+-------+------+----------+-------+---------+----------+----------+-----------+------------+
| 101| 99.10|2019-06-04| 85.03| null| null| null| 85.03| null|
| 101|-69.81|2019-09-11| 85.03| 85.03| null| null| null| null|
| 101| 12.51|2018-12-14| 85.03| null| null| null| null| null|
| 101| 43.23|2018-09-11| 85.03| null| null| null| null| null|
| 102| 89.27|2019-06-04| 178.37| null| null| null| 178.37| null|
| 102| 89.10|2019-03-04| 178.37| null| null| null| null| null|
| 103| 73.11|2019-09-10| 73.11| 73.11| null| null| null| null|
+-------+------+----------+-------+---------+----------+----------+-----------+------------+
Примечание: выглядитвы используете 90-дневные интервалы вместо 30-дневных в вашем коде.но я полагаю, что вам легко настроить приведенный выше код в соответствии с вашими потребностями.