Apache spark Spark RDD:如何最有效地计算统计数据?

Apache spark Spark RDD:如何最有效地计算统计数据?,apache-spark,pyspark,distributed-computing,rdd,apache-spark-mllib,Apache Spark,Pyspark,Distributed Computing,Rdd,Apache Spark Mllib,假设存在类似于以下内容的元组RDD: (key1, 1) (key3, 9) (key2, 3) (key1, 4) (key1, 5) (key3, 2) (key2, 7) ... 计算每个键对应的统计信息的最有效(理想情况下是分布式)方法是什么?(目前,我特别希望计算标准偏差/方差。)据我所知,我的选择包括: 使用:这种方法的优点是,如果认为有必要进行其他统计计算,则可以方便地在以后使用其他mllib.stat函数。但是,它在包含每列数据的VectorRDD上运行,因此据我所知,这种方法

假设存在类似于以下内容的元组RDD:

(key1, 1)
(key3, 9)
(key2, 3)
(key1, 4)
(key1, 5)
(key3, 2)
(key2, 7)
...
计算每个键对应的统计信息的最有效(理想情况下是分布式)方法是什么?(目前,我特别希望计算标准偏差/方差。)据我所知,我的选择包括:

  • 使用:这种方法的优点是,如果认为有必要进行其他统计计算,则可以方便地在以后使用其他
    mllib.stat
    函数。但是,它在包含每列数据的
    Vector
    RDD上运行,因此据我所知,这种方法需要在单个节点上收集每个键的完整值集,这对于大型数据集来说似乎并不理想。Spark
    Vector
    是否总是意味着
    Vector
    中的数据驻留在单个节点上的本地
  • 执行一次,然后:很可能是重洗牌
  • 执行,初始化一个新的,并用作序列和组合器函数:这是一种方法,避免了选项2中的
    groupByKey
    。然而,我还没有在PySpark中找到关于
    StatCounter
    的好文档
  • 我喜欢选项1,因为它使代码更具可扩展性,因为它可以方便地使用具有类似契约的其他MLLib函数进行更复杂的计算,但是如果
    向量
    输入固有地要求在本地收集数据集,然后限制代码可以有效操作的数据大小。在其他两个选项中,选项3看起来更有效,因为它避免了
    groupByKey
    ,但我希望证实这一点


    还有其他我没有考虑的选择吗?(我目前正在使用Python+PySpark,但如果存在语言差异,我也愿意使用Java/Scala解决方案。)

    您可以尝试
    reduceByKey
    。如果我们只想计算
    min()

    要计算
    平均值
    ,首先需要创建
    (值,1)
    元组,我们使用元组在
    reduceByKey
    操作中计算
    总和
    计数
    。最后,我们将它们彼此分开,得出
    平均值

    meanRDD = (rdd
               .mapValues(lambda x: (x, 1))
               .reduceByKey(lambda x, y: (x[0]+y[0], x[1]+y[1]))
               .mapValues(lambda x: x[0]/x[1]))
    
    meanRDD.collect()
    #Out[85]: [('key3', 5.5), ('key2', 5.0), ('key1', 3.3333333333333335)]
    
    对于
    方差
    ,您可以使用公式
    (平方和/计数)-(总和/计数)^2
    , 我们用以下方式翻译:

    varRDD = (rdd
              .mapValues(lambda x: (1, x, x*x))
              .reduceByKey(lambda x,y: (x[0]+y[0], x[1]+y[1], x[2]+y[2]))
              .mapValues(lambda x: (x[2]/x[0] - (x[1]/x[0])**2)))
    
    varRDD.collect()
    #Out[106]: [('key3', 12.25), ('key2', 4.0), ('key1', 2.8888888888888875)]
    
    我在虚拟数据中使用了
    double
    类型的值,而不是
    int
    ,以准确说明平均值和方差的计算:

    rdd = sc.parallelize([("key1", 1.0),
                          ("key3", 9.0),
                          ("key2", 3.0),
                          ("key1", 4.0),
                          ("key1", 5.0),
                          ("key3", 2.0),
                          ("key2", 7.0)])
    
    可能重复的
    rdd = sc.parallelize([("key1", 1.0),
                          ("key3", 9.0),
                          ("key2", 3.0),
                          ("key1", 4.0),
                          ("key1", 5.0),
                          ("key3", 2.0),
                          ("key2", 7.0)])