Apache Spark:指数移动平均线

时间:2015-11-27 14:15:53

标签: scala apache-spark hive apache-spark-sql spark-dataframe

我在Spark / Scala中编写一个应用程序,我需要计算列的指数移动平均值。

EMA_t = (price_t * 0.4) + (EMA_t-1 * 0.6)

我面临的问题是我需要先前计算的同一列的值(EMA_t-1)。通过mySQL可以通过使用MODEL或创建一个EMA列来实现,然后你可以每行更新一行,但是我已经尝试了这个并且不能使用Spark SQL或Hive Context ...有什么方法我可以访问此EMA_t-1?

我的数据如下:

timestamp price    
15:31 132.3 
15:32 132.48 
15:33 132.76 
15:34 132.66
15:35 132.71 
15:36 132.52
15:37 132.63
15:38 132.575
15:39 132.57

所以我需要添加一个新列,其中我的第一个值只是第一行的价格,然后我需要使用前一个值:EMA_t =(price_t * 0.4)+(EMA_t-1 * 0.6)计算该列中的以下行。 我的EMA专栏必须是:

EMA
132.3
132.372
132.5272
132.58032
132.632192
132.5873152
132.6043891
132.5926335
132.5835801

我目前正在尝试使用Spark SQL和Hive,但如果可以通过其他方式实现,那么这将是受欢迎的!我也想知道如何用Spark Streaming做到这一点。我的数据在数据框中,我使用的是Spark 1.4.1。

非常感谢您提供的任何帮助!

2 个答案:

答案 0 :(得分:0)

要回答您的问题:

  

我面临的问题是我需要同一列的先前计算出的值(EMA_t-1)

我认为您需要两个功能:Window和Lag。 (为方便起见,在计算EMA时,我也将null值设为零)

my_window = Window.orderBy("timestamp")

df.withColumn("price_lag_1",when(lag(col("price"),1).over(my_window).isNull,lit(0)).otherwise(lag(col("price"),1).over(my_window)))

我也是Spark Scala的新手,并且正在尝试查看是否可以定义UDF进行指数平均。但目前来看,一个明显的解决方法是手动将所有滞后列加起来(0.4 * lag0 + 0.4 * 0.6 * lag1 + 0.4 * 0.6 ^ 2 * lag2 ...)

df.withColumn("ema_price", 
price * lit(0.4) * Math.pow(0.6,0) + 
lag(col("price"),1).over(my_window) * 0.4 * Math.pow(0.6,1) +
lag(col("price"),2).over(my_window) * 0.4 * Math.pow(0.6,2)  + .... )

我忽略了when.other,以使其更加清晰。这种方法现在对我有用。

----更新----

def emaFunc (y: org.apache.spark.sql.Column, group: org.apache.spark.sql.Column, order: org.apache.spark.sql.Column, beta: Double, lookBack: Int) : org.apache.spark.sql.Column = {
  val ema_window = Window.partitionBy(group).orderBy(order)
  var i = 1
  var result = y
  while (i < lookBack){
    result =  result + lit(1) * ( when(lag(y,i).over(ema_window).isNull,lit(0)).otherwise(lag(y,i).over(ema_window)) * beta * Math.pow((1-beta),i) 
    - when(lag(y,i).over(ema_window).isNull,lit(0)).otherwise(y * beta * Math.pow((1-beta),i))   )
    i = i + 1
  }
  return result } 

通过使用此功能,您应该能够获得价格类似的EMA。

df.withColumn("one",lit(1))
  .withColumn("ema_price", emaFunc('price,'one,'timestamp,0.1,10)

这将回溯10天,并计算beta = 0.1的估算EMA。列“一个”只是一个占位符,因为您没有分组列。

答案 1 :(得分:-1)

您应该可以使用1.4中引入的Spark Window函数执行此操作:https://databricks.com/blog/2015/07/15/introducing-window-functions-in-spark-sql.html

w = Window()。partitionBy()。orderBy(col(“timestamp”)) df.select(“*”,lag(“price”)。over(w).alias(“ema”))

这将为您选择最后一个价格,以便您可以对其进行计算