Python Spark combineByKey Average

时间:2016-10-23 20:22:19

标签: python-3.x apache-spark pyspark

我试图在Python中学习Spark,并坚持使用combineByKey来平均键值对中的值。事实上,我的混淆不是combineByKey语法,而是后来的。典型的例子(来自O' Rielly 2015学习火花书)可以在很多地方的网上看到; here's one

问题在于sumCount.map(lambda (key, (totalSum, count)): (key, totalSum / count)).collectAsMap()语句。使用spark 2.0.1和iPython 3.5.2,会引发语法错误异常。将它简化为应该起作用的东西(并且是O&#39; Reilly书中的内容):sumCount.map(lambda key,vals: (key, vals[0]/vals[1])).collectAsMap()导致Spark蝙蝠疯狂地使用java异常,但我注意到TypeError: <lambda>() missing 1 required positional argument: 'v' 1}}错误。

有人能指出这个功能的例子,它实际上适用于最新版本的Spark&amp;蟒蛇?为了完整起见,我已经包含了我自己的最低工作(或者说非工作)示例:

In: pRDD = sc.parallelize([("s",5),("g",3),("g",10),("c",2),("s",10),("s",3),("g",-1),("c",20),("c",2)])
In: cbk = pRDD.combineByKey(lambda x:(x,1), lambda x,y:(x[0]+y,x[1]+1),lambda x,y:(x[0]+y[0],x[1]+y[1]))
In: cbk.collect()
Out: [('s', (18, 3)), ('g', (12, 3)), ('c', (24, 3))]
In: cbk.map(lambda key,val:(k,val[0]/val[1])).collectAsMap() <-- errors

计算[(e[0],e[1][0]/e[1][1]) for e in cbk.collect()]很容易,但我宁愿得到&#34; Sparkic&#34;工作方式。

2 个答案:

答案 0 :(得分:2)

一步一步:

  • lambda (key, (totalSum, count)): ...是所谓的Tuple Parameter Unpacking,已在Python中删除。
  • RDD.map接受一个期望作为单个参数的函数。您尝试使用的功能:

    lambda key, vals: ...
    

    是一个需要两个参数的函数,而不是一个参数。 2.x语法的有效翻译将是

    lambda key_vals: (key_vals[0], key_vals[1][0] / key_vals[1][1])
    

    或:

    def get_mean(key_vals):
        key, (total, cnt) = key_vals
        return key, total / cnt
    
    cbk.map(get_mean)
    

    您还可以使用mapValues

    使这更简单
    cbk.mapValues(lambda x: x[0] / x[1])
    
  • 最后一个数值稳定的解决方案是:

    from pyspark.statcounter import StatCounter
    
    (pRDD
        .combineByKey(
            lambda x: StatCounter([x]),
            StatCounter.merge,
            StatCounter.mergeStats)
        .mapValues(StatCounter.mean))
    

答案 1 :(得分:-1)

使用 Window 概念可以对特定列值进行平均。请考虑以下代码:

import pyspark.sql.functions as F
from pyspark.sql import Window
df = spark.createDataFrame([('a', 2), ('b', 3), ('a', 6), ('b', 5)],
                           ['a', 'i'])
win = Window.partitionBy('a')
df.withColumn('avg', F.avg('i').over(win)).show()

会屈服:

+---+---+---+
|  a|  i|avg|
+---+---+---+
|  b|  3|4.0|
|  b|  5|4.0|
|  a|  2|4.0|
|  a|  6|4.0|
+---+---+---+

平均聚合分别对每个工作人员进行,不需要往返主机,因此效率很高。