PySpark中地图的汇总列表

时间:2017-10-12 15:46:43

标签: python pyspark pyspark-sql

我有一个地图列表,例如

[{'a' : 10,'b': 20}, {'a' : 5,'b': 20} , {'b': 20}  ,{'a' : 0,'b': 20} } 

我想得到a和b的平均值。所以预期的输出是

a = (10 + 5 + 0 + 0) /3 = 5 ;
b = 80/4 = 20.

如何使用RDD高效地完成

3 个答案:

答案 0 :(得分:1)

最简单的可能是map您的rdd元素,格式如下:

init = {'a': {'sum': 0, 'cnt': 0}, 'b': {'sum': 0, 'cnt': 0}}

即。记录每个密钥的总和和计数,然后减少它。

地图功能:

def map_fun(d, keys=['a', 'b']):
    map_d = {}
    for k in keys:
        if k in d:
            temp = {'sum': d[k], 'cnt': 1}
        else:
            temp = {'sum': 0, 'cnt': 0}
        map_d[k] = temp
    return map_d

减少功能:

def reduce_fun(a, b, keys=['a', 'b']):
    from collections import defaultdict
    reduce_d = defaultdict(dict)
    for k in keys:
        reduce_d[k]['sum'] = a[k]['sum'] + b[k]['sum']
        reduce_d[k]['cnt'] = a[k]['cnt'] + b[k]['cnt']
    return reduce_d
rdd.map(map_fun).reduce(reduce_fun)
# defaultdict(<type 'dict'>, {'a': {'sum': 15, 'cnt': 3}, 'b': {'sum': 80, 'cnt': 4}})

计算平均值:

d = rdd.map(map_fun).reduce(reduce_fun)
{k: v['sum']/v['cnt'] for k, v in d.items()}
{'a': 5, 'b': 20}

答案 1 :(得分:1)

鉴于您的数据结构,您应该能够使用dataframe api来实现此计算。如果你需要一个rdd,那么从数据帧回到rdd并不困难。

from pyspark.sql import functions as F
df = spark.createDataFrame([{'a' : 10,'b': 20}, {'a' : 5,'b': 20} , {'b': 20}  ,{'a' : 0,'b': 20}])

Dataframe看起来像这样

+----+---+
|   a|  b|
+----+---+
|  10| 20|
|   5| 20|
|null| 20|
|   0| 20|
+----+---+

然后简单地使用pyspark.sql函数计算平均值

cols = df.columns
df_means = df.agg(*[F.mean(F.col(col)).alias(col+"_mean") for col in cols])
df_means.show()

输出:

+------+------+
|a_mean|b_mean|
+------+------+
|   5.0|  20.0|
+------+------+

答案 2 :(得分:0)

您可以使用defaultdict收集类似的密钥及其值list。 然后简单地使用值的总和除以每个值的list元素的数量进行聚合。

from collections import defaultdict

x = [{'a' : 10,'b': 20}, {'a' : 5,'b': 20} , {'b': 20}  ,{'a' : 0,'b': 20}]
y = defaultdict(lambda: [])
[y[k].append(v) for i in x for k,v in i.items() ]

for k,v in y.items():
    print k, "=" ,sum(v)/len(v)

>>> y
defaultdict(<function <lambda> at 0x02A43BB0>, {'a': [10, 5, 0], 'b': [20, 20, 20, 20]})
>>> 

>>> 
a = 5
b = 20