def zip_estimate_state(data, clusters, init_means=None, init_weights=None, max_iters=<NUM_LIT:10>, tol=<NUM_LIT>, disp=True, inner_max_iters=<NUM_LIT>, normalize=True):
genes, cells = data.shape<EOL>if init_means is None:<EOL><INDENT>means, assignments = kmeans_pp(data, clusters)<EOL><DEDENT>else:<EOL><INDENT>means = init_means.copy()<EOL><DEDENT>clusters = means.shape[<NUM_LIT:1>]<EOL>w_init = np.random.random(cells*clusters)<EOL>if init_weights is not None:<EOL><INDENT>if len(init_weights.shape)==<NUM_LIT:1>:<EOL><INDENT>init_weights = initialize_from_assignments(init_weights, clusters)<EOL><DEDENT>w_init = init_weights.reshape(cells*clusters)<EOL><DEDENT>m_init = means.reshape(genes*clusters)<EOL>L, Z = zip_fit_params_mle(data)<EOL>ll = np.inf<EOL>for i in range(max_iters):<EOL><INDENT>if disp:<EOL><INDENT>print('<STR_LIT>'.format(i))<EOL><DEDENT>w_bounds = [(<NUM_LIT:0>, <NUM_LIT:1.0>) for x in w_init]<EOL>m_bounds = [(<NUM_LIT:0>, None) for x in m_init]<EOL>w_objective = _create_w_objective(means, data, Z)<EOL>w_res = minimize(w_objective, w_init, method='<STR_LIT>', jac=True, bounds=w_bounds, options={'<STR_LIT>':disp, '<STR_LIT>':inner_max_iters})<EOL>w_diff = np.sqrt(np.sum((w_res.x-w_init)**<NUM_LIT:2>))/w_init.size<EOL>w_new = w_res.x.reshape((clusters, cells))<EOL>w_init = w_res.x<EOL>m_objective = _create_m_objective(w_new, data, Z)<EOL>m_res = minimize(m_objective, m_init, method='<STR_LIT>', jac=True, bounds=m_bounds, options={'<STR_LIT>':disp, '<STR_LIT>':inner_max_iters})<EOL>ll = m_res.fun<EOL>m_diff = np.sqrt(np.sum((m_res.x-m_init)**<NUM_LIT:2>))/m_init.size<EOL>m_new = m_res.x.reshape((genes, clusters))<EOL>m_init = m_res.x<EOL>means = m_new<EOL>if w_diff < tol and m_diff < tol:<EOL><INDENT>break<EOL><DEDENT><DEDENT>if normalize:<EOL><INDENT>w_new = w_new/w_new.sum(<NUM_LIT:0>)<EOL><DEDENT>return m_new, w_new, ll<EOL>
Uses a Zero-inflated Poisson Mixture model to estimate cell states and
cell state mixing weights.

Args:
    data (array): genes x cells
    clusters (int): number of mixture components
    init_means (array, optional): initial centers - genes x clusters. Default: kmeans++ initializations
    init_weights (array, optional): initial weights - clusters x cells. Default: random(0,1)
    max_iters (int, optional): maximum number of iterations. Default: 10
    tol (float, optional): if both M and W change by less than tol (in RMSE), then the iteration is stopped. Default: 1e-4
    disp (bool, optional): whether or not to display optimization parameters. Default: True
    inner_max_iters (int, optional): Number of iterations to run in the scipy minimizer for M and W. Default: 400
    normalize (bool, optional): True if the resulting W should sum to 1 for each cell. Default: True.

Returns:
    M: genes x clusters - state centers
    W: clusters x cells - state mixing components for each cell
    ll: final log-likelihood