[PYTHON] Classification de texte non supervisée avec Doc2Vec et k-means

Lorsque la classification de texte a été effectuée à l'aide de données classées par les humains comme données d'enseignants, les effets néfastes de l'intervention humaine entre les données sont apparus, j'ai donc créé un classificateur de texte sans enseignant.

Problèmes causés par l'étiquetage humain

Matériel de référence

Ce que j'ai fait

Je regrette qu'il valait mieux classer par algorithme graphique plutôt que par k-means. La raison est qu'il n'y a qu'un nombre limité de documents qui produisent une similitude lorsqu'ils sont calculés avec Doc2Vec. Avec k-means, vous devez construire une matrice creuse une fois, mais si vous classifiez avec un algorithme de graphe, vous n'avez pas à vous soucier de perdre de la mémoire. ..

Avantages de la création de fonctionnalités avec Doc2Vec

Code de référence

Je suis désolé que les commentaires soient mélangés avec du japonais et de l'anglais, et le code est assez sale. ..

# coding: utf-8

from gensim import corpora, models
import numpy as np
from numpy import random
random.seed(555)
from scipy.cluster.vq import vq, kmeans, whiten
from sklearn.decomposition import TruncatedSVD
from collections import defaultdict
from separatewords import MecabTokenize  #Veuillez appeler un analyseur morphologique adapté à vos besoins.


class MyTexts:
    def __init__(self, text_list):
        self.text_list = text_list

    def __iter__(self):
        for line in self.text_list:
            if line==b'Non entré': continue
            yield MecabTokenize.tokenize( line.rstrip().decode('utf-8') )


class LabeledLineSentence(object):
    def __init__(self, texts_words):
        self.texts_words = texts_words

    def __iter__(self):
        for uid, words in enumerate(self.texts_words):
            yield models.doc2vec.LabeledSentence(words, labels=['SENT_%s' % uid])


#Définir la similitude de chaque phrase acquise par Doc2Vec avec la matrice
#De plus, obtenez le mot représentatif de chaque phrase
def create_sim_vec(model,n_sent):
    base_name = 'SENT_'
    sim_matrix = []
    sim_matrix_apd = sim_matrix.append
    word_matrix = []
    word_matrix_apd = word_matrix.append
    for i_sent in xrange(n_sent):
        sim_vec = np.zeros(n_sent)
        word_list = []
        word_list_apd = word_list.append
        #Comme envoyé peut ne pas exister, incluez la gestion des exceptions
        try:
            for word, sim_val in model.most_similar(base_name+str(i_sent)):
                if 'SENT_' in word:
                    _, s_idx = word.split('_')
                    sim_vec[int(s_idx)] = sim_val
                else:
                    word_list_apd(word)
        except:
            pass
        sim_matrix_apd(sim_vec)
        word_matrix_apd(word_list)
    return sim_matrix, word_matrix

#Organiser des documents similaires avec kmeans
def sent_integrate(sim_matrix,n_class):
    #Distribution uniforme pour chaque dimension
    whiten(sim_matrix)

    centroid, destortion = kmeans(sim_matrix, n_class, iter=100, thresh=1e-05)
    labels, dist = vq(sim_matrix, centroid)
    return labels

def count_class(labels):
    res_dic = defaultdict(int)
    for label in labels:
        res_dic[label] += 1
    return res_dic

def count_labeled_data(label_data, labels):
    result_dict = {}
    for orig_labels, label in zip(label_data, labels):
        labels = np.array(orig_labels.split(), dtype=np.int64)
        if label not in result_dict:
            result_dict[label] = labels
        else:
            result_dict[label] += labels
    return result_dict


if __name__=='__main__':
    ifname = './out_data.csv'
    model_basename = './D2V/doc2vec_result/model'
    topic_result_basename = './D2V/doc2vec_result/topic'

    comment_data = []
    comment_data_apd = comment_data.append
    label_data = []
    label_data_apd = label_data.append
    with open(ifname, 'r') as f:
        for line in f:
            single_flag, label_flags, comment = line.strip().split('\t')
            comment_data_apd(comment.strip())
            label_data_apd(label_flags.strip())

    texts = MyTexts(comment_data)
    sentences = LabeledLineSentence(texts)
    model = models.Doc2Vec(alpha=0.025, min_alpha=0.025)  # use fixed learning rate
    model.build_vocab(sentences)

    # store the model to mmap-able files
    model.save(model_basename+'.d2v')

    # load the model back
    model_loaded = models.Doc2Vec.load(model_basename+'.d2v')

    epoch = 10
    for _ in xrange(epoch):
        model.train(sentences)
        model.alpha -= 0.002  # decrease the learning rate
        model.min_alpha = model.alpha  # fix the learning rate, no decay
    print 'done training'

    # show topic
    n_sent = len(comment_data)
    sent_matrix, word_matrix = create_sim_vec(model, n_sent)
    print 'done get sent_matrix'

    ##Rassemblez des documents similaires
    #Compression de données par svd(Données denses)
    np.savetxt('./D2V/sent_matrix', np.array(sent_matrix))
    dimension = 100
    lsa = TruncatedSVD(dimension)
    info_matrix = lsa.fit_transform(sent_matrix)
    np.savetxt('./D2V/info_matrix', np.array(info_matrix))

    #Mise en œuvre des kmeans
    n_class = 7
    labels = sent_integrate(np.array(info_matrix),n_class)
    np.savetxt('./D2V/sent_labels.csv', labels,delimiter=',', fmt='%d')
    print count_class(labels)

    #Comparaison avec ce que les humains ont classé
    print count_labeled_data(label_data, labels)

Les données utilisées sont une ligne composée de (0 \ t1 0 1 0 0 0 0 \ txxxx). Les étiquettes étiquetées par l'homme sont marquées de 7 01 indicateurs séparés par des espaces.

commentaire

Ce n'est pas crédible car les résultats des données expérimentales ne sont pas joints. En vérifiant visuellement 2000 éléments de données, environ 80% ont été classés sans aucune gêne. Au contraire, quand j'ai regardé les étiquettes attachées par les humains, il y en avait environ 30% qui n'avaient pas de sens. (Quelle est la différence de sensibilité ...)

Récemment, j'ai publié un article sans expliquer la méthode ni publier de données expérimentales. Je veux écrire un article (j'aimerais pouvoir l'écrire) sans couper les coins ronds à l'avenir. Nous vous prions de nous excuser pour la gêne occasionnée, mais nous vous serions reconnaissants de bien vouloir signaler toute erreur.

Recommended Posts

Classification de texte non supervisée avec Doc2Vec et k-means
Classification des documents avec texte toch de PyTorch
k-means et kernel k-means
Classification des textes du défi par Naive Bayes avec sklearn
kmeans ++ avec scikit-learn
Filtrage coordonné avec analyse des composants principaux et clustering K-means
Text mining avec Python-Scraping-
Pythonbrew avec Sublime Text
Avec et sans WSGI
Classification de texte à l'aide de la convolution (CNN) et du regroupement de pyramides spatiales (SPP-net)
Apprenez les catégories de texte japonais avec tf-idf et Random Forest ~ [Tuning]
Classification d'images avec un réseau de neurones auto-fabriqué par Keras et PyTorch