code: def expectation_maximization_fit(
      observation_intervals,
      turnbull_intervals,
      turnbull_lookup,
      weights,
      tol,
      max_iter,
      optimize,
      verbose,
  ):
      # convergence init
      converged = False
      i = 0
  
      # initialize to equal weight
      T = len(turnbull_intervals)
      p = 1 / T * np.ones(T)
  
      while (not converged) and (i < max_iter):
          new_p = E_step_M_step(
              observation_intervals,
              p,
              turnbull_lookup,
              weights,
              i,
              optimize,
          )
          converged = check_convergence(
              new_p,
              p,
              turnbull_lookup,
              weights,
              tol,
              i,
              verbose=verbose,
          )
  
          # find alpha that maximizes ll using a line search
          best_p, best_ll = p, -np.inf
          delta = log_odds(new_p) - log_odds(p)
          for alpha in np.array([1.0, 1.25, 1.95]):
              p_temp = probs(log_odds(p) + alpha * delta)
              ll_temp = log_likelihood(p_temp, turnbull_lookup, weights)
              if best_ll < ll_temp:
                  best_ll = ll_temp
                  best_p = p_temp
  
          p = best_p
  
          i += 1
  
      if i >= max_iter:
          warnings.warn("Exceeded max iterations.", ConvergenceWarning)
  
      return p
  
imports: from collections import defaultdict, namedtuple
  import warnings
  import numpy
  from numpy.linalg import norm
  import pandas
  from lifelines.exceptions import ConvergenceWarning
  from typing import *
label_desc: Use image node_id 13 for calling a global function with example usage: expectation_maximization_fit(observation_intervals, turnbull_intervals, turnbull_lookup, weights, tol, max_iter, optimize, verbose) and returns: p