2013-07-03 2 views
4

Я пытаюсь создать симметричную матрицу слов из текстового документа.python симметричная матрица слов с использованием nltk

Например: text = "Барбара хорошая. Барбара дружит с Бенни. Бенни плохой."

Я подписал текстовый документ, используя 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