class_docstr: !
  @brief Expectation-Maximization clustering algorithm for Gaussian Mixture Model (GMM).
  @details The algorithm provides only clustering services (unsupervised learning).
            Here an example of data clustering process:
  @code
      from pyclustering.cluster.ema import ema, ema_visualizer
      from pyclustering.utils import read_sample
      from pyclustering.samples.definitions import FCPS_SAMPLES
  
      # Read data from text file.
      sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN)
  
      # Create EM algorithm to allocated four clusters.
      ema_instance = ema(sample, 3)
  
      # Run clustering process.
      ema_instance.process()
  
      # Get clustering results.
      clusters = ema_instance.get_clusters()
      covariances = ema_instance.get_covariances()
      means = ema_instance.get_centers()
  
      # Visualize obtained clustering results.
      ema_visualizer.show_clusters(clusters, sample, covariances, means)
  @endcode
  
  Here is clustering results of the Expectation-Maximization clustering algorithm where popular sample 'OldFaithful' was used.
  Initial random means and covariances were used in the example. The first step is presented on the left side of the figure and
  final result (the last step) is on the right side:
  @image html ema_old_faithful_clustering.png
  
  @see ema_visualizer
  @see ema_observer
docstr: !
  @brief Initializes Expectation-Maximization algorithm for cluster analysis.
  
  @param[in] data (list): Dataset that should be analysed and where each point (object) is represented by the list of coordinates.
  @param[in] amount_clusters (uint): Amount of clusters that should be allocated.
  @param[in] means (list): Initial means of clusters (amount of means should be equal to amount of clusters for allocation).
              If this parameter is 'None' then K-Means algorithm with K-Means++ method will be used for initialization by default.
  @param[in] variances (list): Initial cluster variances (or covariances in case of multi-dimensional data). Amount of
              covariances should be equal to amount of clusters that should be allocated. If this parameter is 'None' then
              K-Means algorithm with K-Means++ method will be used for initialization by default.
  @param[in] observer (ema_observer): Observer for gathering information about clustering process.
  @param[in] tolerance (float): Defines stop condition of the algorithm (when difference between current and
              previous log-likelihood estimation is less then 'tolerance' then clustering is over).
  @param[in] iterations (uint): Additional stop condition parameter that defines maximum number of steps that can be
              performed by the algorithm during clustering process.
docstr_tok: ["!","@","brief","Initializes","Expectation-Maximization","algorithm","for","cluster","analysis",".","@","param","[","in","]","data","(","list",")",":","Dataset","that","should","be","analysed","and","where","each","point","(","object",")","is","represented","by","the","list","of","coordinates",".","@","param","[","in","]","amount_clusters","(","uint",")",":","Amount","of","clusters","that","should","be","allocated",".","@","param","[","in","]","means","(","list",")",":","Initial","means","of","clusters","(","amount","of","means","should","be","equal","to","amount","of","clusters","for","allocation",")",".","If","this","parameter","is","'None","'","then","K-Means","algorithm","with","K-Means++","method","will","be","used","for","initialization","by","default",".","@","param","[","in","]","variances","(","list",")",":","Initial","cluster","variances","(","or","covariances","in","case","of","multi-dimensional","data",")",".","Amount","of","covariances","should","be","equal","to","amount","of","clusters","that","should","be","allocated",".","If","this","parameter","is","'None","'","then","K-Means","algorithm","with","K-Means++","method","will","be","used","for","initialization","by","default",".","@","param","[","in","]","observer","(","ema_observer",")",":","Observer","for","gathering","information","about","clustering","process",".","@","param","[","in","]","tolerance","(","float",")",":","Defines","stop","condition","of","the","algorithm","(","when","difference","between","current","and","previous","log-likelihood","estimation","is","less","then","'tolerance","'","then","clustering","is","over",")",".","@","param","[","in","]","iterations","(","uint",")",":","Additional","stop","condition","parameter","that","defines","maximum","number","of","steps","that","can","be","performed","by","the","algorithm","during","clustering","process","."]
code: def __init__(
      self,
      data,
      amount_clusters,
      means=None,
      variances=None,
      observer=None,
      tolerance=0.00001,
      iterations=100,
  ):
      """!
      @brief Initializes Expectation-Maximization algorithm for cluster analysis.
  
      @param[in] data (list): Dataset that should be analysed and where each point (object) is represented by the list of coordinates.
      @param[in] amount_clusters (uint): Amount of clusters that should be allocated.
      @param[in] means (list): Initial means of clusters (amount of means should be equal to amount of clusters for allocation).
                  If this parameter is 'None' then K-Means algorithm with K-Means++ method will be used for initialization by default.
      @param[in] variances (list): Initial cluster variances (or covariances in case of multi-dimensional data). Amount of
                  covariances should be equal to amount of clusters that should be allocated. If this parameter is 'None' then
                  K-Means algorithm with K-Means++ method will be used for initialization by default.
      @param[in] observer (ema_observer): Observer for gathering information about clustering process.
      @param[in] tolerance (float): Defines stop condition of the algorithm (when difference between current and
                  previous log-likelihood estimation is less then 'tolerance' then clustering is over).
      @param[in] iterations (uint): Additional stop condition parameter that defines maximum number of steps that can be
                  performed by the algorithm during clustering process.
  
      """
  
      self.__data = numpy.array(data)
      self.__amount_clusters = amount_clusters
      self.__tolerance = tolerance
      self.__iterations = iterations
      self.__observer = observer
  
      self.__means = means
      self.__variances = variances
  
      self.__verify_arguments()
  
      if (means is None) or (variances is None):
          self.__means, self.__variances = ema_initializer(
              data, amount_clusters
          ).initialize(ema_init_type.KMEANS_INITIALIZATION)
  
          if len(self.__means) != amount_clusters:
              self.__amount_clusters = len(self.__means)
  
      self.__rc = [
          [0.0] * len(self.__data) for _ in range(amount_clusters)
      ]
      self.__pic = [1.0] * amount_clusters
      self.__clusters = []
      self.__gaussians = [[] for _ in range(amount_clusters)]
      self.__stop = False
  
imports: import numpy
  import random
  from pyclustering.cluster import cluster_visualizer
  from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer
  from pyclustering.cluster.kmeans import kmeans
  from pyclustering.utils import pi, calculate_ellipse_description, euclidean_distance_square
  from enum import IntEnum
  import matplotlib.pyplot
  import matplotlib.animation
  from matplotlib import patches
label_desc: Use image node_id 1 to create a new ema object  with example: obj = ema(data, amount_clusters, means, variances, observer, tolerance, iterations)