class_docstr: Ensemble Latent Dirichlet Allocation (eLDA), a method of training a topic model ensemble.
  
  Extracts stable topics that are consistently learned across multiple LDA models. eLDA has the added benefit that
  the user does not need to know the exact number of topics the topic model should extract ahead of time.
class_docstr_tok: ["Ensemble","Latent","Dirichlet","Allocation","(","eLDA",")",",","a","method","of","training","a","topic","model","ensemble",".","Extracts","stable","topics","that","are","consistently","learned","across","multiple","LDA","models",".","eLDA","has","the","added","benefit","that","the","user","does","not","need","to","know","the","exact","number","of","topics","the","topic","model","should","extract","ahead","of","time","."]
docstr: Add the topic term distribution array (ttda) of another model to the ensemble.
  
  This way, multiple topic models can be connected to an ensemble manually. Make sure that all the models use
  the exact same dictionary/idword mapping.
  
  In order to generate new stable topics afterwards, use:
      2. ``self.``:meth:`~gensim.models.ensemblelda.EnsembleLda.recluster`
  
  The ttda of another ensemble can also be used, in that case set ``num_new_models`` to the ``num_models``
  parameter of the ensemble, that means the number of classic models in the ensemble that generated the ttda.
  This is important, because that information is used to estimate "min_samples" for _generate_topic_clusters.
  
  If you trained this ensemble in the past with a certain Dictionary that you want to reuse for other
  models, you can get it from: ``self.id2word``.
  
  Parameters
  ----------
  target : {see description}
      1. A single EnsembleLda object
      2. List of EnsembleLda objects
      3. A single Gensim topic model (e.g. (:py:class:`gensim.models.LdaModel`)
      4. List of Gensim topic models
  
      if memory_friendly_ttda is True, target can also be:
      5. topic-term-distribution-array
  
      example: [[0.1, 0.1, 0.8], [...], ...]
  
      [topic1, topic2, ...]
      with topic being an array of probabilities:
      [token1, token2, ...]
  
      token probabilities in a single topic sum to one, therefore, all the words sum to len(ttda)
  
  num_new_models : integer, optional
      the model keeps track of how many models were used in this ensemble. Set higher if ttda contained topics
      from more than one model. Default: None, which takes care of it automatically.
  
      If target is a 2D-array of float values, it assumes 1.
  
      If the ensemble has ``memory_friendly_ttda`` set to False, then it will always use the number of models in
      the target parameter.
docstr_tok: ["Add","the","topic","term","distribution","array","(","ttda",")","of","another","model","to","the","ensemble",".","This","way",",","multiple","topic","models","can","be","connected","to","an","ensemble","manually",".","Make","sure","that","all","the","models","use","the","exact","same","dictionary\/idword","mapping",".","In","order","to","generate","new","stable","topics","afterwards",",","use",":","2",".","``","self.","``",":","meth",":","`","~gensim.models.ensemblelda.EnsembleLda.recluster","`","The","ttda","of","another","ensemble","can","also","be","used",",","in","that","case","set","``","num_new_models","``","to","the","``","num_models","``","parameter","of","the","ensemble",",","that","means","the","number","of","classic","models","in","the","ensemble","that","generated","the","ttda",".","This","is","important",",","because","that","information","is","used","to","estimate","``","min_samples","''","for","_generate_topic_clusters",".","If","you","trained","this","ensemble","in","the","past","with","a","certain","Dictionary","that","you","want","to","reuse","for","other","models",",","you","can","get","it","from",":","``","self.id2word","``",".","Parameters","--","--","--","--","--","target",":","{","see","description","}","1",".","A","single","EnsembleLda","object","2",".","List","of","EnsembleLda","objects","3",".","A","single","Gensim","topic","model","(","e.g",".","(",":","py",":","class",":","`","gensim.models.LdaModel","`",")","4",".","List","of","Gensim","topic","models","if","memory_friendly_ttda","is","True",",","target","can","also","be",":","5.","topic-term-distribution-array","example",":","[","[","0.1",",","0.1",",","0.8","]",",","[","...","]",",","...","]","[","topic1",",","topic2",",","...","]","with","topic","being","an","array","of","probabilities",":","[","token1",",","token2",",","...","]","token","probabilities","in","a","single","topic","sum","to","one",",","therefore",",","all","the","words","sum","to","len","(","ttda",")","num_new_models",":","integer",",","optional","the","model","keeps","track","of","how","many","models","were","used","in","this","ensemble",".","Set","higher","if","ttda","contained","topics","from","more","than","one","model",".","Default",":","None",",","which","takes","care","of","it","automatically",".","If","target","is","a","2D-array","of","float","values",",","it","assumes","1",".","If","the","ensemble","has","``","memory_friendly_ttda","``","set","to","False",",","then","it","will","always","use","the","number","of","models","in","the","target","parameter","."]
code: def add_model(self, target, num_new_models=None):
      """Add the topic term distribution array (ttda) of another model to the ensemble.
  
      This way, multiple topic models can be connected to an ensemble manually. Make sure that all the models use
      the exact same dictionary/idword mapping.
  
      In order to generate new stable topics afterwards, use:
          2. ``self.``:meth:`~gensim.models.ensemblelda.EnsembleLda.recluster`
  
      The ttda of another ensemble can also be used, in that case set ``num_new_models`` to the ``num_models``
      parameter of the ensemble, that means the number of classic models in the ensemble that generated the ttda.
      This is important, because that information is used to estimate "min_samples" for _generate_topic_clusters.
  
      If you trained this ensemble in the past with a certain Dictionary that you want to reuse for other
      models, you can get it from: ``self.id2word``.
  
      Parameters
      ----------
      target : {see description}
          1. A single EnsembleLda object
          2. List of EnsembleLda objects
          3. A single Gensim topic model (e.g. (:py:class:`gensim.models.LdaModel`)
          4. List of Gensim topic models
  
          if memory_friendly_ttda is True, target can also be:
          5. topic-term-distribution-array
  
          example: [[0.1, 0.1, 0.8], [...], ...]
  
          [topic1, topic2, ...]
          with topic being an array of probabilities:
          [token1, token2, ...]
  
          token probabilities in a single topic sum to one, therefore, all the words sum to len(ttda)
  
      num_new_models : integer, optional
          the model keeps track of how many models were used in this ensemble. Set higher if ttda contained topics
          from more than one model. Default: None, which takes care of it automatically.
  
          If target is a 2D-array of float values, it assumes 1.
  
          If the ensemble has ``memory_friendly_ttda`` set to False, then it will always use the number of models in
          the target parameter.
  
      """
      # If the model has never seen a ttda before, initialize.
      # If it has, append.
  
      # Be flexible. Can be a single element or a list of elements
      # make sure it is a numpy array
      if not isinstance(target, (np.ndarray, list)):
          target = np.array([target])
      else:
          target = np.array(target)
          assert len(target) > 0
  
      if self.memory_friendly_ttda:
          # for memory friendly models/ttdas, append the ttdas to itself
  
          detected_num_models = 0
          ttda = []
  
          # 1. ttda array, because that's the only accepted input that contains numbers
          if isinstance(target.dtype.type(), (np.number, float)):
              ttda = target
              detected_num_models = 1
  
          # 2. list of ensemblelda objects
          elif isinstance(target[0], type(self)):
              ttda = np.concatenate(
                  [ensemble.ttda for ensemble in target], axis=0
              )
              detected_num_models = sum(
                  [ensemble.num_models for ensemble in target]
              )
  
          # 3. list of gensim models
          elif isinstance(target[0], basemodel.BaseTopicModel):
              ttda = np.concatenate(
                  [model.get_topics() for model in target], axis=0
              )
              detected_num_models = len(target)
  
          # unknown
          else:
              raise ValueError(
                  f"target is of unknown type or a list of unknown types: {type(target[0])}"
              )
  
          # new models were added, increase num_models
          # if the user didn't provide a custon numer to use
          if num_new_models is None:
              self.num_models += detected_num_models
          else:
              self.num_models += num_new_models
  
      else:  # memory unfriendly ensembles
          ttda = []
  
          # 1. ttda array
          if isinstance(target.dtype.type(), (np.number, float)):
              raise ValueError(
                  "ttda arrays cannot be added to ensembles, for which memory_friendly_ttda=False, "
                  "you can call convert_to_memory_friendly, but it will discard the stored gensim "
                  "models and only keep the relevant topic term distributions from them."
              )
  
          # 2. list of ensembles
          elif isinstance(target[0], type(self)):
              for ensemble in target:
                  self.tms += ensemble.tms
              ttda = np.concatenate(
                  [ensemble.ttda for ensemble in target], axis=0
              )
  
          # 3. list of gensim models
          elif isinstance(target[0], basemodel.BaseTopicModel):
              self.tms += target.tolist()
              ttda = np.concatenate(
                  [model.get_topics() for model in target], axis=0
              )
  
          # unknown
          else:
              raise ValueError(
                  f"target is of unknown type or a list of unknown types: {type(target[0])}"
              )
  
          # in this case, len(self.tms) should
          # always match self.num_models
          if (
              num_new_models is not None
              and num_new_models + self.num_models != len(self.tms)
          ):
              logger.info(
                  "num_new_models will be ignored. num_models should match the number of "
                  "stored models for a memory unfriendly ensemble"
              )
          self.num_models = len(self.tms)
  
      logger.info(
          f"ensemble contains {self.num_models} models and {len(self.ttda)} topics now"
      )
  
      if self.ttda.shape[1] != ttda.shape[1]:
          raise ValueError(
              f"target ttda dimensions do not match. Topics must be {self.ttda.shape[-1]} but was {ttda.shape[-1]} "
              f"elements large"
          )
  
      self.ttda = np.append(self.ttda, ttda, axis=0)
  
      # tell recluster that the distance matrix needs to be regenerated
      self.asymmetric_distance_matrix_outdated = True
  
imports: import logging
  import os
  from multiprocessing import Process, Pipe, ProcessError
  import importlib
  from typing import Set, Optional, List
  import numpy
  from scipy.spatial.distance import cosine
  from dataclasses import dataclass
  from gensim import utils
  from gensim.models import ldamodel, ldamulticore, basemodel
  from gensim.utils import SaveLoad
label_desc: Use image node_id 6 for calling the EnsembleLda obj's underlying member method code with example usage: obj.add_model(target, num_new_models) without return types