2010-03-05 51 views
3

基本上我有一個詞典,包含我的詞彙量的所有單詞作爲鍵,所有的0作爲價值。一袋詞的表示問題

要將文檔處理成一包文字表示形式,我曾使用適當的IEqualityComparer複製該詞典,並簡單地檢查該詞典是否包含文檔中的每個詞並將其增加爲鍵。

爲了獲得單詞表示袋的數組,我簡單地使用了ToArray方法。

這似乎工作正常,但我只是被告知字典不保證相同的密鑰順序,所以得到的數組可能代表單詞以不同的順序,使它無用。

我目前的想法是將單詞詞典的所有關鍵字都複製到一個ArrayList中,創建一個合適大小的數組,然後使用數組列表的indexOf方法來填充數組。

所以我的問題是,有沒有更好的方法來解決這個問題,我的看起來有點粗糙......並且不會因爲IEqualityComparer而有問題嗎?

+1

作爲一個問題,你爲什麼要轉換成一個數組? – 2010-03-05 01:28:49

+2

您能否提供一些示例代碼和數據以更好地說明您使用單詞袋模型要做什麼? – 2010-03-05 01:29:43

+0

我想將它轉換爲一個數組,以便稍後可以使用餘弦相似度。 當你用單詞的頻率來表示一個文檔時,無論它的順序和其他屬性如何,都是一堆詞。 – brokencoding 2010-03-05 01:35:59

回答

4

讓我看看我是否理解這個問題。您有兩個文件D1和D2,每個文件都包含從已知詞彙{W1,W2 ... Wn}中繪製的單詞序列。您希望獲得兩個映射,指出每個文檔中每個單詞的出現次數。因此,對於D1,您可能有

W1 --> 0 
W2 --> 1 
W3 --> 4 

表明D1可能是「W3 W2 W3 W3 W3」。也許D2是「W2 W1 W2」,所以它的映射是

W1 --> 1 
W2 --> 2 
W3 --> 0 

要採取兩個映射,並確定矢量[0,1,4]和[1,2,0],然後計算角作爲確定兩個文件有多相似或不同的一種方式。

您的問題是,字典不保證鍵/值對按任何特定的順序列舉。

好的,請訂購它們。

vector1 = (from pair in map1 orderby pair.Key select pair.Value).ToArray(); 
vector2 = (from pair in map2 orderby pair.Key select pair.Value).ToArray(); 

你就完成了。

這是否解決您的問題,或者我誤解了這種情況?

+0

這是場景,但對於一個字典,讓我們說20千字每次做排序我每次轉換一個文件是計算量大還是不大? – brokencoding 2010-03-05 01:58:30

+1

埃裏克,我不明白「W2 W1 W2」如何對應第二個映射。 – spender 2010-03-05 01:59:16

+0

@brokencoding:如果您只比較兩個文檔,那麼爲什麼要在所有20k字的字典上執行此操作?這些文件有多大?您只需要包含至少出現在一個文檔中的單詞的計數。 – Aaronaught 2010-03-05 02:00:23

1

還有一個OrderedDictionary

表示鍵/值 對是由密鑰 或索引可訪問的集合。

+0

這不是通用的。 – 2010-03-05 01:28:39

+0

@gWiz:這不是要求。 – 2010-03-05 01:37:25

+0

@gWiz - 這裏有幾個版本:http://www.codeproject.com/KB/recipes/GenericOrderedDictionary.aspx – 2010-03-05 01:37:58

0

像這樣的東西可能會工作,雖然它肯定是醜陋的,我相信是類似於你的建議。 GetWordCount()完成這項工作。

類WordCounter {

公共詞典=新詞典();

public void CountWords(string text) 
    { 
     if (text != null && text != string.Empty) 
     { 
      text = text.ToLower(); 
      string[] words = text.Split(' '); 
      if (dictionary.ContainsKey(words[0])) 
      { 
       if (text.Length > words[0].Length) 
       { 
        text = text.Substring(words[0].Length + 1); 
        CountWords(text); 
       } 

      } 
      else 
      { 
       int count = words.Count(
        delegate(string s) 
        { 
         if (s == words[0]) { return true; } 
         else { return false; } 
        }); 
       dictionary.Add(words[0], count); 
       if (text.Length > words[0].Length) 
       { 
        text = text.Substring(words[0].Length + 1); 
        CountWords(text); 
       } 

      } 
     } 
    } 

    public int[] GetWordCount(string text) 
    { 
     CountWords(text); 
     return dictionary.Values.ToArray<int>(); 
    } 


} 
+0

不,我解析文本沒有問題,這個想法是代表這樣的文字: Text =「貓狗狼貓馬狗」;有 我會像這樣的詞典: [貓,2] [狗,2] [狼,1] [馬,1] 而字表示的包是簡單的: [2 2 1 1] 但是,如果字典不維持秩序,我可以結束與像[2 1 2 1]這樣的東西,擊敗目的 – brokencoding 2010-03-05 01:48:39

2

如果我理解正確的話,你想拆通過詞頻的文檔。

你可以採取的文件並運行一個正則表達式在其上打出一行字:

var words=Regex 
    .Matches(input,@"\w+") 
    .Cast<Match>() 
    .Where(m=>m.Success) 
    .Select(m=>m.Value); 

爲了使頻率圖表:

var map=words.GroupBy(w=>w).Select(g=>new{word=g.Key,freqency=g.Count()}); 

有對的GroupBy方法允許過載如果這很重要,您可以提供另一種IEqualityComparer。

閱讀您的意見,只創建頻率的對應序列:

map.Select(a=>a.frequency) 

這個序列將是完全相同的順序與上面的序列map

這有什麼幫助嗎?

0

會是這樣對您有所幫助:

SortedDictionary<string, int> dic = new SortedDictionary<string, int>(); 

      for (int i = 0; i < 10; i++) 
      { 
       if (dic.ContainsKey("Word" + i)) 
        dic["Word" + i]++; 
       else 
        dic.Add("Word" + i, 0); 
      } 

      //to get the array of words: 
      List<string> wordsList = new List<string>(dic.Keys); 
      string[] wordsArr = wordsList.ToArray(); 

      //to get the array of values 
      List<int> valuesList = new List<int>(dic.Values); 
      int[] valuesArr = valuesList.ToArray(); 
0

如果你正在試圖做的是計算餘弦相似度一切,你不需要將數據轉換爲20,000長數組,尤其是考慮到數據可能會稀少,大多數條目爲零。

在處理文件時,將文件輸出數據存儲到字典中的字典上。然後爲了計算點積和幅度,您遍歷整個單詞列表中的單詞,在每個文件ouptut數據中查找單詞,如果存在則使用找到的值,如果不存在則使用找到的值。