web-dev-qa-db-fra.com

Comment calculer une matrice de cooccurrence mot-mot avec sklearn?

Je cherche un module dans sklearn qui vous permette d’obtenir la matrice de cooccurrence mot-mot. 

Je peux obtenir la matrice de termes de document, mais je ne sais pas trop comment obtenir une matrice de co-occurrences mot-mot.

13
newdev14

Voici mon exemple de solution utilisant CountVectorizer dans scikit-learn. Et en vous référant à ce post , vous pouvez simplement utiliser la multiplication matricielle pour obtenir une matrice de cooccurrence mot-mot.

from sklearn.feature_extraction.text import CountVectorizer
docs = ['this this this book',
        'this cat good',
        'cat good shit']
count_model = CountVectorizer(ngram_range=(1,1)) # default unigram model
X = count_model.fit_transform(docs)
# X[X > 0] = 1 # run this line if you don't want extra within-text cooccurence (see below)
Xc = (X.T * X) # this is co-occurrence matrix in sparse csr format
Xc.setdiag(0) # sometimes you want to fill same Word cooccurence to 0
print(Xc.todense()) # print out matrix in dense format

Vous pouvez également vous référer au dictionnaire de mots dans count_model

count_model.vocabulary_

Ou, si vous voulez normaliser par composante diagonale (référé à la réponse dans le post précédent).

import scipy.sparse as sp
Xc = (X.T * X)
g = sp.diags(1./Xc.diagonal())
Xc_norm = g * Xc # normalized co-occurence matrix

Extra pour noter la réponse @ Federico Caccia, si vous ne souhaitez pas que les co-occurrences soient fausses dans le texte même, définissez une occurrence supérieure à 1 à 1, par exemple.

X[X > 0] = 1 # do this line first before computing cooccurrence
Xc = (X.T * X)
...
19
titipata

Vous pouvez utiliser le paramètre ngram_range dans les variables CountVectorizer ou TfidfVectorizer.

Exemple de code:

bigram_vectorizer = CountVectorizer(ngram_range=(2, 2)) # by saying 2,2 you are telling you only want pairs of 2 words

Si vous souhaitez indiquer explicitement les co-occurrences de mots à compter, utilisez le paramètre vocabulary, c.-à-d. vocabulary = {'awesome unicorns':0, 'batman forever':1}.

http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html

Code explicite et prêt à l'emploi avec des occurrences mot-mot prédéfinies. Dans ce cas, nous recherchons des co-occurrences de awesome unicorns et batman forever:

from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
samples = ['awesome unicorns are awesome','batman forever and ever','I love batman forever']
bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), vocabulary = {'awesome unicorns':0, 'batman forever':1}) 
co_occurrences = bigram_vectorizer.fit_transform(samples)
print 'Printing sparse matrix:', co_occurrences
print 'Printing dense matrix (cols are vocabulary keys 0-> "awesome unicorns", 1-> "batman forever")', co_occurrences.todense()
sum_occ = np.sum(co_occurrences.todense(),axis=0)
print 'Sum of Word-word occurrences:', sum_occ
print 'Pretty printig of co_occurrences count:', Zip(bigram_vectorizer.get_feature_names(),np.array(sum_occ)[0].tolist())

La sortie finale est ('awesome unicorns', 1), ('batman forever', 2), ce qui correspond exactement à nos données samples fournies.

1
Guiem Bosch

@titipata Je pense que votre solution n'est pas une bonne mesure car nous accordons le même poids aux co-occurrences réelles et aux occurrences tout simplement fictives . Par exemple, si j'ai 5 textes et les mots Apple et house apparaît avec cette fréquence:

text1: Apple: 10, "house": 1

text2: Apple: 10, "house": 0

text3: Apple: 10, "house": 0

text4: Apple: 10, "house": 0

text5: Apple: 10, "house": 0

La co-occurrence que nous allons mesurer est 10 * 1 + 10 * 0 + 10 * 0 + 10 * 0 + 10 * 0 = 10, mais est simplement fausse.

Et, dans ce cas, un autre cas important, comme celui-ci:

text1: Apple: 1, "banane": 1

text2: Apple: 1, "banane": 1

text3: Apple: 1, "banane": 1

text4: Apple: 1, "banane": 1

text5: Apple: 1, "banane": 1

nous allons obtenir juste un {co-occurrence} _ de 1 * 1 + 1 * 1 + 1 * 1 + 1 * 1 = 5, alors que cette co-occurrence est vraiment importante .

@Guiem Bosch Dans ce cas, les co-occurrences ne sont mesurées que lorsque les deux mots sont contigus.

Je propose d'utiliser quelque chose de la solution @titipa pour calculer la matrice:

Xc = (Y.T * Y) # this is co-occurrence matrix in sparse csr format

où, au lieu d'utiliser X, utilisez une matrice Y avec uns dans des positions supérieures à 0 et zéros dans d'autres positions.

En utilisant cela, dans le premier exemple, nous aurons: co-occurrence: 1 * 1 + 1 * 0 + 1 * 0 + 1 * 0 + 1 * 0 = 1 et dans le deuxième exemple: co-occurrence: 1 * 1 + 1 * 1 + 1 * 1 + 1 * 1 + 1 * 0 = 5 C'est ce que nous recherchons vraiment.

1
Federico Caccia