簡體   English   中英

高效計算火花中的熵

[英]Efficient calculation of entropy in spark

給定RDD(數據),以及用於計算熵的索引字段列表。 執行以下流程時,需要大約5秒來計算2MB(16k行)源上的單個熵值。

def entropy(data: RDD[Array[String]], colIdx: Array[Int], count: Long): Double = { 
  println(data.toDebugString)
    data.map(r => colIdx.map(idx => r(idx)).mkString(",") -> 1)
        .reduceByKey(_ + _)
        .map(v => {
        val p = v._2.toDouble / count
        -p * scala.math.log(p) / scala.math.log(2)
      })
        .reduce((v1, v2) => v1 + v2)
}

debugString的輸出如下:

(entropy,MappedRDD[93] at map at Q.scala:31 (8 partitions)
  UnionRDD[72] at $plus$plus at S.scala:136 (8 partitions)
    MappedRDD[60] at map at S.scala:151 (4 partitions)
      FilteredRDD[59] at filter at S.scala:150 (4 partitions)
        MappedRDD[40] at map at S.scala:124 (4 partitions)
          MapPartitionsRDD[39] at mapPartitionsWithIndex at L.scala:356 (4 partitions)
            FilteredRDD[27] at filter at S.scala:104 (4 partitions)
              MappedRDD[8] at map at X.scala:21 (4 partitions)
                MappedRDD[6] at map at R.scala:39 (4 partitions)
                  FlatMappedRDD[5] at objectFile at F.scala:51 (4 partitions)
                    HadoopRDD[4] at objectFile at F.scala:51 (4 partitions)
    MappedRDD[68] at map at S.scala:151 (4 partitions)
      FilteredRDD[67] at filter at S.scala:150 (4 partitions)
        MappedRDD[52] at map at S.scala:124 (4 partitions)
          MapPartitionsRDD[51] at mapPartitionsWithIndex at L.scala:356 (4 partitions)
            FilteredRDD[28] at filter at S.scala:105 (4 partitions)
              MappedRDD[8] at map at X.scala:21 (4 partitions)
                MappedRDD[6] at map at R.scala:39 (4 partitions)
                  FlatMappedRDD[5] at objectFile at F.scala:51 (4 partitions)
                    HadoopRDD[4] at objectFile at F.scala:51 (4 partitions),colIdex,13,count,3922)

如果我收集RDD並再次並行化 ,則需要大約150ms來計算(對於簡單的2MB文件來說仍然很高) - 並且在處理多個GB數據時顯然會產生挑戰。 為了正確使用Spark和Scala,我錯過了什么?

我最初的實現(表現更差):

data.map(r => colIdx
  .map(idx => r(idx)).mkString(","))
  .groupBy(r => r)
  .map(g => g._2.size)
  .map(v => v.toDouble / count)
  .map(v => -v * scala.math.log(v) / scala.math.log(2))
  .reduce((v1, v2) => v1 + v2)

首先看起來你的代碼中有一個bug,你需要處理p0所以-p * math.log(p) / math.log(2)應該是if (p == 0.0) 0.0 else -p * math.log(p) / math.log(2)

其次,你可以使用base e,你真的不需要有2的基數。

無論如何,你的代碼很慢的原因可能是因為分區很少。 每個CPU應該至少有2-4個分區,實際上我經常使用更多分區。 你有多少CPU?

現在可能花費最長時間的不是熵計算,因為它非常簡單 - 但是在String鍵上進行的reduceByKey 是否可以使用其他一些數據類型? 什么是colIdx? 究竟是什么?

最后一個觀察是你使用這個colIdx.map(r.apply)多次索引每條記錄...你知道如果r不是ArrayIndexedSeq類型,這將非常慢...如果它是一個List它將是O (索引)因為你必須遍歷列表以獲得你想要的索引。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM