Quelle est la différence entre un vectoriseur de hachage et un vectoriseur tfidf

11

Je convertis un corpus de documents texte en vecteurs de mots pour chaque document. J'ai essayé ceci en utilisant un TfidfVectorizer et un HashingVectorizer

Je comprends qu'un a HashingVectorizerne prend pas en compte les IDFscores comme un le TfidfVectorizerfait. La raison pour laquelle je travaille toujours avec HashingVectorizerest la flexibilité qu'il donne tout en traitant d'énormes ensembles de données, comme expliqué ici et ici . (Mon ensemble de données d'origine contient 30 millions de documents)

Actuellement, je travaille avec un échantillon de 45339 documents, j'ai donc la possibilité de travailler avec un TfidfVectorizeraussi. Lorsque j'utilise ces deux vectoriseurs sur les mêmes documents 45339, les matrices que je reçois sont différentes.

hashing = HashingVectorizer()
with LSM('corpus.db')) as corpus:
    hashing_matrix = hashing.fit_transform(corpus)
print(hashing_matrix.shape) 

forme de matrice de hachage (45339, 1048576)

tfidf = TfidfVectorizer()
with LSM('corpus.db')) as corpus:
    tfidf_matrix = tfidf.fit_transform(corpus)
print(tfidf_matrix.shape) 

forme de matrice tfidf (45339, 663307)

Je veux mieux comprendre les différences entre a HashingVectorizeret a TfidfVectorizer, et la raison pour laquelle ces matrices sont de tailles différentes - en particulier dans le nombre de mots / termes.

Minu
la source
Pouvez-vous s'il vous plaît partager l'ensemble de données avec moi? (réponse à supprimer)
nKarza

Réponses:

7

La principale différence réside dans le fait qu’une HashingVectorizerfonction de hachage est appliquée aux décomptes de fréquence des termes dans chaque document, où elle met à l' TfidfVectorizeréchelle ces décomptes de fréquence des termes dans chaque document en pénalisant les termes qui apparaissent plus largement dans le corpus. Il y a un bon résumé ici: https://spark.apache.org/docs/latest/mllib-feature-extraction.html

  • Les fonctions de hachage sont un moyen efficace de mapper les termes aux entités; il n'est pas nécessairement nécessaire de l'appliquer uniquement aux fréquences des termes, mais c'est la façon dont HashingVectorizeron l' utilise ici. Avec les documents 45339, je soupçonne que le vecteur d'entité est de longueur 1048576 car c'est le 2 ^ 20 par défaut n_features; vous pouvez réduire cela et le rendre moins coûteux à traiter, mais avec un risque accru de collision, où la fonction mappe différents termes à la même fonctionnalité: http://preshing.com/20110504/hash-collision-probabilities/

  • Selon le cas d'utilisation des vecteurs de mots, il peut être possible de réduire considérablement la longueur du vecteur de caractéristiques de hachage (et donc la complexité) avec une perte acceptable de précision / efficacité (en raison d'une collision accrue). Scikit-learn a des paramètres de hachage qui peuvent aider, par exemple alternate_sign.

  • Si la matrice de hachage est plus large que le dictionnaire, cela signifie que de nombreuses entrées de colonne dans la matrice de hachage seront vides, et pas seulement parce qu'un document donné ne contient pas de terme spécifique, mais parce qu'elles sont vides dans l'ensemble matrice. Si ce n'est pas le cas, il peut envoyer plusieurs termes au même hachage de fonctionnalité - c'est la «collision» dont nous avons parlé. HashingVectorizera un paramètre qui fonctionne pour atténuer cet appel alternate_signpar défaut, décrit ici: en.wikipedia.org/wiki/Feature_hashing#Properties

  • «Fréquence terminologique - fréquence inverse du document» prend les fréquences terminologiques dans chaque document et les pondère en pénalisant les mots qui apparaissent plus fréquemment dans l'ensemble du corpus. L'intuition est que les termes trouvés de façon situationnelle sont plus susceptibles d'être représentatifs du sujet d'un document spécifique. Ceci est différent d'une fonction de hachage en ce qu'il est nécessaire d'avoir un dictionnaire complet de mots dans le corpus afin de calculer la fréquence inverse du document. Je m'attends à ce que vos dimensions de matrice tf.idf soient 45339 documents par 663307 mots dans le corpus; Manning et al fournissent plus de détails et des exemples de calcul: https://nlp.stanford.edu/IR-book/html/htmledition/term-frequency-and-weighting-1.html

'Mining of Massive Datasets' de Leskovec et al a une tonne de détails sur le hachage des fonctionnalités et tf.idf, les auteurs ont mis le pdf à disposition ici: http://www.mmds.org/

redhqs
la source
1
Si vous tfidf vectorizeravez besoin d'un dictionnaire complet de mots pour les calculs idf, les termes de la matrice tfidf ne devraient-ils pas être supérieurs aux termes de la matrice de hachage?
Minu
2
Si la matrice de hachage est plus large que le dictionnaire, cela signifie que de nombreuses entrées de colonne dans la matrice de hachage seront vides, et pas seulement parce qu'un document donné ne contient pas de terme spécifique, mais parce qu'elles sont vides dans l'ensemble matrice. Légèrement hors sujet, mais effectuez-vous un traitement des mots dans vos documents avant de les vectoriser? Mots vides, stemming, etc.?
redhqs
Oui, je traite. J'utilise Spacy.
Minu
1
Confirmation: Donc, 1048576 est la longueur par défaut de toute matrice de hachage si n_features n'est pas mentionné? S'il n'y a vraiment que 663307 mots dans le corpus, les 385269 fonctionnalités restantes sont vides. Comment rendre cette matrice de hachage ajustée sans toutes les fonctionnalités vides?
Minu
1
C'est vrai - vous pouvez redimensionner le nombre de fonctionnalités en modifiant le paramètre n_features=1048576, si vous avez le temps, essayez 640k, 320k et voyez si cela a beaucoup d'impact sur votre précision. Cela devrait au moins accélérer votre temps d'entraînement. Voir la réponse de @ Nathan pour n_features=5!
redhqs
5

A HashingVectorizerun paramètre n_featuresqui est 1048576par défaut. Lors du hachage, ils ne calculent pas réellement un dictionnaire mappant les termes à un index unique à utiliser pour chacun. Au lieu de cela, vous hachez juste chaque terme et utiliser une assez grande taille que vous ne vous attendez pas qu'il y ait trop de collisions: hash(term) mod table_size. Vous pouvez faire en sorte que la matrice retournée soit de la taille que vous souhaitez en définissant n_features. Vous devez régler cela pour être dans le bon stade pour votre corpus si vous ne pensez pas que la valeur par défaut est raisonnable (une taille plus grande entraînera moins de collisions même si cela prend plus de mémoire).

from sklearn.feature_extraction.text import HashingVectorizer
vectorizer = HashingVectorizer()
print(vectorizer.transform(['a very small document']).shape)
(1, 1048576)

small_vectorizer = HashingVectorizer(n_features=5)
print(small_vectorizer.transform(['a very small document']).shape)    
(1, 5)
Nathan
la source
0

HashingVectorizer et CountVectorizer (notez pas Tfidfvectorizer) sont censés faire la même chose. Ce qui consiste à convertir une collection de documents texte en une matrice d'occurrences de jetons.

Si vous cherchez à obtenir des fréquences de terme pondérées par leur importance relative (IDF), alors Tfidfvectorizer est ce que vous devez utiliser. Si vous avez besoin des comptes bruts ou des comptes normalisés (fréquence des termes), vous devez utiliser CountVectorizer ou HashingVectorizer.

Pour en savoir plus sur HashingVectorizer, consultez cet article sur HashingVectorizer vs CountVectorizer .

Pour plus d'informations sur Tfidfvectorizer, consultez cet article sur la façon d'utiliser Tfidftransformer et Tfidfvectorizer .

kavgan
la source