LDr*_*opl 3 date-range apache-spark apache-spark-sql pyspark
我有一些带有"date"列的DataFrame,并且我试图生成一个新的DataFrame,其中包含该"date"列的最小和最大日期之间的所有每月时间戳记。
解决方案之一如下:
month_step = 31*60*60*24
min_date, max_date = df.select(min_("date").cast("long"), max_("date").cast("long")).first()
df_ts = spark.range(
(min_date / month_step) * month_step,
((max_date / month_step) + 1) * month_step,
month_step
).select(col("id").cast("timestamp").alias("yearmonth"))
df_formatted_ts = df_ts.withColumn(
"yearmonth",
f.concat(f.year("yearmonth"), f.lit('-'), format_string("%02d", f.month("yearmonth")))
).select('yearmonth')
df_formatted_ts.orderBy(asc('yearmonth')).show(150, False)
Run Code Online (Sandbox Code Playgroud)
问题是我花了month_step31天的时间,但这并不正确,因为有些月份有30天,甚至28天。有可能以某种方式使其更加精确吗?
请注意:以后我只需要年和月的值,所以我将忽略日期和时间。但是无论如何,因为我正在生成一个很大的日期范围(在2001年至2018年之间)之间的时间戳,所以时间戳在变化。
这就是为什么有时会跳过几个月的原因。例如,此快照缺少2010-02:
|2010-01 |
|2010-03 |
|2010-04 |
|2010-05 |
|2010-06 |
|2010-07 |
Run Code Online (Sandbox Code Playgroud)
我检查了一下,从2001年到2018年仅跳过了3个月。
假设您具有以下DataFrame:
data = [("2000-01-01","2002-12-01")]
df = spark.createDataFrame(data, ["minDate", "maxDate"])
df.show()
#+----------+----------+
#| minDate| maxDate|
#+----------+----------+
#|2000-01-01|2002-12-01|
#+----------+----------+
Run Code Online (Sandbox Code Playgroud)
您可以按照与我对这个问题的回答相同的方法,添加一个date介于minDate和之间的所有月份的列。maxDate
只需替换pyspark.sql.functions.datediff为pyspark.sql.functions.months_between,然后使用add_months代替date_add:
import pyspark.sql.functions as f
df.withColumn("monthsDiff", f.months_between("maxDate", "minDate"))\
.withColumn("repeat", f.expr("split(repeat(',', monthsDiff), ',')"))\
.select("*", f.posexplode("repeat").alias("date", "val"))\
.withColumn("date", f.expr("add_months(minDate, date)"))\
.select('date')\
.show(n=50)
#+----------+
#| date|
#+----------+
#|2000-01-01|
#|2000-02-01|
#|2000-03-01|
#|2000-04-01|
# ...skipping some rows...
#|2002-10-01|
#|2002-11-01|
#|2002-12-01|
#+----------+
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2150 次 |
| 最近记录: |