Spark:所有键的值总和?

时间:2016-02-23 23:26:04

标签: scala apache-spark

假设我有包含userId的键值对,以及表示用户具有属性的布尔整数列表:

userId     hasAttrA  hasAttrB  hasAttrC
joe               1         0         1
jack              1         1         0
jane              0         0         1
jeri              1         0         0

在Scala代码中,数据结构如下所示:

var data = Array(("joe",  List(1, 0, 1)),
                 ("jack", List(1, 1, 0)),
                 ("jane", List(0, 0, 1)),
                 ("jeri", List(1, 0, 0)))

我想计算具有这些属性的所有用户的比例。但是,这个计算要求我可以总结所有的键,我不知道该怎么做。所以我想计算:

  1. 有多少用户?
  2. data.size // 4

    1. 有多少用户拥有属性A?
    2. 应该是:sum(hasAttrA)/ data.size = 3/4 = 0.75

      1. 有多少用户拥有属性B?
      2. 应该是:sum(hasAttrB)/ data.size = 1/4 = 0.25

        如何计算所有键的总和,以及如何计算最终百分比?

        编辑2016年2月24日:

        我可以手动查找各列的总和,如下所示:

        var sumAttributeA = data.map{ case(id, attributeList) => attributeList(0)}.sum
        var sumAttributeB = data.map{ case(id, attributeList) => attributeList(1)}.sum
        var sumAttributeC = data.map{ case(id, attributeList) => attributeList(2)}.sum
        
        var fractionAttributeA = sumAttributeA.toDouble/data.size
        //fractionAttributeA: Double = 0.75
        var fractionAttributeB = sumAttributeB.toDouble/data.size
        //fractionAttributeB: Double = 0.25
        

1 个答案:

答案 0 :(得分:2)

一种可能的解决方案:

import org.apache.spark.mllib.stat.MultivariateOnlineSummarizer
import org.apache.spark.mllib.linalg.Vectors

val stats = sc.parallelize(data)
  .values
  .map(xs => Vectors.dense(xs.toArray.map(_.toDouble)))
  .aggregate(new MultivariateOnlineSummarizer)(_ add _, _ merge _)

(stats.count, stats.mean)
// (Long, org.apache.spark.mllib.linalg.Vector) = (4,[0.75,0.25,0.5])

您也可以手动应用类似的操作:

val (total, sums) = sc.parallelize(data).values
  .map(vs => (1L, vs.map(_.toLong)))
  .reduce{
    case ((cnt1, vs1), (cnt2, vs2)) => 
    (cnt1 + cnt2, vs1.zip(vs2).map{case (x, y) => x + y})}

sums.map(_.toDouble / total)

但它会有更糟糕的数字属性。