【问题标题】:Spark DataFrame TimestampType - how to get Year, Month, Day values from field?Spark DataFrame TimestampType - 如何从字段中获取年、月、日值?
【发布时间】:2015-09-06 02:08:58
【问题描述】:

我有带有 take(5) 顶行的 Spark DataFrame,如下所示:

[Row(date=datetime.datetime(1984, 1, 1, 0, 0), hour=1, value=638.55),
 Row(date=datetime.datetime(1984, 1, 1, 0, 0), hour=2, value=638.55),
 Row(date=datetime.datetime(1984, 1, 1, 0, 0), hour=3, value=638.55),
 Row(date=datetime.datetime(1984, 1, 1, 0, 0), hour=4, value=638.55),
 Row(date=datetime.datetime(1984, 1, 1, 0, 0), hour=5, value=638.55)]

它的架构定义为:

elevDF.printSchema()

root
 |-- date: timestamp (nullable = true)
 |-- hour: long (nullable = true)
 |-- value: double (nullable = true)

如何从“日期”字段中获取年、月、日值?

【问题讨论】:

    标签: python timestamp apache-spark pyspark


    【解决方案1】:

    从 Spark 1.5 开始,您可以使用许多日期处理函数:

    import datetime
    from pyspark.sql.functions import year, month, dayofmonth
    
    elevDF = sc.parallelize([
        (datetime.datetime(1984, 1, 1, 0, 0), 1, 638.55),
        (datetime.datetime(1984, 1, 1, 0, 0), 2, 638.55),
        (datetime.datetime(1984, 1, 1, 0, 0), 3, 638.55),
        (datetime.datetime(1984, 1, 1, 0, 0), 4, 638.55),
        (datetime.datetime(1984, 1, 1, 0, 0), 5, 638.55)
    ]).toDF(["date", "hour", "value"])
    
    elevDF.select(
        year("date").alias('year'), 
        month("date").alias('month'), 
        dayofmonth("date").alias('day')
    ).show()
    # +----+-----+---+
    # |year|month|day|
    # +----+-----+---+
    # |1984|    1|  1|
    # |1984|    1|  1|
    # |1984|    1|  1|
    # |1984|    1|  1|
    # |1984|    1|  1|
    # +----+-----+---+
    

    您可以像使用任何其他 RDD 一样使用简单的map

    elevDF = sqlContext.createDataFrame(sc.parallelize([
            Row(date=datetime.datetime(1984, 1, 1, 0, 0), hour=1, value=638.55),
            Row(date=datetime.datetime(1984, 1, 1, 0, 0), hour=2, value=638.55),
            Row(date=datetime.datetime(1984, 1, 1, 0, 0), hour=3, value=638.55),
            Row(date=datetime.datetime(1984, 1, 1, 0, 0), hour=4, value=638.55),
            Row(date=datetime.datetime(1984, 1, 1, 0, 0), hour=5, value=638.55)]))
    
    (elevDF
     .map(lambda (date, hour, value): (date.year, date.month, date.day))
     .collect())
    

    结果是:

    [(1984, 1, 1), (1984, 1, 1), (1984, 1, 1), (1984, 1, 1), (1984, 1, 1)]
    

    顺便说一句:datetime.datetime 无论如何都会存储一个小时,因此将其单独保存似乎是在浪费内存。

    【讨论】:

    • 好的,谢谢,它以前不适合我,但现在可以使用 elevDF.map(lambda (date, value): (date.year, value))
    • 谢谢!正是我需要的。对于未来的读者,reference for extraction time as well
    【解决方案2】:

    您可以使用pyspark.sql.functions中的函数:yearmonthetc等函数

    参考这里:https://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.DataFrame

    from pyspark.sql.functions import *
    
    newdf = elevDF.select(year(elevDF.date).alias('dt_year'), month(elevDF.date).alias('dt_month'), dayofmonth(elevDF.date).alias('dt_day'), dayofyear(elevDF.date).alias('dt_dayofy'), hour(elevDF.date).alias('dt_hour'), minute(elevDF.date).alias('dt_min'), weekofyear(elevDF.date).alias('dt_week_no'), unix_timestamp(elevDF.date).alias('dt_int'))
    
    newdf.show()
    
    
    +-------+--------+------+---------+-------+------+----------+----------+
    |dt_year|dt_month|dt_day|dt_dayofy|dt_hour|dt_min|dt_week_no|    dt_int|
    +-------+--------+------+---------+-------+------+----------+----------+
    |   2015|       9|     6|      249|      0|     0|        36|1441497601|
    |   2015|       9|     6|      249|      0|     0|        36|1441497601|
    |   2015|       9|     6|      249|      0|     0|        36|1441497603|
    |   2015|       9|     6|      249|      0|     1|        36|1441497694|
    |   2015|       9|     6|      249|      0|    20|        36|1441498808|
    |   2015|       9|     6|      249|      0|    20|        36|1441498811|
    |   2015|       9|     6|      249|      0|    20|        36|1441498815|
    

    【讨论】:

      【解决方案3】:

      其实我们真的不需要导入任何python库。我们可以使用简单的 SQL 来分隔年、月、日。看下面的例子,

      +----------+
      |       _c0|
      +----------+
      |1872-11-30|
      |1873-03-08|
      |1874-03-07|
      |1875-03-06|
      |1876-03-04|
      |1876-03-25|
      |1877-03-03|
      |1877-03-05|
      |1878-03-02|
      |1878-03-23|
      |1879-01-18|
      

      我的数据框中有一个日期列,其中包含日期、月份和年份,并假设我只想从该列中提取年份。

      df.createOrReplaceTempView("res")
      sqlDF = spark.sql("SELECT EXTRACT(year from `_c0`) FROM res ")
      

      我在这里创建一个临时视图并使用这一行存储年份值,输出将是,

      +-----------------------+
      |year(CAST(_c0 AS DATE))|
      +-----------------------+
      |                   1872|
      |                   1873|
      |                   1874|
      |                   1875|
      |                   1876|
      |                   1876|
      |                   1877|
      |                   1877|
      |                   1878|
      |                   1878|
      |                   1879|
      |                   1879|
      |                   1879|
      

      【讨论】:

      • 请注意,这只适用于 Spark >= 3.0
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多