2010-11-21 130 views
9

我開發了一個應用程序,它可以在(標記化)文本中構建單詞對並生成每個對的發生次數(即使相同單詞對多次出現也可以,因爲它稍後會在算法中被平衡掉)。Scala:列表元素的列表(標識)

當我使用

elements groupBy() 

我想用的元素內容本身組,所以我寫了以下內容:

def self(x: (String, String)) = x 

/** 
* Maps a collection of words to a map where key is a pair of words and the 
* value is number of 
* times this pair 
* occurs in the passed array 
*/ 
def producePairs(words: Array[String]): Map[(String,String), Double] = { 
    var table = List[(String, String)]() 
    words.foreach(w1 => 
    words.foreach(w2 => 
     table = table ::: List((w1, w2)))) 


    val grouppedPairs = table.groupBy(self) 
    val size = int2double(grouppedPairs.size) 
    return grouppedPairs.mapValues(_.length/size) 
} 

現在,我充分認識到,這種自我()訣竅是一個骯髒的黑客。所以我覺得有點出來一個:

grouppedPairs = table groupBy (x => x) 

這樣它產生了我想要的。然而,我仍然覺得我顯然錯過了一些東西,應該有更簡單的方法來做到這一點。任何想法,親愛的?另外,如果你能幫助我改進對提取部分,它也會有很大幫助 - 它看起來非常必要,C++ - 現在就是。提前謝謝了!

回答

2

你正在創建一個對所有單詞的所有單詞對的列表,通過迭代單詞兩次,在那裏我想你只是想要鄰居對。最簡單的方法就是使用滑動視圖。

def producePairs(words: Array[String]): Map[(String, String), Int] = { 
    val pairs = words.sliding(2, 1).map(arr => arr(0) -> arr(1)).toList 
    val grouped = pairs.groupBy(t => t) 
    grouped.mapValues(_.size) 
} 

另一種方法是摺疊成對的列表。不知道這是否更有效率:

def producePairs(words: Array[String]): Map[(String, String), Int] = { 
    val pairs = words.sliding(2, 1).map(arr => arr(0) -> arr(1)) 
    pairs.foldLeft(Map.empty[(String, String), Int]) { (m, p) => 
    m + (p -> (m.getOrElse(p, 0) + 1)) 
    } 
} 

我看你是返回一個相對數(雙)。爲了簡單起見,我只計算了發生的事件,所以你需要做最後的劃分。我認爲你想除以總配對數量(words.size - 1)而不是唯一配對數量(grouped.size)...,因此相對頻率總和爲1.0

+0

事實上,正是我想要的所有對 - 通常,它的話那種模式的袋子。但滑動的方法非常酷,我將需要它來解決另一個問題,非常感謝! – sgzmd 2010-11-21 15:15:30

13

I' ð建議是:

def producePairs(words: Array[String]): Map[(String,String), Double] = { 
    val table = for(w1 <- words; w2 <- words) yield (w1,w2) 
    val grouppedPairs = table.groupBy(identity) 
    val size = grouppedPairs.size.toDouble 
    grouppedPairs.mapValues(_.length/size) 
} 

的理解力是非常容易閱讀,並且已經有一個predifined功能identity,用的是你的self的一般化版本。

1

另類的做法,是爲了O(num_words * num_words)但爲了O(num_unique_words * num_unique_words)(或類似的東西)不:

def producePairs[T <% Traversable[String]](words: T): Map[(String,String), Double] = { 
    val counts = words.groupBy(identity).map{case (w, ws) => (w -> ws.size)} 
    val size = (counts.size * counts.size).toDouble 
    for(w1 <- counts; w2 <- counts) yield { 
     ((w1._1, w2._1) -> ((w1._2 * w2._2)/size)) 
    } 
}