Scala 将timeseries数据映射到以前的数据点和平均值

Scala 将timeseries数据映射到以前的数据点和平均值,scala,apache-spark,Scala,Apache Spark,如果我有一个RDD,其中包含每分钟的卷数,例如 (("12:00" -> 124), ("12:01" -> 543), ("12:02" -> 102), ... ) 我想把它映射到一个数据集,这个数据集有这一分钟的体积,前一分钟的体积,前5分钟的平均体积。例如 (("12:00" -> (124, 300, 245.3)), ("12:01" -> (543, 124, 230.2)), ("12:02" -> (102, 543, 287.1)))

如果我有一个RDD,其中包含每分钟的卷数,例如

(("12:00" -> 124), ("12:01" -> 543), ("12:02" -> 102), ... )
我想把它映射到一个数据集,这个数据集有这一分钟的体积,前一分钟的体积,前5分钟的平均体积。例如

(("12:00" -> (124, 300, 245.3)),
("12:01" -> (543, 124, 230.2)),
("12:02" -> (102, 543, 287.1)))
输入RDD可以是
RDD[(DateTime,Int)]
,输出
RDD[(DateTime,(Int,Int,Float))]


做这件事的好方法是什么

转换为数据帧并使用窗口函数可以覆盖滞后、平均和可能的间隙:

import com.github.nscala\u time.time.Imports_
导入org.apache.spark.sql.Row
导入org.apache.spark.sql.functions.{lag,avg,when}
导入org.apache.spark.sql.expressions.Window
val fmt=DateTimeFormat.forPattern(“HH:mm:ss”)
val rdd=sc.parallelize(顺序(
("12:00:00" -> 124), ("12:01:00" -> 543), ("12:02:00" -> 102),
("12:30:00" -> 100), ("12:31:00" -> 101)
).map{case(ds,vol)=>(fmt.parseDateTime(ds,vol)})
val df=rdd
//窗口范围转换为毫秒
.map{case(dt,vol)=>(dt.getMillis,vol)}
.toDF(“ts”,“卷”)
val w=窗口.订单依据($“ts”)
val transformed=df.select(
$“ts”、$“卷”,
什么时候(
//检查我们是否有前一分钟的数据
(滞后($“ts”,1)。超过(w)-$“ts”)。等于(-60000),
//如果是,则获得滞后,否则为0
滞后($“卷”,1)。超过(w))。否则为(0)。别名(“上一卷”),
//窗口平均值
平均值($“数量”)。超过(w.Range-between(-300000,0))。别名(“平均值”))
//可以选择返回到RDD
转换的.map{
案例行(ts:Long,volume:Int,previousVolume:Int,average:Double)=>
(新日期时间(ts)->(卷、上一卷、平均值))
}

请注意,没有窗口分区的窗口函数效率很低

转换为数据帧并使用窗口函数可以覆盖滞后、平均和可能的间隙:

import com.github.nscala\u time.time.Imports_
导入org.apache.spark.sql.Row
导入org.apache.spark.sql.functions.{lag,avg,when}
导入org.apache.spark.sql.expressions.Window
val fmt=DateTimeFormat.forPattern(“HH:mm:ss”)
val rdd=sc.parallelize(顺序(
("12:00:00" -> 124), ("12:01:00" -> 543), ("12:02:00" -> 102),
("12:30:00" -> 100), ("12:31:00" -> 101)
).map{case(ds,vol)=>(fmt.parseDateTime(ds,vol)})
val df=rdd
//窗口范围转换为毫秒
.map{case(dt,vol)=>(dt.getMillis,vol)}
.toDF(“ts”,“卷”)
val w=窗口.订单依据($“ts”)
val transformed=df.select(
$“ts”、$“卷”,
什么时候(
//检查我们是否有前一分钟的数据
(滞后($“ts”,1)。超过(w)-$“ts”)。等于(-60000),
//如果是,则获得滞后,否则为0
滞后($“卷”,1)。超过(w))。否则为(0)。别名(“上一卷”),
//窗口平均值
平均值($“数量”)。超过(w.Range-between(-300000,0))。别名(“平均值”))
//可以选择返回到RDD
转换的.map{
案例行(ts:Long,volume:Int,previousVolume:Int,average:Double)=>
(新日期时间(ts)->(卷、上一卷、平均值))
}

请注意,没有窗口分区的窗口函数效率很低

您的数据是否完整,或者是否可能有一些丢失的记录?可能存在缺口,我将默认为零。我不介意解决方案是否能解决这个问题。在纯scala中,我会转换为DateTime并使用SortedMap。您的数据集有多大?我想这种方法可能会有所帮助,il会在时间序列上创建窗口:。我认为创建windows与您正在尝试做的非常接近,也就是说,将一个值与其在系列中的上一个/下一个值组合在一起。您的数据是否完整,或者是否可能有一些丢失的记录?可能存在差距,我将默认为零。我不介意解决方案是否能解决这个问题。在纯scala中,我会转换为DateTime并使用SortedMap。您的数据集有多大?我想这种方法可能会有所帮助,il会在时间序列上创建窗口:。我认为创建windows很接近您正在尝试做的事情,也就是说,将一个值与它在系列中的上一个/下一个内容组合在一起,这些内容都很有用。