基于Scala与Spark MLlib:线性回归中日期转连续数值的实现咨询
解决Spark Scala中日期转数值用于线性回归的问题
没问题,我来帮你搞定这个日期转换的需求!要把日期转换成以最早日期为0的递增数值,咱们可以分三步在Spark Scala里实现,全程用Spark的内置函数就能搞定,不需要复杂的自定义逻辑。
步骤1:把字符串日期转换成Spark日期类型
首先得把你DataFrame里的字符串格式日期(比如01-01-2017)转换成Spark原生的DateType,这样才能进行后续的日期计算。这里要注意指定正确的日期格式,你的示例是dd-MM-yyyy(日-月-年),所以用to_date函数的时候要对应上:
import org.apache.spark.sql.functions._ import org.apache.spark.sql.types.DateType // 假设你的原始DataFrame叫originalDF val dfWithParsedDate = originalDF .withColumn("date", to_date($"date", "dd-MM-yyyy")) // 解析字符串为日期 .na.drop(Seq("date")) // 过滤掉解析失败的无效日期,避免后续报错
步骤2:获取全局最早日期作为基准
接下来要找出整个DataFrame里的最小日期,这个日期就是我们的基准值(对应数值0)。为了提升性能,我们可以把这个最小日期广播出去,避免每个分区重复计算:
// 获取全局最小日期 val earliestDate = dfWithParsedDate.agg(min("date")).first().getDate(0) // 广播这个值,优化分布式计算的性能 val broadcastEarliestDate = spark.sparkContext.broadcast(earliestDate)
步骤3:计算每个日期与基准日期的天数差
最后一步就是用datediff函数计算每个日期和基准日期的天数差,这个差值就是我们需要的数值特征——最早日期会得到0,后续日期按天数递增:
val dfWithDateNum = dfWithParsedDate .withColumn("date_num", datediff($"date", lit(broadcastEarliestDate.value)))
验证一下结果
拿你的示例数据来说:
| date | id | date_num |
|---|---|---|
| 01-01-2017 | 12 | 334 |
| 01-02-2016 | 13 | 0 |
| 05-05-2016 | 22 | 94 |
这样得到的date_num字段就是完全符合你需求的数值特征,可以和其他独热编码后的字段一起,组成线性回归模型的输入特征向量啦。
补充:另一种时间戳方式(可选)
如果你偏好使用时间戳来计算,也可以用unix_timestamp转成秒数,再减去基准时间戳,最后除以86400转换成天数:
val dfWithUnix = dfWithParsedDate .withColumn("unix_timestamp", unix_timestamp($"date")) val earliestUnix = dfWithUnix.agg(min("unix_timestamp")).first().getLong(0) val dfWithDateNum = dfWithUnix .withColumn("date_num", ($"unix_timestamp" - earliestUnix) / 86400)
两种方法结果一致,不过datediff更直观,推荐优先使用。
内容的提问来源于stack exchange,提问作者Interstellar
相关产品推荐
相关产品推荐

