web-dev-qa-db-ja.com

Scala:固定ウィンドウでのリストの移動合計の計算

Scalaは初めてですが、リストの固定ウィンドウで移動合計を計算したいと思います。

例:リストの値(1.0、2.0、3.0、6.0、7.0、8.0、12.0、9.0、4.0、1.0)と期間4を指定すると、関数は(1.0、3.0、6.0、12.0、18.0、 24.0、33.0、36.0、33.0、26.0)

List.size <periodの場合、累積合計を返します。

私はいくつかの試みをしました

def mavg(values: List[Double], period: Int): List[Double] = {
  if (values.size <= period) (values.sum ) :: List.fill(period -1)(values.sum ) else {
      val rest: List[Double] = mavg(values.tail, period)
      (rest.head + ((values.head - values(period)))):: rest
  }
}

しかし、私は得ました

List(12.0, 18.0, 24.0, 33.0, 36.0, 33.0, 26.0, 26.0, 26.0, 26.0

これは正しくありません。結果を得るためにPysparkを使用したくありません。誰か助けてもらえますか?

どうもありがとう。

8
FlyUFalcon

answer に似た別のアプローチ@ User9123による

違いは、スライディングウィンドウ内のすべての要素の合計を計算するのではなく、その合計から最後のウィンドウヘッドの値を減算し、次のウィンドウヘッドの値を加算して、次のローリング合計を生成することです。これは大きなウィンドウの場合により効率的です。

def rollingSum[N](values: Seq[N], period: Int)(
    implicit num: Numeric[N]
): Seq[N] = {
  import num._
  values match {
    case values if period == 1 => values // Can't slide on period 1
    case head :: tail if period < values.size =>
      (Seq.fill(period - 2)(num.zero) ++ (values)) // zero padding
        .sliding(period)
        .foldLeft((num.zero, Seq(head))) { // Use a Tuple to store previous head
          case ((prevHead, acc), y) => {
            (y.head, acc :+ acc.last - prevHead + y.last) // do the magic
          }
        }
        ._2 // only return the result
    case head :: tail => tail.scanLeft(head)(_ + _) // Regular cummulative sum
    case Nil          => Nil
  }
}

また、処理する必要がある特殊なケースにいくつかのガードを追加し、すべてのNumericタイプの汎用関数にしました。

Here's いくつかのテストケースを含む実行例。

1
CervEd