如何在Pyspark数据框中将多列(如时间、年份、月份和日期)转换为日期时间格式。

4

数据帧有4个列,分别是年、月、日和hhmm。

hhmm代表小时和分钟连接在一起的格式, 例如:10:30相当于1030。

dd=spark.createDataFrame([(2019,2,13,1030),(2018,2,14,1000),(2029,12,13,0300)],["Year","month","date","hhmm"])
dd.collect()

预期在Pyspark数据框中以日期时间格式输出

dd.collect()
2019-02-13 10:30:00 
2018-2-14 10:00:00  
2019-12-13 03:00:00 

1
您可以使用 concat() 进行字符串连接,然后使用 unix_timestamp()from_unixtime() 将其转换为 timestamp - samkart
1
一旦您将单个数字的日期/月份转换为两位数,以及将hhmm转换为四位数后,您可以使用from_unixtime(unix_timestamp(col('concatedcol'), 'yyyy-MM-dd HHmm'), 'yyyy-MM-dd HH:mm:ss')。我正在使用您上面提到的代码格式。 - samkart
如果您从数据库源获取数据,则只需注意一位数字到两位数字的日期和月份。 - samkart
我来自R语言背景,对pyspark还不熟悉。在R中有一个叫做mktime(year = 1970, month = 10, day = 10, hour = 02, minute =30, second = 0, msec = 0)的函数,它的结果是1970/10/10 02:30:00。在pyspark中是否有类似的函数呢? - premon
谢谢samkart,我得到了我期望的代码输出。 dt.select(to_timestamp(dt.datetime1,'yyyy-MM-dd HH:mm').alias('datetime1')).collect()``` - premon
显示剩余7条评论
2个回答

3
对于Spark 3+,您可以使用make_timestamp函数:
from pyspark.sql import functions as F

dd = dd.withColumn(
    "time",
    F.expr("make_timestamp(Year, month, date, substr(hhmm,1,2), substr(hhmm,3,2), 0)")
)

dd.show(truncate=False)

#+----+-----+----+----+-------------------+
#|Year|month|date|hhmm|time               |
#+----+-----+----+----+-------------------+
#|2019|2    |13  |1030|2019-02-13 10:30:00|
#|2018|2    |14  |1000|2018-02-14 10:00:00|
#|2029|12   |13  |0300|2029-12-13 03:00:00|
#+----+-----+----+----+-------------------+

2
您的数据存在问题,整数0300无法按照所需格式加载,对我而言它被加载为了192,因此您需要首先将其作为字符串加载,并在加载时使用模式指定数据类型。请参考文档。例如,对于一个.csv文件:
from pyspark.sql import DataFrameReader
from pyspark.sql.types import *

schema = StructType([StructField("Year", StringType(), True), StructField("month", StringType(), True), StructField("date", StringType(), True), StructField("hhmm", StringType(), True)])

dd = DataFrameReader.csv(path='your/data/path', schema=schema)

然后您需要修复数据格式并将其转换为时间戳:
from pyspark.sql import functions as F

dd = spark.createDataFrame([('2019','2','13','1030'),('2018','2','14','1000'),('2029','12','13','300')],["Year","month","date","hhmm"])

dd = (dd.withColumn('month', F.when(F.length(F.col('month')) == 1, F.concat(F.lit('0'), F.col('month'))).otherwise(F.col('month')))
        .withColumn('date', F.when(F.length(F.col('date')) == 1, F.concat(F.lit('0'), F.col('date'))).otherwise(F.col('date')))
        .withColumn('hhmm', F.when(F.length(F.col('hhmm')) == 1, F.concat(F.lit('000'), F.col('hhmm')))
                             .when(F.length(F.col('hhmm')) == 2, F.concat(F.lit('00'), F.col('hhmm')))
                             .when(F.length(F.col('hhmm')) == 3, F.concat(F.lit('0'), F.col('hhmm')))
                             .otherwise(F.col('hhmm')))
        .withColumn('time', F.to_timestamp(F.concat(*dd.columns), format='yyyyMMddHHmm'))
     )

dd.show()

+----+-----+----+----+-------------------+
|Year|month|date|hhmm|               time|
+----+-----+----+----+-------------------+
|2019|   02|  13|1030|2019-02-13 10:30:00|
|2018|   02|  14|1000|2018-02-14 10:00:00|
|2029|   12|  13|0300|2029-12-13 03:00:00|
+----+-----+----+----+-------------------+

很好的答案。我们如何将年份转换为仅保留最后两位数字? - Kenny
@Kenny 你可以将它转换为字符串,然后使用子字符串函数。 - Henrique Florencio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接