Генерация месячных временных меток между двумя датами в фрейме данных pyspark - PullRequest
0 голосов
/ 19 сентября 2018

У меня есть некоторый DataFrame со столбцом "date", и я пытаюсь сгенерировать новый 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)

Проблема в том, что я взял за month_step 31 день, и это не совсем правильно, потому что в некоторых месяцах есть 30 дней и даже28 днейМожно ли как-то сделать это более точным?

Так же, как примечание : позже мне понадобятся только значения year и month , поэтому я буду игнорироватьдень и время.Но в любом случае, потому что я генерирую временные метки между довольно большим диапазоном дат (между 2001 и 2018 годами), смещение временных меток.

Вот почему иногда некоторые месяцы пропускаются.Например, этот снимок отсутствует 2010-02:

|2010-01  |
|2010-03  |
|2010-04  |
|2010-05  |
|2010-06  |
|2010-07  |

Я проверил, и с 2001 по 2018 годы было пропущено всего 3 месяца.

1 Ответ

0 голосов
/ 19 сентября 2018

Предположим, у вас был следующий фрейм данных:

data = [("2000-01-01","2002-12-01")]
df = spark.createDataFrame(data, ["minDate", "maxDate"])
df.show()
#+----------+----------+
#|   minDate|   maxDate|
#+----------+----------+
#|2000-01-01|2002-12-01|
#+----------+----------+

Вы можете добавить столбец 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|
#+----------+
...