def _ca(self):
    X = self.X
    (r, c) = X.shape
    if (X.min() < 0):
        raise ValueError('Input matrix elements must be non-negative.')
    grand_total = X.sum()
    Q = (X / grand_total)
    column_marginals = Q.sum(axis=0)
    row_marginals = Q.sum(axis=1)
    self.column_marginals = column_marginals
    self.row_marginals = row_marginals
    expected = np.outer(row_marginals, column_marginals)
    Q_bar = ((Q - expected) / np.sqrt(expected))
    (U_hat, W, Ut) = np.linalg.svd(Q_bar, full_matrices=False)
    rank = svd_rank(Q_bar.shape, W)
    assert (rank <= (min(r, c) - 1))
    self.U_hat = U_hat[:, :rank]
    self.W = W[:rank]
    self.U = Ut[:rank].T
def _ca(self):
    X = self.X
    (r, c) = X.shape
    if (X.min() < 0):
        raise ValueError('Input matrix elements must be non-negative.')
    grand_total = X.sum()
    Q = (X / grand_total)
    column_marginals = Q.sum(axis=0)
    row_marginals = Q.sum(axis=1)
    self.column_marginals = column_marginals
    self.row_marginals = row_marginals
    expected = np.outer(row_marginals, column_marginals)
    Q_bar = ((Q - expected) / np.sqrt(expected))
    (U_hat, W, Ut) = np.linalg.svd(Q_bar, full_matrices=False)
    rank = svd_rank(Q_bar.shape, W)
    assert (rank <= (min(r, c) - 1))
    self.U_hat = U_hat[:, :rank]
    self.W = W[:rank]
    self.U = Ut[:rank].T