我试图在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' 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;工作方式。
答案 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|
+---+---+---+
平均聚合分别对每个工作人员进行,不需要往返主机,因此效率很高。