def poisson_cluster(data, k, init=None, max_iters=<NUM_LIT:100>):
<EOL>genes, cells = data.shape<EOL>if sparse.issparse(data) and not sparse.isspmatrix_csc(data):<EOL><INDENT>data = sparse.csc_matrix(data)<EOL><DEDENT>init, assignments = kmeans_pp(data, k, centers=init)<EOL>centers = np.copy(init)<EOL>assignments = np.zeros(cells)<EOL>for it in range(max_iters):<EOL><INDENT>lls = poisson_ll(data, centers)<EOL>new_assignments = np.argmax(lls, <NUM_LIT:1>)<EOL>if np.equal(assignments, new_assignments).all():<EOL><INDENT>return new_assignments, centers<EOL><DEDENT>for c in range(k):<EOL><INDENT>if sparse.issparse(data):<EOL><INDENT>if data[:,new_assignments==c].shape[<NUM_LIT:0>]==<NUM_LIT:0>:<EOL><INDENT>new_c, _ = kmeans_pp(data, k, centers[:,:c])<EOL>centers[:,c] = new_c[:,c]<EOL><DEDENT>else:<EOL><INDENT>centers[:,c] = np.asarray(data[:,new_assignments==c].mean(<NUM_LIT:1>)).flatten()<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if len(data[:,new_assignments==c])==<NUM_LIT:0>:<EOL><INDENT>new_c, _ = kmeans_pp(data, k, centers[:,:c])<EOL>centers[:,c] = new_c[:,c]<EOL><DEDENT>else:<EOL><INDENT>centers[:,c] = np.mean(data[:,new_assignments==c], <NUM_LIT:1>)<EOL><DEDENT><DEDENT><DEDENT>assignments = new_assignments<EOL><DEDENT>return assignments, centers<EOL>
Performs Poisson hard EM on the given data.

Args:
    data (array): A 2d array- genes x cells. Can be dense or sparse; for best performance, sparse matrices should be in CSC format.
    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:
    a tuple of two arrays: a cells x 1 vector of cluster assignments,
    and a genes x k array of cluster means.