2013-07-03 69 views
4

我試圖從文本文檔創建一個對稱字矩陣。python對稱字矩陣使用nltk

例如: 文本=「真真是好真真是朋友,尼尼是壞的。」

我已經使用nltk標記了文本文檔。現在我要計算其他詞在同一句子中出現多少次。從上面的文字中,我想創建下面的矩陣:

 Barbara good friends Benny bad 
Barbara 2 1 1 1 0 
good 1 1 0 0 0 
friends 1 0 1 1 0 
Benny 1 0 1 2 1 
bad  0 0 1 1 1 

注意對角線是單詞的頻率。因爲芭芭拉和巴巴拉一樣經常出現在巴巴拉的句子中。我希望不要超支,但如果代碼變得太複雜,這不是一個大問題。

+0

問題是什麼? –

+0

如何從文本創建上述矩陣? – mumpy

回答

3

首先我們記號化的文字,遍歷每個句子,並通過在每個句子的單詞的所有配對組合迭代,並存放數嵌套dict

from nltk.tokenize import word_tokenize, sent_tokenize 
from collections import defaultdict 
import numpy as np 
text = "Barbara is good. Barbara is friends with Benny. Benny is bad." 

sparse_matrix = defaultdict(lambda: defaultdict(lambda: 0)) 

for sent in sent_tokenize(text): 
    words = word_tokenize(sent) 
    for word1 in words: 
     for word2 in words: 
      sparse_matrix[word1][word2]+=1 

print sparse_matrix 
>> defaultdict(<function <lambda> at 0x7f46bc3587d0>, { 
'good': defaultdict(<function <lambda> at 0x3504320>, 
    {'is': 1, 'good': 1, 'Barbara': 1, '.': 1}), 
'friends': defaultdict(<function <lambda> at 0x3504410>, 
    {'friends': 1, 'is': 1, 'Benny': 1, '.': 1, 'Barbara': 1, 'with': 1}), etc.. 

這基本上就像一個矩陣,因爲我們可以索引sparse_matrix['good']['Barbara']並獲得號碼1,索引sparse_matrix['bad']['Barbara']並獲得0,但我們實際上並未存儲任何從未共同發生的詞的計數,0僅由defaultdict生成,僅當您要求時它。這可以在做這些事情時真的節省很多內存。如果我們需要某種類型的線性代數或其他計算理性的密集矩陣,我們可以得到這樣的:

lexicon_size=len(sparse_matrix) 
def mod_hash(x, m): 
    return hash(x) % m 
dense_matrix = np.zeros((lexicon_size, lexicon_size)) 

for k in sparse_matrix.iterkeys(): 
    for k2 in sparse_matrix[k].iterkeys(): 
     dense_matrix[mod_hash(k, lexicon_size)][mod_hash(k2, lexicon_size)] = \ 
      sparse_matrix[k][k2] 

print dense_matrix 
>> 
[[ 0. 0. 0. 0. 0. 0. 0. 0.] 
[ 0. 0. 0. 0. 0. 0. 0. 0.] 
[ 0. 0. 1. 1. 1. 1. 0. 1.] 
[ 0. 0. 1. 1. 1. 0. 0. 1.] 
[ 0. 0. 1. 1. 1. 1. 0. 1.] 
[ 0. 0. 1. 0. 1. 2. 0. 2.] 
[ 0. 0. 0. 0. 0. 0. 0. 0.] 
[ 0. 0. 1. 1. 1. 2. 0. 3.]] 

我會建議看http://docs.scipy.org/doc/scipy/reference/sparse.html用於處理矩陣稀疏的其他方式。

+0

謝謝大家時間!我也很感謝你在稀疏矩陣上的鏈接。乾杯! – mumpy

3

我會首先設置類似下面的內容。可能會添加某種類型的標記;儘管對於你的例子來說沒有必要。

text = """Barbara is good. Barbara is friends with Benny. Benny is bad.""" 
allwords = text.replace('.','').split(' ') 
word_to_index = {} 
index_to_word = {} 
index = 0 
for word in allwords: 
    if word not in word_to_index: 
     word_to_index[word] = index 
     index_to_word[index] = word 
     index += 1 
word_count = index 

>>> index_to_word 
{0: 'Barbara', 
1: 'is', 
2: 'good', 
3: 'friends', 
4: 'with', 
5: 'Benny', 
6: 'bad'} 

>>> word_to_index 
{'Barbara': 0, 
'Benny': 5, 
'bad': 6, 
'friends': 3, 
'good': 2, 
'is': 1, 
'with': 4} 

然後聲明適當大小的矩陣(word_count x word_count);可能使用numpy

import numpy 
matrix = numpy.zeros((word_count, word_count)) 

或者只是一個嵌套列表:

matrix = [None,]*word_count 
for i in range(word_count): 
    matrix[i] = [0,]*word_count 

注意這是棘手的,像matrix = [[0]*word_count]*word_count不會因爲這項工作將使7所引用的名單相同的內部陣列(例如,如果您嘗試該代碼,然後執行matrix[0][1] = 1,則會發現matrix[1][1],matrix[2][1]等也將更改爲1)。

然後你只需要遍歷你的句子。

sentences = text.split('.') 
for sent in sentences: 
    for word1 in sent.split(' '): 
     if word1 not in word_to_index: 
      continue 
     for word2 in sent.split(' '): 
      if word2 not in word_to_index: 
       continue 
      matrix[word_to_index[word1]][word_to_index[word2]] += 1 

然後你得到:

>>> matrix 

[[2, 2, 1, 1, 1, 1, 0], 
[2, 3, 1, 1, 1, 2, 1], 
[1, 1, 1, 0, 0, 0, 0], 
[1, 1, 0, 1, 1, 1, 0], 
[1, 1, 0, 1, 1, 1, 0], 
[1, 2, 0, 1, 1, 2, 1], 
[0, 1, 0, 0, 0, 1, 1]] 

或者有什麼說「本尼」和「壞」,你可以問matrix[word_to_index['Benny']][word_to_index['bad']]的頻率,如果你是好奇。

+0

非常感謝!我感謝您的幫助。 – mumpy

+0

我希望我可以選擇兩個答案 - 你的答案都對我的分析非常有幫助。乾杯! – mumpy