class_docstr: Class used to compute parameters for a model using Expectation
  Maximization (EM).
  
  EM is an iterative algorithm commonly used for
  estimation in the case when there are latent variables in the model.
  The algorithm iteratively improves the parameter estimates maximizing
  the likelihood of the given data.
  
  Parameters
  ----------
  model: A pgmpy.models.BayesianNetwork instance
  
  data: pandas DataFrame object
      DataFrame object with column names identical to the variable names
      of the network.  (If some values in the data are missing the data
      cells should be set to `numpy.NaN`.  Note that pandas converts each
      column containing `numpy.NaN`s to dtype `float`.)
  
  state_names: dict (optional)
      A dict indicating, for each variable, the discrete set of states
      that the variable can take. If unspecified, the observed values in
      the data set are taken to be the only possible states.
  
  Examples
  --------
  >>> import numpy as np
  >>> import pandas as pd
  >>> from pgmpy.models import BayesianNetwork
  >>> from pgmpy.estimators import ExpectationMaximization
  >>> data = pd.DataFrame(np.random.randint(low=0, high=2, size=(1000, 5)),
  ...                       columns=['A', 'B', 'C', 'D', 'E'])
  >>> model = BayesianNetwork([('A', 'B'), ('C', 'B'), ('C', 'D'), ('B', 'E')])
  >>> estimator = ExpectationMaximization(model, data)
class_docstr_tok: ["Class","used","to","compute","parameters","for","a","model","using","Expectation","Maximization","(","EM",")",".","EM","is","an","iterative","algorithm","commonly","used","for","estimation","in","the","case","when","there","are","latent","variables","in","the","model",".","The","algorithm","iteratively","improves","the","parameter","estimates","maximizing","the","likelihood","of","the","given","data",".","Parameters","--","--","--","--","--","model",":","A","pgmpy.models.BayesianNetwork","instance","data",":","pandas","DataFrame","object","DataFrame","object","with","column","names","identical","to","the","variable","names","of","the","network",".","(","If","some","values","in","the","data","are","missing","the","data","cells","should","be","set","to","`","numpy.NaN","`",".","Note","that","pandas","converts","each","column","containing","`","numpy.NaN","`","s","to","dtype","`","float","`",".",")","state_names",":","dict","(","optional",")","A","dict","indicating",",","for","each","variable",",","the","discrete","set","of","states","that","the","variable","can","take",".","If","unspecified",",","the","observed","values","in","the","data","set","are","taken","to","be","the","only","possible","states",".","Examples","--","--","--","--",">",">",">","import","numpy","as","np",">",">",">","import","pandas","as","pd",">",">",">","from","pgmpy.models","import","BayesianNetwork",">",">",">","from","pgmpy.estimators","import","ExpectationMaximization",">",">",">","data","=","pd.DataFrame","(","np.random.randint","(","low=0",",","high=2",",","size=","(","1000",",","5",")",")",",","...","columns=","[","'","A","'",",","'","B","'",",","'","C","'",",","'D","'",",","'","E","'","]",")",">",">",">","model","=","BayesianNetwork","(","[","(","'","A","'",",","'","B","'",")",",","(","'","C","'",",","'","B","'",")",",","(","'","C","'",",","'D","'",")",",","(","'","B","'",",","'","E","'",")","]",")",">",">",">","estimator","=","ExpectationMaximization","(","model",",","data",")"]
code: def _parallel_compute_weights(
      self, data_unique, latent_card, n_counts, offset, batch_size
  ):
      cache = []
  
      for i in range(
          offset, min(offset + batch_size, data_unique.shape[0])
      ):
          v = list(
              product(*[range(card) for card in latent_card.values()])
          )
          latent_combinations = np.array(v, dtype=int)
          df = data_unique.iloc[
              [i] * latent_combinations.shape[0]
          ].reset_index(drop=True)
          for index, latent_var in enumerate(latent_card.keys()):
              df[latent_var] = latent_combinations[:, index]
          weights = np.e ** (
              df.apply(
                  lambda t: self._get_log_likelihood(dict(t)), axis=1
              )
          )
          df["_weight"] = (weights / weights.sum()) * n_counts[
              tuple(data_unique.iloc[i])
          ]
          cache.append(df)
  
      return pd.concat(cache, copy=False)
  
file_path: pgmpy/pgmpy/estimators/EM.py
imports: from itertools import chain, product
  from math import log
  import numpy
  import pandas
  from joblib import Parallel, delayed
  from tqdm.auto import tqdm
  from pgmpy import config
  from pgmpy.estimators import MaximumLikelihoodEstimator, ParameterEstimator
  from pgmpy.factors.discrete import TabularCPD
  from pgmpy.models import BayesianNetwork
label_desc: Use image node_id 3 for calling the ExpectationMaximization obj's underlying member method code with example usage: obj._parallel_compute_weights(data_unique, latent_card, n_counts, offset, batch_size) and returns: pd