Scala 多元数组求和

Scala multivariate array sum

我正在使用多变量自举法计算某些比率的置信区间,每个变量都有不同的置信区间。

case class Limits(lowerLimit: Double, upperLimit: Double, confidenceInterval: Double)

case class CI(c85: Limits, c90: Limits, c95: Limits, c99: Limits)

为了bootstrapping,我运行循环了100次

val arrCIRatio: Array[CI] = Array()
var ci85: Limits = new Limits(0.0, 0.0, 0.0)
var ci90: Limits = new Limits(0.0, 0.0, 0.0)
var ci95: Limits = new Limits(0.0, 0.0, 0.0)
var ci99: Limits = new Limits(0.0, 0.0, 0.0)

val a = Array(1,2,3,4,5,6,7,8,9,10)
val rg = new scala.util.Random(100)

 for(iteration <- 1 to 100){
    val i= rg.nextInt(10)      
    ci85 = getInterval(a(i), 0.85)
    ci90 = getInterval(a(i), 0.90)
    ci95 = getInterval(a(i), 0.95)
    ci99 = getInterval(a(i), 0.99)

    arrCIRatio(iteration) = new CI(ci85,ci90,ci95,ci99)
}

循环结束后,我想对所有ci85,ci89,ci95,ci99的CI数组内的每个上限和下限取平均值。

我可以用 foldLeft 来计算总和

x.foldLeft(0.0)( (x, y) => x + y.lowerLimit, x.foldLeft(0.0)( (x, y) => x + y.upperLimit

或天真的方式:

var avgci85: Limits = new Limits(0.0, 0.0, 0.0)
var avgci90: Limits = new Limits(0.0, 0.0, 0.0)
var avgci95: Limits = new Limits(0.0, 0.0, 0.0)
var avgci99: Limits = new Limits(0.0, 0.0, 0.0)

 for(ci <- arrCIRatio){  
    ci85 = ci.c85
    ci90 = ci.c90
    ci95 = ci.c95
    ci99 = ci.c99

    avgci85 = new Limits(avgci85.lowerLimit + ci85.lowerLimit, avgci85.upperLimit + ci85.upperLimit, 0.85) 
    avgci90 = new Limits(avgci90.lowerLimit + ci90.lowerLimit, avgci90.upperLimit + ci85.upperLimit, 0.90) 
    avgci95 = new Limits(avgci95.lowerLimit + ci95.lowerLimit, avgci95.upperLimit + ci85.upperLimit, 0.95) 
    avgci99 = new Limits(avgci99.lowerLimit + ci99.lowerLimit, avgci99.upperLimit + ci85.upperLimit, 0.99) 
}

但我必须对至少 10 个变量以及数组中的所有 CI 执行相同的过程。 所以最后,对于 1 个变量,它将是一个 10000 x 4 x 3 的 3 维数组。 我不知道如何对该数组内的所有变量求和,例如对数组中ci85的所有下限求和。如果有人能帮忙解决就好了。

也许只需为您的 CILimits 创建 method/operator,这样您就可以合并两个实例?类似的东西:

case class Limits(lowerLimit: Double, upperLimit: Double, confidenceInterval: Double) {
  // operator |+| would allow us to combine two limits
  def |+|(l: Limits): Limits = Limits(l.lowerLimit + lowerLimit, l.upperLimit + upperLimit, confidenceInterval)
 // I don't know what should be done in case of attempt of combining two limits with different confidenceInterval. 
 // Maybe it's a sign that every kind of Limits should be separate case class extending the common trait
}

object Limits {
  val Zero = new Limits(0,0,0) //zero element for convienience
}

case class CI(c85: Limits, c90: Limits, c95: Limits, c99: Limits) {
  //same operator for CI, we use |+| from Limits to combine them
  def |+|(c: CI): CI = CI(c.c85 |+| c85, c.c90 |+| c90, c.c95 |+| c95, c.c99 |+| c99)
}

object CI {
  val Zero = new CI(Limits.Zero, Limits.Zero, Limits.Zero, Limits.Zero)
}

那么您就可以轻松地弃牌 CI:

arrCIRatio.fold(CI.Zero)(_ |+| _)

我们所做的叫做monoid。您可以使用 type类 实现它,而不是在 case 类 中实现 |+|Zero (如文章)。