如何用Scala集合方法实现皮尔逊相关系数计算方法?
解决皮尔逊相关系数中对应元素相乘求和的问题
嘿,完全不需要递归就能搞定这个问题!你卡在的对应x、y偏差相乘求和的部分,Scala里的zip方法正好是为这种场景设计的。
问题分析
你已经正确计算出了每个x与均值的偏差(x - x̅)和每个y与均值的偏差(y - y̅),但需要把两个列表对应位置的元素配对相乘,再把结果加起来。原代码里直接用xValues.map(...) * yValues.map(...)是不对的——Scala的列表没有定义乘法操作,这时候zip就能帮你把两个列表按位置组合成元组列表。
修正后的代码
先看调整后的完整实现,我会标注关键修改点:
def correlation[T](elements: List[T], property1: T => Double, property2: T => Double): Double = { val xValues = elements.map(property1) val yValues = elements.map(property2) // 注意:如果你的standardDeviation方法接收的是Double列表,这里不需要传property1/2,因为x/yValues已经是Double类型了 val Sx = standardDeviation(xValues) val Sy = standardDeviation(yValues) val n = xValues.size.toDouble val xMean = xValues.sum / n val yMean = yValues.sum / n // 核心修正:用zip配对偏差列表,再相乘求和 val deviationProductsSum = xValues.map(_ - xMean) .zip(yValues.map(_ - yMean)) .map { case (dx, dy) => dx * dy } .sum // 计算协方差和最终的皮尔逊相关系数 val covariance = deviationProductsSum / (n - 1) covariance / (Sx * Sy) }
关键步骤解释
针对你给出的测试数据集List((2,7), (8,12), (11,17)):
xValues.map(_ - xMean)得到List(-5, 1, 4),yValues.map(_ - yMean)得到List(-5, 0, 5)zip操作后会生成元组列表:List((-5,-5), (1,0), (4,5))map { case (dx, dy) => dx * dy }把每个元组的元素相乘,得到List(25, 0, 20)- 最后
sum就得到了你需要的45
另外还要注意原代码里的一个运算符优先级问题:(1/xSize-1)会被解析成(1/xSize) - 1,这和你需要的1/(xSize - 1)完全不同,我在修正后的代码里改成了正确的形式。
测试调用示例
用你的测试数据调用这个方法(附标准差实现参考):
// 参考的标准差实现(样本标准差,除以n-1) def standardDeviation(values: List[Double]): Double = { val mean = values.sum / values.size.toDouble val squaredDeviations = values.map(v => math.pow(v - mean, 2)) math.sqrt(squaredDeviations.sum / (values.size - 1)) } // 测试调用 val data = List((2,7), (8,12), (11,17)) val result = correlation(data, _._1.toDouble, _._2.toDouble) println(result) // 输出约0.982,符合预期
内容的提问来源于stack exchange,提问作者Klock123
相关产品推荐
相关产品推荐

