Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Python计算Spark中成对(K,V)RDD中每个键的平均值_Python_Apache Spark_Aggregate_Average_Rdd - Fatal编程技术网

使用Python计算Spark中成对(K,V)RDD中每个键的平均值

使用Python计算Spark中成对(K,V)RDD中每个键的平均值,python,apache-spark,aggregate,average,rdd,Python,Apache Spark,Aggregate,Average,Rdd,我想与Python共享这个特定的ApacheSpark解决方案,因为它的文档非常差 我想按键计算K/V对(存储在成对RDD中)的平均值。以下是示例数据的外观: >>> rdd1.take(10) # Show a small sample. [(u'2013-10-09', 7.60117302052786), (u'2013-10-10', 9.322709163346612), (u'2013-10-10', 28.264462809917358), (u'2013-10-

我想与Python共享这个特定的ApacheSpark解决方案,因为它的文档非常差

我想按键计算K/V对(存储在成对RDD中)的平均值。以下是示例数据的外观:

>>> rdd1.take(10) # Show a small sample.
[(u'2013-10-09', 7.60117302052786),
(u'2013-10-10', 9.322709163346612),
(u'2013-10-10', 28.264462809917358),
(u'2013-10-07', 9.664429530201343),
(u'2013-10-07', 12.461538461538463),
(u'2013-10-09', 20.76923076923077),
(u'2013-10-08', 11.842105263157894),
(u'2013-10-13', 32.32514177693762),
(u'2013-10-13', 26.249999999999996),
(u'2013-10-13', 10.693069306930692)]
现在,下面的代码序列是一种不太理想的方法,但确实有效。这就是我在找到更好的解决方案之前所做的。这并不可怕,但是,正如你将在答案部分看到的那样,有一种更简洁、更有效的方法

>>> import operator
>>> countsByKey = sc.broadcast(rdd1.countByKey()) # SAMPLE OUTPUT of countsByKey.value: {u'2013-09-09': 215, u'2013-09-08': 69, ... snip ...}
>>> rdd1 = rdd1.reduceByKey(operator.add) # Calculate the numerators (i.e. the SUMs).
>>> rdd1 = rdd1.map(lambda x: (x[0], x[1]/countsByKey.value[x[0]])) # Divide each SUM by it's denominator (i.e. COUNT)
>>> print(rdd1.collect())
  [(u'2013-10-09', 11.235365503035176),
   (u'2013-10-07', 23.39500642456595),
   ... snip ...
  ]

现在更好的方法是使用
rdd.aggregateByKey()
方法。因为这个方法在ApacheSpark with Python文档中的文档记录非常糟糕——这也是我编写这个Q&A的原因——直到最近,我一直在使用上面的代码序列。但同样,它的效率较低,所以除非必要,否则要避免这样做

下面介绍了如何使用
rdd.aggregateByKey()
方法(推荐的方法)执行相同操作:

按键同时计算总和(我们要计算的平均值的分子)和计数(我们要计算的平均值的分母):

其中,关于上面每对
a
b
的含义,以下是正确的(因此您可以直观地看到发生了什么):

最后,计算每个键的平均值,并收集结果

>>> finalResult = rdd1.mapValues(lambda v: v[0]/v[1]).collect()
>>> print(finalResult)
      [(u'2013-09-09', 11.235365503035176),
       (u'2013-09-01', 23.39500642456595),
       (u'2013-09-03', 13.53240060820617),
       (u'2013-09-05', 13.141148418977687),
   ... snip ...
  ]

我希望用aggregateByKey()回答这个问题会有所帮助。

在我看来,与带有两个lambda的aggregateByKey相比,更具可读性的等价物是:

rdd1 = rdd1 \
    .mapValues(lambda v: (v, 1)) \
    .reduceByKey(lambda a,b: (a[0]+b[0], a[1]+b[1]))
这样,整个平均值计算结果将为:

avg_by_key = rdd1 \
    .mapValues(lambda v: (v, 1)) \
    .reduceByKey(lambda a,b: (a[0]+b[0], a[1]+b[1])) \
    .mapValues(lambda v: v[0]/v[1]) \
    .collectAsMap()

只是添加了一个关于这个问题的直观和简短(但不好)解决方案的注释。这本书在最后一章很好地解释了这个问题

使用
groupByKey
可以像这样轻松地解决问题:

rdd = sc.parallelize([
        (u'2013-10-09', 10),
        (u'2013-10-09', 10),
        (u'2013-10-09', 13),
        (u'2013-10-10', 40),
        (u'2013-10-10', 45),
        (u'2013-10-10', 50)
    ])

rdd \
.groupByKey() \
.mapValues(lambda x: sum(x) / len(x)) \
.collect()
输出:

[('2013-10-10', 45.0), ('2013-10-09', 11.0)]
这很直观,也很吸引人,但是不要使用它
groupByKey
不会在映射器上进行任何组合,并将所有单个键值对带到reducer


尽量避免使用
groupByKey
。使用像@pat's这样的
reduceByKey
解决方案。

对prismalytics.io的答案稍加增强

可能有这样一种情况,计算总和可能会溢出数字,因为我们正在对大量的值求和。我们可以保留平均值,并根据平均值计算平均值,然后减少两部分的计数

如果有两个部分具有平均值,并且计数为(a1,c1)和(a2,c2),则总体平均值为: 总数/计数=(总数1+2)/(计数1+2)=(a1*c1+a2*c2)/(c1+c2)

如果我们标记R=c2/c1,它可以进一步重写为a1/(1+R)+a2*R/(1+R) 如果我们进一步把Ri标记为1/(1+R),我们可以把它写成a1*Ri+a2*R*Ri

myrdd = sc.parallelize([1.1, 2.4, 5, 6.0, 2, 3, 7, 9, 11, 13, 10])
sumcount_rdd = myrdd.map(lambda n : (n, 1))
def avg(A, B):
    R = 1.0*B[1]/A[1]
    Ri = 1.0/(1+R);
    av = A[0]*Ri + B[0]*R*Ri
    return (av, B[1] + A[1]);

(av, counts) = sumcount_rdd.reduce(avg)
print(av)
这种方法可以通过简单地使用mapValues而不是map和reduceByKey而不是reduce来转换为键值


这是来自:

这确实是一个很好的答案。然而,我将注意到,由于这一点,只有python 2.x兼容,因为在python 3中不再支持lambda表达式中的元组解包。x@Tgsmith61591非常感谢。我添加了中间变量“aTuple”来解决这个问题。(唉,我想不出更好的标识符名称了,哈哈)。很好地抓住了3113!“key1”、(1,1)“key1”、(2,1)=>“key1”、(3,2)基于对a,b的相同解释:。aggregateByKey(一对,lambda,b:(a[0]+b[0],a[1]+1),lambda,b:(a[0]+b[0],a[1]+b[1]))这就是我的建议和参考的作用。有人能解释一下a和b在lambda函数中的重要性吗@拍打
[('2013-10-10', 45.0), ('2013-10-09', 11.0)]
myrdd = sc.parallelize([1.1, 2.4, 5, 6.0, 2, 3, 7, 9, 11, 13, 10])
sumcount_rdd = myrdd.map(lambda n : (n, 1))
def avg(A, B):
    R = 1.0*B[1]/A[1]
    Ri = 1.0/(1+R);
    av = A[0]*Ri + B[0]*R*Ri
    return (av, B[1] + A[1]);

(av, counts) = sumcount_rdd.reduce(avg)
print(av)