def _array_type_std_res(self, counts, total, colsum, rowsum):
        """Return ndarray containing standard residuals for array values.

        The shape of the return value is the same as that of *counts*.
        Array variables require special processing because of the
        underlying math. Essentially, it boils down to the fact that the
        variable dimensions are mutually independent, and standard residuals
        are calculated for each of them separately, and then stacked together
        in the resulting array.
        """
        if self.mr_dim_ind == 0:
            # --This is a special case where broadcasting cannot be
            # --automatically done. We need to "inflate" the single dimensional
            # --ndarrays, to be able to treat them as "columns" (essentially a
            # --Nx1 ndarray). This is needed for subsequent multiplication
            # --that needs to happen column wise (rowsum * colsum) / total.
            total = total[:, np.newaxis]
            rowsum = rowsum[:, np.newaxis]

        expected_counts = rowsum * colsum / total
        variance = rowsum * colsum * (total - rowsum) * (total - colsum) / total ** 3
        return (counts - expected_counts) / np.sqrt(variance)
Return ndarray containing standard residuals for array values.

        The shape of the return value is the same as that of *counts*.
        Array variables require special processing because of the
        underlying math. Essentially, it boils down to the fact that the
        variable dimensions are mutually independent, and standard residuals
        are calculated for each of them separately, and then stacked together
        in the resulting array.