Example #1
0
 def testar_num_topics(
         self,
         modelo,
         num_topicos=[20, 50, 100, 200, 300, 400, 500, 1000, 1500],
         perc_fichas=0.2,
         vetor_testes=None,
         tipo_teste='similaridade'):
     '''
     Testa a coerência dos modelos gerados por tópicos para uma lista de quantidade de tópicos para encontrar
     o melhor número de tópicos para o modelo com relação ao corpus.
     Parâmetros:
         modelo (str) --> Modelo a ser testado: "lda", "lsi" ou "doc2vec".
         num_topicos (list de int) --> Lista de números de tópicos a serem testados
                 (default: [20, 50, 100, 200, 300, 400, 500, 1000, 1500])
         per_fichas (float) --> Percentual de fichas do corpus a serem considerados para o teste (default: 0.2)
         vetor_teste (list de tuple) --> Lista de pares de fichas para testes de similaridade. É ignorado se o teste
             é o "u_mass" (default: None)
         tipo_testes (str) --> Tipo de teste: "u_mass" ou "similaridade" (default: "similaridade")
     Retorno: um dicionário de dicionários. A chave do dicionário principal é o número de tópicos e, para cada número de
         tópicos, há outro dicionário com as seguintes chaves:
             "medida" --> Valor de coerência calculado para o modelo com aquele número de tópicos.
             "modelo" --> O modelo gerado para aquele número de tópicos
     '''
     # Verifica se o teste para o modelo foi implantado
     if modelo not in ['lda', 'lsi', 'doc2vec']:
         print(
             f'O modelo {modelo} ou não é de tópico ou não foi implantado.')
         return
     if tipo_teste not in ['u_mass', 'similaridade']:
         print(f'O tipo de teste {tipo_teste} não foi implementado.')
         return
     if modelo == 'doc2vec' and tipo_teste == 'u_mass':
         print(
             'O teste de coerência com u_mass não pode ser usado para o modelo doc2vec.'
         )
         return
     # Iniciando as variáveis para os testes
     resultado = {}
     arq_index = os.path.join(self.corpus._pastas['indices'],
                              f'{self.corpus._link_nome}_testes.idx')
     if vetor_testes:
         flat = list(zip(*vetor_testes))
         fichas_incluir = set(flat[0])
         fichas_incluir.update(flat[1])
     else:
         fichas_incluir = None
     # Define os corpus de treinamento e o corpus parcial
     if modelo == 'lsi':
         bow = self.corpus.corpus(tipo='bow')
         corpus_parcial = bow.fatiar(perc_fichas=perc_fichas,
                                     incluir=fichas_incluir)
         model_tfidf = self['tfidf'] or TfidfModel(
             corpus=corpus_parcial, id2word=self.corpus.dicionario())
         corpus_train = model_tfidf[corpus_parcial]
     elif modelo == 'lda':
         bow = self.corpus.corpus(tipo='bow')
         corpus_parcial = corpus_train = bow.fatiar(perc_fichas=perc_fichas,
                                                    incluir=fichas_incluir)
     elif modelo == 'doc2vec':
         corpus_tagged = self.corpus.corpus(tipo='tagged')
         corpus_parcial = corpus_train = corpus_tagged.fatiar(
             perc_fichas=perc_fichas, incluir=fichas_incluir)
     # Obtém a relação dos ids_fichas do corpus parcial
     if fichas_incluir: ids_fichas = corpus_parcial.fichas()
     else: ids_fichas = list(range(len(corpus_parcial)))
     # Faz o teste para cada quantidade de tópicos
     for num in tqdm(num_topicos):
         print(f'Criando modelo "{modelo}" para num_topics={num}')
         # Treina os modelo solicitado
         if modelo == 'lda':
             model = LdaModel(corpus=corpus_train,
                              id2word=self.corpus.dicionario(),
                              num_topics=num)
         elif modelo == 'lsi':
             model = LsiModel(corpus=corpus_train,
                              id2word=self.corpus.dicionario(),
                              num_topics=num)
         elif modelo == 'doc2vec':
             model = Doc2Vec(vector_size=num,
                             workers=mp.cpu_count() / 2,
                             alpha=self._modelos[modelo]['alpha'],
                             min_alpha=self._modelos[modelo]['min_alpha'])
             # Obtém o vocabulário do corpus para treinar o modelo Doc2Vec
             model.build_vocab(corpus_train)
             # Treina o modelo Doc2Vec
             model.train(corpus_train,
                         total_examples=model.corpus_count,
                         epochs=model.epochs)
         # Salva o modelo construído para o número de tópicos da iteração
         resultado[num] = {'modelo': model}
         # Realiza o teste de coerência
         if tipo_teste == 'u_mass':
             # Calcula a coerência do modelo para o número de tópicos setado
             print(
                 f'Calculando o score de coerência do modelo "{modelo}" para num_topics={num}'
             )
             cm = CoherenceModel(model=model,
                                 corpus=corpus_train,
                                 coherence='u_mass')
             resultado[num]['medida'] = cm.get_coherence()
             print(f'Score u_mass = {resultado[num]["medida"]}')
         # Realiza o teste de similaridade
         elif tipo_teste == 'similaridade':
             # Define o corpus para a matriz de similaridade
             if modelo == 'doc2vec': corpus = Doc2VecCorpus(model)
             else: corpus = model[corpus_train]
             # Calcula a similaridade do modelo para o número de tópicos setado
             print(
                 f'Calculando o score de similaridade do modelo "{modelo}" para num_topics={num}'
             )
             index = Similarity(output_prefix=arq_index,
                                corpus=corpus,
                                num_features=num)
             medidas = []
             for ficha_query, ficha_target in vetor_testes:
                 id_query = self.corpus.ficha2id(ficha_query)
                 query = ids_fichas.index(id_query)
                 id_target = self.corpus.ficha2id(ficha_target)
                 target = ids_fichas.index(id_target)
                 posicao, _ = self._obter_posicao_target(
                     index, query, target)
                 medidas.append(1 / posicao)
             valores = pd.Series(medidas)
             resultado[num]['medida'] = valores.median()
             print(f'Score similaridade = {resultado[num]["medida"]}')
     return resultado