Je ne sais pas comment il est possible de faire l'extraction de mots clés avec un apprentissage supervisé, mais je sais comment le faire avec un apprentissage non supervisé.
Il existe plusieurs méthodes pour le faire, les voici donc:
Hiérarchique
Vous pouvez appliquer n'importe quelle méthode de clustering hiérarchique sur le terme matrice de similarité directement (avec n'importe quelle fonction de similarité, pas seulement cosinus)
Dans scikit-learn, vous feriez quelque chose comme ceci:
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_
Source: [1]
Mais comme il s'agit d'un cluster agglomératif, il est coûteux en calcul et le calcul prendra un certain temps.
K-Means
Une autre possibilité consiste à faire les k-moyennes habituelles sur les lignes de la matrice terme-document, puis à trouver les termes les plus courants pour chaque centroïde
Par exemple, dans scikit, apprenez que c'est la façon de procéder:
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='')
Source: [2]
Mais k-means s'appuie sur la distance euclidienne, ce qui est mauvais pour les données clairsemées de haute dimension. Il existe d'autres techniques qui fonctionnent mieux pour les textes et utilisent la similitude cosinus
Cosinus K-Means et Scatter / Gather
Il est possible d'utiliser le cosinus avec les moyennes K (voir par exemple [3] ): calculer les centroïdes comme moyenne sur tous les documents de chaque cluster, puis utiliser le cosinus pour calculer la distance au centroïde le plus proche.
À la fin, vous pouvez extraire des mots clés de la même manière que pour les k-means habituels.
Le calcul du centroïde moyen en tant que moyenne de tous les documents du cluster n'est pas toujours bon. Une autre approche est suggérée dans l'algorithme Scatter / Gather [4] : le centroïde d'un cluster est la concaténation de tous les documents de ce cluster.
Pour cette approche, vous devrez simplement prendre les termes les plus fréquents pour chaque cluster centroïde.
Il n'y a pas d'implémentation de ces algorithmes dans scikit learn, mais vous pouvez facilement les implémenter vous-même en les étendant KMeans
.
Notez que dans les deux cas, les centroïdes deviennent assez denses: plus denses que le reste des documents dans chaque cluster, vous pouvez donc vouloir tronquer les termes dans les centroïdes, c'est-à-dire supprimer ceux "sans importance". (voir [8]).
Regroupement spectral
Une autre façon serait d'appliquer un regroupement spectral. Vous devrez fournir une matrice de similitude, que vous avez déjà, et elle y trouvera des clusters.
Il est implémenté dans la SpectralClustering
classe, voir des exemples dans [5] . Notez que puisque vous avez déjà une matrice pré-calculée, vous devez utiliser l' affinity='precumputed'
attribut lors de l'initialisation.
Le regroupement spectral est lié aux Kernel KMeans: il y a du papier (voir [7]) qui montre que c'est la même chose. J'ai récemment rencontré une implémentation de Kernel KMeans qui peut être utile: https://gist.github.com/mblondel/6230787
Factorisation matricielle non négative
Enfin, vous pouvez regrouper votre matrice terme-document avec certaines techniques de décomposition de l'algèbre linéaire, comme SVD (ce serait ce qu'on appelle "l'analyse sémantique latente") ou la factorisation matricielle non négative. Ce dernier peut être considéré comme un clustering, et il peut regrouper à la fois des lignes et des colonnes de la matrice.
Par exemple, vous pouvez extraire des mots clés en faisant
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()
Source du code: [6]
Même si ici les exemples sont en python scikit-learn, je pense que cela ne devrait pas être un gros problème de trouver des exemples pour R
Sources