<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def zip_cluster(data, k, init=None, max_iters=100):
 """ Performs hard EM clustering using the zero-inflated Poisson distribution. Args: data (array):
 A 2d array- genes x cells k (int):
 Number of clusters init (array, optional):
 Initial centers - genes x k array. Default: None, use kmeans++ max_iters (int, optional):
 Maximum number of iterations. Default: 100 Returns: assignments (array):
 integer assignments of cells to clusters (length cells) L (array):
 Poisson parameter (genes x k) M (array):
 zero-inflation parameter (genes x k) """

    genes, cells = data.shape
    init, new_assignments = kmeans_pp(data+eps, k, centers=init)
    centers = np.copy(init)
    M = np.zeros(centers.shape)
    assignments = new_assignments
    for c in range(k):
        centers[:,c], M[:,c] = zip_fit_params_mle(data[:, assignments==c])
    for it in range(max_iters):
        lls = zip_ll(data, centers, M)
        new_assignments = np.argmax(lls, 1)
        if np.equal(assignments, new_assignments).all():
            return assignments, centers, M
        for c in range(k):
            centers[:,c], M[:,c] = zip_fit_params_mle(data[:, assignments==c])
        assignments = new_assignments
    return assignments, centers, M