PySpark 数据框中的日期差异

Date difference in years in PySpark dataframe

我来自 Pandas 背景,是 Spark 的新手。我有一个数据框,其中包含 iddobage 作为列。我想从他的 dob 中获取用户的年龄(在某些情况下 age 列为 NULL)。

+----+------+----------+
| id | age  |   dob    |
+----+------+----------+
|  1 | 24   | NULL     |
|  2 | 25   | NULL     |
|  3 | NULL | 1/1/1973 |
|  4 | NULL | 6/6/1980 |
|  5 | 46   |          |
|  6 | NULL | 1/1/1971 |
+----+------+----------+

我想要一个新列,它将根据 dob 和当前日期计算年龄。

我试过了,但没有得到任何结果:

df.withColumn("diff", 
              datediff(to_date(lit("01-06-2020")),
                       to_date(unix_timestamp('dob', "dd-MM-yyyy").cast("timestamp")))).show()

您需要计算日期差异并将结果转换为年份,如下所示:

df.withColumn('diff', 
    when(col('age').isNull(), 
         floor(datediff(current_date(), to_date(col('dob'), 'M/d/yyyy'))/365.25))\
  .otherwise(col('age'))).show()

产生:

+---+----+--------+----+
| id| age|     dob|diff|
+---+----+--------+----+
|  1|  24|    null|  24|
|  2|  25|    null|  25|
|  3|null|1/1/1973|  47|
|  4|null|6/6/1980|  39|
|  5|  46|    null|  46|
|  6|null|1/1/1971|  49|
+---+----+--------+----+

它保留不为空的 age 列,并计算 dobage 为空的今天之间的差异(以天为单位)。然后将结果转换为年(除以 365.25;您可能想确认这一点)然后 floored.

我觉得year differencemonths_between比较合适。只有当你需要 difference in days

时,我们才应该使用 datediff

接近-

 val data =
      """
        | id | age  |   dob
        |  1 | 24   |
        |  2 | 25   |
        |  3 |      | 1/1/1973
        |  4 |      | 6/6/1980
        |  5 | 46   |
        |  6 |      | 1/1/1971
      """.stripMargin

    val stringDS = data.split(System.lineSeparator())
      .map(_.split("\|").map(_.replaceAll("""^[ \t]+|[ \t]+$""", "")).mkString(","))
      .toSeq.toDS()
    val df = spark.read
      .option("sep", ",")
      .option("inferSchema", "true")
      .option("header", "true")
      .csv(stringDS)
    df.show(false)
    df.printSchema()

    /**
      * +---+----+--------+
      * |id |age |dob     |
      * +---+----+--------+
      * |1  |24  |null    |
      * |2  |25  |null    |
      * |3  |null|1/1/1973|
      * |4  |null|6/6/1980|
      * |5  |46  |null    |
      * |6  |null|1/1/1971|
      * +---+----+--------+
      *
      * root
      * |-- id: integer (nullable = true)
      * |-- age: integer (nullable = true)
      * |-- dob: string (nullable = true)
      */

查找年龄

  df.withColumn("diff",
      coalesce(col("age"),
      round(months_between(current_date(),to_date(col("dob"), "d/M/yyyy"),true).divide(12),2)
      )
     ).show()

    /**
      * +---+----+--------+-----+
      * | id| age|     dob| diff|
      * +---+----+--------+-----+
      * |  1|  24|    null| 24.0|
      * |  2|  25|    null| 25.0|
      * |  3|null|1/1/1973|47.42|
      * |  4|null|6/6/1980|39.99|
      * |  5|  46|    null| 46.0|
      * |  6|null|1/1/1971|49.42|
      * +---+----+--------+-----+
      */

round it to 0 if you want age in whole number

一样使用 months_between,但采用不同的方法:

  • 在我的 table 中,我还没有 'age' 列;
  • 为了四舍五入到完整年份,我使用 .cast('int')
from pyspark.sql import functions as F
df = df.withColumn('age', (F.months_between(current_date(), F.col('dob')) / 12).cast('int'))

如果系统日期是 UTC 而您的区域设置不同,则可能需要单独的日期函数:

from pyspark.sql import functions as F
def current_local_date():
    return F.from_utc_timestamp(F.current_timestamp(), 'Europe/Riga').cast('date')
df = df.withColumn('age', (F.months_between(current_local_date(), F.col('dob')) / 12).cast('int'))