如何在Scala中计算滚动统计

时间:2018-09-23 15:30:09

标签: scala collections

我在使用Python处理数据帧方面有一定的知识,但是在使用Scala编写程序时我面临以下问题。

case class Transaction(
      transactionId: String,
      accountId: String,
      transactionDay: Int,
      category: String,
      transactionAmount: Double)

我创建了这样的列表:

  val transactions: List[Transaction] = transactionslines.map {           
      line => val split = line.split(',')
      Transaction(split(0), split(1), split(2).toInt, split(3),split(4).toDouble)
      }.toList

列表内容:

  Transaction(T000942,A38,28,EE,694.54)
  Transaction(T000943,A35,28,CC,828.57)
  Transaction(T000944,A26,28,DD,290.18)
  Transaction(T000945,A17,28,CC,627.62)
  Transaction(T000946,A42,28,FF,616.73)
  Transaction(T000947,A20,28,FF,86.84)
  Transaction(T000948,A14,28,BB,620.32)
  Transaction(T000949,A14,28,AA,260.02)
  Transaction(T000950,A32,28,AA,600.34)

任何人都可以帮助我如何计算前五天交易的每个帐号的统计信息,但不包括正在计算当日统计信息的交易。例如,在第10天,您应该只考虑第5天到第9天之间的交易(这称为5天的滚动时间窗口)。我需要计算的统计数据是:

•每个帐户最近5天的交易类型“ AA”的交易总金额

•每个帐户最近5天的平均交易金额

理想情况下,每个帐户ID每天输出应包含一行,并且每行应包含每个计算出的统计信息:

前5天的代码如下:

val a = transactions.
        filter(trans => trans.transactionDay <= 5).
        groupBy(_.accountId).
        mapValues(trans => (trans.map(amount => 
        amount.transactionAmount).sum/trans.map(amount => 
        amount.transactionAmount).size,trans.filter(trans => 
        trans.category == "AA").map(amount => 
        amount.transactionAmount).sum)
a.foreach{println}

我想知道是否有任何一种优雅的方式来计算这些统计数据。请注意,交易日的范围是[1..29],因此理想情况下,我希望有一个代码可以计算直到29天(不仅是前5天)的那些滚动统计信息。

非常感谢!

1 个答案:

答案 0 :(得分:0)

也许不是“优雅”,但以下内容将由accountID提供特定一天的两个所需统计信息:

def calcStats(ts: List[Transaction], day: Int): Map[String, (Double, Double)] = {
  // all transactions for date range, grouped by accountID
  val atsById = ts
   .filter(trans => trans.transactionDay >= day - 5 && trans.transactionDay < day)
   .groupBy(_.accountId)
  // "AA" transactions summmed by account id
  val aaSums = atsById.mapValues(_.filter(_.category == "AA"))
                      .mapValues(_.map(_.transactionAmount).sum)
  // sum of all transactions by account id
  val allSums = atsById.mapValues(_.map(_.transactionAmount).sum)
  // count of all transactions by account id
  val allCounts = atsById.mapValues(_.length)
  // output is Map(account id -> (aaSum, allAve))
  allSums.map { case (id, sum) => 
    id -> (aaSums.getOrElse(id, 0.0), sum / allCounts(id)) }
}

示例(使用您提供的数据):

scala> calcStats(transactions, 30)
res13: Map[String,(Double, Double)] = Map(A32 -> (600.34,600.34), A26 -> 
(0.0,290.18), A38 -> (0.0,694.54), A20 -> (0.0,86.84), A17 -> (0.0,627.62), 
A42 -> (0.0,616.73), A35 -> (0.0,828.57), A14 -> (260.02,440.17))

scala> calcStats(transactions, 1)
res14: Map[String,(Double, Double)] = Map()