Qual é a diferença entre um vetorizador de hash e um vetorizador de tfidf


11

Estou convertendo um corpus de documentos de texto em vetores de palavras para cada documento. Eu tentei isso usando um TfidfVectorizer e um HashingVectorizer

Entendo que um HashingVectorizernão leva em consideração as IDFpontuações como um TfidfVectorizerfaz. A razão pela qual ainda estou trabalhando com a HashingVectorizeré a flexibilidade que ela oferece ao lidar com grandes conjuntos de dados, conforme explicado aqui e aqui . (Meu conjunto de dados original possui 30 milhões de documentos)

Atualmente, estou trabalhando com uma amostra de 45339 documentos, portanto, tenho a capacidade de trabalhar com uma TfidfVectorizertambém. Quando uso esses dois vetorizadores nos mesmos documentos 45339, as matrizes que recebo são diferentes.

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

forma da matriz de hash (45339, 1048576)

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

forma da matriz tfidf (45339, 663307)

Quero entender melhor as diferenças entre a HashingVectorizere a TfidfVectorizer, e a razão pela qual essas matrizes têm tamanhos diferentes - particularmente no número de palavras / termos.


Você pode compartilhar o conjunto de dados comigo? (resposta a ser removida)
nKarza

Respostas:


7

A principal diferença é que HashingVectorizeraplica uma função de hash às contagens de frequência de termo em cada documento, onde TfidfVectorizerdimensiona essas contagens de frequência de termo em cada documento penalizando termos que aparecem mais amplamente no corpus. Há um ótimo resumo aqui: https://spark.apache.org/docs/latest/mllib-feature-extraction.html

  • As funções de hash são uma maneira eficiente de mapear termos para recursos; ele não precisa necessariamente ser aplicado apenas a frequências a termo, mas é assim que HashingVectorizeré empregado aqui. Junto com os documentos 45339, suspeito que o vetor de recurso tenha o comprimento 1048576 porque é o padrão 2 ^ 20 n_features; você pode reduzir isso e tornar o processo mais barato, mas com um risco maior de colisão, onde a função mapeia termos diferentes para o mesmo recurso: http://preshing.com/20110504/hash-collision-probabilities/

  • Dependendo do caso de uso dos vetores de palavras, pode ser possível reduzir significativamente o comprimento do vetor de recurso de hash (e, portanto, a complexidade) com perda aceitável de precisão / eficácia (devido ao aumento da colisão). O Scikit-learn possui alguns parâmetros de hash que podem ajudar, por exemplo alternate_sign.

  • Se a matriz de hash for maior que o dicionário, isso significará que muitas das entradas da coluna na matriz de hash estarão vazias, e não apenas porque um determinado documento não contém um termo específico, mas porque elas estão vazias no conjunto. matriz. Caso contrário, poderá enviar vários termos para o mesmo hash do recurso - é sobre a "colisão" que estamos falando. HashingVectorizertem uma configuração que funciona para atenuar essa chamada ativada alternate_signpor padrão, descrita aqui: en.wikipedia.org/wiki/Feature_hashing#Properties

  • 'Frequência de termos - frequência inversa de documentos' pega frequências de termos em cada documento e as pondera penalizando palavras que aparecem com mais frequência em todo o corpus. A intuição é que os termos encontrados situacionalmente têm maior probabilidade de serem representativos do tópico de um documento específico. Isso é diferente de uma função de hash, pois é necessário ter um dicionário completo de palavras no corpus para calcular a frequência inversa do documento. Espero que suas dimensões da matriz tf.idf sejam 45339 documentos por 663307 palavras no corpus; Manning et al fornecem mais detalhes e exemplos de cálculo: https://nlp.stanford.edu/IR-book/html/htmledition/term-frequency-and-weighting-1.html

'Mining of Massive Datasets' de Leskovec et al. Tem muitos detalhes sobre hash de recursos e tf.idf, os autores disponibilizaram o pdf aqui: http://www.mmds.org/


11
Se tfidf vectorizerprecisar de um dicionário completo de palavras para cálculos do IDF, os termos na matriz tfidf não deveriam ser mais do que os termos na matriz de hash?
Minu

2
Se a matriz de hash for maior que o dicionário, isso significará que muitas das entradas da coluna na matriz de hash estarão vazias, e não apenas porque um determinado documento não contém um termo específico, mas porque elas estão vazias no conjunto. matriz. Um pouco fora do tópico, mas você está processando as palavras em seus documentos antes de vetorizar? Stopwords, stemming, etc?
Redhqs

Sim, estou processando. Estou usando o Spacy.
Minu

11
Confirmação: 1048576 é o comprimento padrão de qualquer matriz de hash se n_features não for mencionado? Se realmente houver apenas 663307 palavras no corpus, os 385269 recursos restantes estarão vazios. Como tornar essa matriz de hash confortável sem todos os recursos vazios?
Minu

11
É isso mesmo - você pode redimensionar o número de recursos alterando o parâmetro n_features=1048576, se tiver tempo, experimente 640k, 320k e veja se isso afeta bastante sua precisão. Deve acelerar pelo menos o seu tempo de treinamento. Veja a resposta de @ Nathan para n_features=5!
Redhqs

5

O HashingVectorizertem um parâmetro n_featuresque é 1048576por padrão. Ao fazer o hash, eles não calculam os termos de mapeamento de dicionário para um índice exclusivo a ser usado em cada um. Em vez disso, você só botar para cada termo e usar um tamanho grande o suficiente para que você não esperar que haja muitas colisões: hash(term) mod table_size. Você pode fazer com que a matriz retornada seja do tamanho que desejar, definindo n_features. Você deve ajustá-lo para estar no estádio certo para o seu corpus, se não achar que o padrão é razoável (tê-lo maior causará menos colisões, embora consuma mais memória).

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)

0

HashingVectorizer e CountVectorizer (note que não Tfidfvectorizer) devem fazer a mesma coisa. Que é converter uma coleção de documentos de texto em uma matriz de ocorrências de token.

Se você deseja obter frequências de termo ponderadas por sua importância relativa (IDF), o Tfidfvectorizer é o que você deve usar. Se você precisar de contagens brutas ou normalizadas (frequência de termo), use CountVectorizer ou HashingVectorizer.

Para aprender sobre o HashingVectorizer, consulte este artigo em HashingVectorizer vs. CountVectorizer .

Para obter mais informações sobre o Tfidfvectorizer, consulte este artigo em Como usar o Tfidftransformer e o Tfidfvectorizer .

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.