2014-01-10 60 views
3

我正在使用Golang爲具有超過30000種可能標記的數據集實施樸素貝葉斯分類。我已經建立了模型,我正處於分類階段。我正在分類1000條記錄,這需要5分鐘。我用pprof功能描述了代碼; top10顯示如下:Golang中的地圖訪問瓶頸

Total: 28896 samples 
    16408 56.8% 56.8% 24129 83.5% runtime.mapaccess1_faststr 
    4977 17.2% 74.0%  4977 17.2% runtime.aeshashbody 
    2552 8.8% 82.8%  2552 8.8% runtime.memeqbody 
    1468 5.1% 87.9% 28112 97.3% main.(*Classifier).calcProbs 
    861 3.0% 90.9%  861 3.0% math.Log 
    435 1.5% 92.4%  435 1.5% runtime.markspan 
    267 0.9% 93.3%  302 1.0% MHeap_AllocLocked 
    187 0.6% 94.0%  187 0.6% runtime.aeshashstr 
    183 0.6% 94.6%  1137 3.9% runtime.mallocgc 
    127 0.4% 95.0%  988 3.4% math.log10 

令人驚訝的是,地圖訪問似乎是瓶頸。有沒有人經歷過這個。還有哪些其他關鍵的價值數據結構可以用來避免這個瓶頸?所有地圖訪問在下面給出的下面的代碼段來完成:

func (nb *Classifier) calcProbs(data string) *BoundedPriorityQueue{ 
    probs := &BoundedPriorityQueue{} 
    heap.Init(probs) 

    terms := strings.Split(data, " ") 
    for class, prob := range nb.classProb{ 
     condProb := prob 
     clsProbs := nb.model[class] 
     for _, term := range terms{ 
      termProb := clsProbs[term] 
      if termProb != 0{ 
       condProb += math.Log10(termProb) 
      }else{ 
       condProb += -6 //math.Log10(0.000001) 
      } 
     } 
     entry := &Item{ 
      value: class, 
      priority: condProb, 
     } 
     heap.Push(probs,entry) 
    } 
    return probs 
} 

地圖是nb.classProb是map[string]float64而nb.model是類型的嵌套地圖

map[string]map[string]float64 
+0

如果你知道它是這樣的,你爲什麼要實施一種天真的方法? – Fallenreaper

+3

看到實際的代碼將是有用的,至少要知道你使用什麼樣的鍵/值。地圖應該相當快。 – siritinga

+0

我已經瘋狂的快速基準與本地地圖上的字符串和整數高達10M項目。正如siritinga所說,代碼會很好。什麼類型的地圖? –

回答

2

在除了@tomwilde所說的,另一種方法可能加速你的算法是字符串實習。也就是說,如果您提前知道密鑰的域,則可以完全避免使用地圖。我寫了一個小包裝,爲你做string interning

2

是的,地圖訪問將成爲此代碼中的瓶頸:它是兩個嵌套循環中最重要的操作。

從包含的代碼中無法確定,但我期望您的類數量有限。你可能會做的,是數他們,並存儲術語明智類的概率是這樣的:

map[string][NumClasses]float64 

(即:每個術語,存儲類明智的概率的數組[或者也許他們的日誌已經預先計算] ,NumClasses是你擁有的不同類別的數量)。

然後,首先迭代條件,並在裏面的類。昂貴的地圖查找將在外部循環中完成,並且內部循環將遍歷數組。

這會將地圖查找的數量減少一個NumClasses因子。如果你的數據非常稀少,這可能需要更多的內存。

下一個優化是使用多個goroutines來進行計算,假設您有多個CPU核心可用。