web-dev-qa-db-fra.com

Apache Spark Moyenne mobile

J'ai un énorme fichier en HDFS contenant des points de données de séries chronologiques (prix Yahoo Stock).

Je veux trouver la moyenne mobile de la série chronologique, comment dois-je faire pour écrire le travail Apache Spark pour le faire).

36
Ahmed Shabib

Vous pouvez utiliser la fonction coulissante de MLLIB qui fait probablement la même chose que la réponse de Daniel. Vous devrez trier les données par heure avant d'utiliser la fonction coulissante.

import org.Apache.spark.mllib.rdd.RDDFunctions._

sc.parallelize(1 to 100, 10)
  .sliding(3)
  .map(curSlice => (curSlice.sum / curSlice.size))
  .collect()
29
Arvind

La moyenne mobile est un problème délicat pour Spark et tout système distribué. Lorsque les données sont réparties sur plusieurs machines, certaines fenêtres temporelles traversent les partitions. Nous devons dupliquer les données au début des partitions, afin que le calcul de la moyenne mobile par partition donne une couverture complète.

Voici une façon de le faire dans Spark. Les données d'exemple:

val ts = sc.parallelize(0 to 100, 10)
val window = 3

Un simple partitionneur qui place chaque ligne dans la partition que nous spécifions par la clé:

class StraightPartitioner(p: Int) extends org.Apache.spark.Partitioner {
  def numPartitions = p
  def getPartition(key: Any) = key.asInstanceOf[Int]
}

Créez les données avec le premier window - 1 lignes copiées dans la partition précédente:

val partitioned = ts.mapPartitionsWithIndex((i, p) => {
  val overlap = p.take(window - 1).toArray
  val spill = overlap.iterator.map((i - 1, _))
  val keep = (overlap.iterator ++ p).map((i, _))
  if (i == 0) keep else keep ++ spill
}).partitionBy(new StraightPartitioner(ts.partitions.length)).values

Il suffit de calculer la moyenne mobile sur chaque partition:

val movingAverage = partitioned.mapPartitions(p => {
  val sorted = p.toSeq.sorted
  val olds = sorted.iterator
  val news = sorted.iterator
  var sum = news.take(window - 1).sum
  (olds Zip news).map({ case (o, n) => {
    sum += n
    val v = sum
    sum -= o
    v
  }})
})

En raison des segments en double, il n'y aura pas de lacunes dans la couverture.

scala> movingAverage.collect.sameElements(3 to 297 by 3)
res0: Boolean = true
22
Daniel Darabos

Spark 1.4 a introduit les fonctions de fenêtrage , ce qui signifie que vous pouvez faire la moyenne mobile comme suit ajuster le fenêtrage avec des lignesEntre :

val schema = Seq("id", "cykle", "value")
 val data = Seq(
        (1, 1, 1),
        (1, 2, 11),
        (1, 3, 1),
        (1, 4, 11),
        (1, 5, 1),
        (1, 6, 11),
        (2, 1, 1),
        (2, 2, 11),
        (2, 3, 1),
        (2, 4, 11),
        (2, 5, 1),
        (2, 6, 11)
      )

val dft = sc.parallelize(data).toDF(schema: _*)

dft.select('*).show

// PARTITION BY id  ORDER BY cykle ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING (5)
val w = Window.partitionBy("id").orderBy("cykle").rowsBetween(-2, 2)

val x = dft.select($"id",$"cykle",avg($"value").over(w))
x.show

Sortie (en zeppelin):

schema: Seq[String] = List(id, cykle, value)
data: Seq[(Int, Int, Int)] = List((1,1,1), (1,2,11), (1,3,1), (1,4,11), (1,5,1), (1,6,11), (2,1,1), (2,2,11), (2,3,1), (2,4,11), (2,5,1), (2,6,11))
dft: org.Apache.spark.sql.DataFrame = [id: int, cykle: int, value: int]
+---+-----+-----+
| id|cykle|value|
+---+-----+-----+
|  1|    1|    1|
|  1|    2|   11|
|  1|    3|    1|
|  1|    4|   11|
|  1|    5|    1|
|  1|    6|   11|
|  2|    1|    1|
|  2|    2|   11|
|  2|    3|    1|
|  2|    4|   11|
|  2|    5|    1|
|  2|    6|   11|
+---+-----+-----+
w: org.Apache.spark.sql.expressions.WindowSpec = org.Apache.spark.sql.expressions.WindowSpec@55cd666f
x: org.Apache.spark.sql.DataFrame = [id: int, cykle: int, 'avg(value) WindowSpecDefinition ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING: double]
+---+-----+-------------------------------------------------------------------------+
| id|cykle|'avg(value) WindowSpecDefinition ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING|
+---+-----+-------------------------------------------------------------------------+
|  1|    1|                                                        4.333333333333333|
|  1|    2|                                                                      6.0|
|  1|    3|                                                                      5.0|
|  1|    4|                                                                      7.0|
|  1|    5|                                                                      6.0|
|  1|    6|                                                        7.666666666666667|
|  2|    1|                                                        4.333333333333333|
|  2|    2|                                                                      6.0|
|  2|    3|                                                                      5.0|
|  2|    4|                                                                      7.0|
|  2|    5|                                                                      6.0|
|  2|    6|                                                        7.666666666666667|
+---+-----+————————————————————————————————————+
15
oluies