Extração automática de palavras-chave: usando semelhanças de cosseno como recursos

12

Eu tenho uma matriz de termos de documentos e agora gostaria de extrair palavras-chave para cada documento com um método de aprendizado supervisionado (SVM, Naive Bayes, ...). Neste modelo, eu já uso Tf-idf, tag Pos, ...M

Mas agora estou me perguntando sobre os próximos. Eu tenho uma matriz com as semelhanças de cosseno entre os termos.C

Existe a possibilidade de usar essas semelhanças como um recurso para o meu modelo? Minha idéia era para o termo no documento d , para usar a média das semelhanças de cosseno de todos os termos no documento d com o termo i . Isso é útil?EuddEu

Silke
fonte
Você fez uma pesquisa no Google? Eu encontrei um monte de hits em "co-seno similaridade extração de palavras-chave" que parece que eles poderiam ajudar a começar
shadowtalker
Pesquisei bastante no Google e li muitos artigos com as palavras "semelhança de cosseno" e "extração de palavras-chave". Mas eu não encontrou um papel onde eles usam algo como a similaridade do cosseno como recurso para extrair palavras-chave
Silke

Respostas:

11

Não sei como é possível extrair palavras-chave com aprendizado supervisionado, mas sei como fazê-lo com aprendizado não supervisionado.

Existem vários métodos para fazer isso, então aqui estão eles:

Hierárquico

Você pode aplicar qualquer método de cluster hierárquico diretamente ao termo matriz de similaridade (com qualquer função de similaridade, não apenas cosseno)

No scikit-learn, você faria algo assim:

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.cluster import AgglomerativeClustering

vectorizer = TfidfVectorizer(stop_words='english')
X = vectorizer.fit_transform(data)
C = 1 - cosine_similarity(X.T)
ward = AgglomerativeClustering(n_clusters=k, linkage='ward').fit(C)
label = ward.labels_

Fonte: [1]

Mas como é um cluster aglomerado, é computacionalmente caro e levará um tempo para computar.

K-Means

Outra possibilidade é fazer k-means comuns em linhas da matriz termo-documento e, em seguida, encontrar os termos mais comuns para cada centróide

Por exemplo, no scikit learn, é assim que se faz:

from sklearn.cluster import KMeans

km = KMeans(n_clusters=k, init='k-means++', max_iter=100, n_init=1)
km.fit(X)
order_centroids = km.cluster_centers_.argsort()[:, ::-1]
terms = vectorizer.get_feature_names()
for i in range(k):
    print("Cluster %d:" % i, end='')
    for ind in order_centroids[i, :10]:
        print(' %s' % terms[ind], end='')

Fonte: [2]

Mas o k-means depende da distância euclidiana, o que é ruim para dados esparsos de alta dimensão. Existem outras técnicas que funcionam melhor para textos e usam similaridade de cosseno

Cosine K-Meios e Dispersão / Coleta

É possível usar o Cosine com meios K (veja, por exemplo, [3] ): calcule os centróides como uma média em todos os documentos em cada cluster e, em seguida, use o co-seno para calcular a distância do centróide mais próximo.

No final, você pode extrair palavras-chave da mesma maneira que para os k-médias comuns.

Calcular o centróide médio como uma média de todos os documentos no cluster nem sempre é bom. Outra abordagem é sugerida no algoritmo Scatter / Gather [4] : o centróide de um cluster é a concatenação de todos os documentos desse cluster.

Para esta abordagem, você só precisará usar os termos mais frequentes para cada cluster de centróide.

Não há implementação desses algoritmos no scikit learn, mas você pode implementá-los facilmente ampliando KMeans.

Observe que, em ambos os casos, os centróides se tornam bastante densos: mais densos que o restante dos documentos em cada cluster, portanto, você pode truncar termos nos centróides, ou seja, remover os "sem importância". (veja [8]).

Clustering espectral

Outra maneira seria aplicar o agrupamento espectral. Você precisará fornecer uma matriz de similaridade, que você já possui, e ela encontrará clusters nela.

É implementado na SpectralClusteringclasse, veja exemplos em [5] . Observe que, como você já possui uma matriz pré-calculada, é necessário usar o affinity='precumputed'atributo ao inicializar.

O agrupamento espectral está relacionado ao Kernel KMeans: existe um documento (veja [7]) que mostra que eles são a mesma coisa. Recentemente, deparei com uma implementação do Kernel KMeans que pode ser útil: https://gist.github.com/mblondel/6230787

Fatoração matricial não negativa

Finalmente, você pode agrupar sua matriz termo-documento com algumas técnicas de decomposição da Álgebra Linear, como SVD (isso seria chamado "Análise Semântica Latente") ou Fatoração de Matriz Não Negativa. O último pode ser visto como agrupamento e pode agrupar linhas e colunas da matriz ao mesmo tempo.

Por exemplo, você pode extrair palavras-chave fazendo

from sklearn.decomposition import NMF
nmf = NMF(n_components=k, random_state=1).fit(X)

feature_names = vectorizer.get_feature_names()

for topic_idx, topic in enumerate(nmf.components_):
    print("Topic #%d:" % topic_idx)
    print(" ".join([feature_names[i]
                    for i in topic.argsort()[:-10-1:-1]]))
    print()

Fonte do código: [6]

Embora aqui os exemplos estejam no python scikit-learn, acho que não deve ser um grande problema encontrar alguns exemplos para R

Fontes

Alexey Grigorev
fonte
Esta é uma resposta inacreditavelmente de alta qualidade. Obrigado! Você pensa em usar o algoritmo de propagação de afinidade do Scikit para agrupar as palavras? Os valores de semelhança de cosseno podem ser usados ​​(acredito que as semelhanças seriam necessárias, e não distâncias) como uma matriz de afinidade pré-computada no algoritmo.
Neelshiv