{
    "file_diffs": [
        {
            "old_file_content": "\"\"\"\nThis module provides alternatives for the few additional functions found in\nand once used from the bottlechest package (fork of bottleneck).\n\nIt also patches bottleneck to contain these functions.\n\"\"\"\nimport warnings\nfrom typing import Iterable\n\nimport bottleneck as bn\nimport numpy as np\nimport pandas\nimport scipy.stats.stats\nfrom scipy import sparse as sp\n\nfrom sklearn.utils.sparsefuncs import mean_variance_axis\n\n\ndef _eliminate_zeros(x):\n    \"\"\"Eliminate zeros from sparse matrix, or raise appropriate warning.\"\"\"\n    if hasattr(x, \"eliminate_zeros\"):\n        x.eliminate_zeros()\n    else:\n        warnings.warn(\n            f\"`{x.__type__}` does not implement `eliminate_zeros`. Some values \"\n            f\"in the sparse matrix may by explicit zeros.\"\n        )\n\n\ndef _count_nans_per_row_sparse(X, weights, dtype=None):\n    \"\"\" Count the number of nans (undefined) values per row. \"\"\"\n    if weights is not None:\n        X = X.tocoo(copy=False)\n        nonzero_mask = np.isnan(X.data)\n        nan_rows, nan_cols = X.row[nonzero_mask], X.col[nonzero_mask]\n\n        if weights.ndim == 1:\n            data_weights = weights[nan_rows]\n        else:\n            data_weights = weights[nan_rows, nan_cols]\n\n        w = sp.coo_matrix((data_weights, (nan_rows, nan_cols)), shape=X.shape)\n        w = w.tocsr()\n        return np.asarray(w.sum(axis=1), dtype=dtype).ravel()\n\n    if isinstance(X, (sp.csr_matrix, sp.csc_matrix)):\n        X = type(X)((np.isnan(X.data), X.indices, X.indptr), X.shape)\n        return np.asarray(X.sum(axis=1), dtype=dtype).ravel()\n    else:  # pragma: no cover\n        raise TypeError(\"unsupported type '{}'\".format(type(X).__name__))\n\n\ndef sparse_count_implicit_zeros(x):\n    \"\"\" Count the number of implicit zeros in a sparse matrix. \"\"\"\n    if not sp.issparse(x):\n        raise TypeError('The matrix provided was not sparse.')\n    return np.prod(x.shape) - x.nnz\n\n\ndef sparse_has_implicit_zeros(x):\n    \"\"\" Check if sparse matrix contains any implicit zeros. \"\"\"\n    if not sp.issparse(x):\n        raise TypeError('The matrix provided was not sparse.')\n    return np.prod(x.shape) != x.nnz\n\n\ndef sparse_implicit_zero_weights(x, weights):\n    \"\"\" Extract the weight values of all zeros in a sparse matrix. \"\"\"\n    if not sp.issparse(x):\n        raise TypeError('The matrix provided was not sparse.')\n\n    if weights.ndim == 1:\n        # Match weights and x axis so `indices` will be set appropriately\n        if x.shape[0] == weights.shape[0]:\n            x = x.tocsc()\n        elif x.shape[1] == weights.shape[0]:\n            x = x.tocsr()\n        n_items = np.prod(x.shape)\n        zero_indices = np.setdiff1d(np.arange(n_items), x.indices, assume_unique=True)\n        return weights[zero_indices]\n    else:\n        # Can easily be implemented using a coo_matrix\n        raise NotImplementedError(\n            'Computing zero weights on ndimensinal weight matrix is not implemented'\n        )\n\n\ndef bincount(x, weights=None, max_val=None, minlength=0):\n    \"\"\"Return counts of values in array X.\n\n    Works kind of like np.bincount(), except that it also supports\n    arrays with nans.\n\n    Parameters\n    ----------\n    x : array_like, 1 dimension, nonnegative ints\n        Input array.\n    weights : array_like, optional\n        Weights, array of the same shape as x.\n    max_val : int, optional\n        Indicates the maximum value we expect to find in X and sets the result\n        array size accordingly. E.g. if we set `max_val=2` yet the largest\n        value in X is 1, the result will contain a bin for the value 2, and\n        will be set to 0. See examples for usage.\n    minlength : int, optional\n        A minimum number of bins for the output array. See numpy docs for info.\n\n    Returns\n    -------\n    Tuple[np.ndarray, int]\n        Returns the bincounts and the number of NaN values.\n\n    Examples\n    --------\n    In case `max_val` is provided, the return shape includes bins for these\n    values as well, even if they do not appear in the data. However, this will\n    not truncate the bincount if values larger than `max_count` are found.\n    >>> bincount([0, 0, 1, 1, 2], max_val=4)\n    (array([ 2.,  2.,  1.,  0.,  0.]), 0.0)\n    >>> bincount([0, 1, 2, 3, 4], max_val=2)\n    (array([ 1.,  1.,  1.,  1.,  1.]), 0.0)\n\n    \"\"\"\n    # Store the original matrix before any manipulation to check for sparse\n    x_original = x\n    if sp.issparse(x):\n        if weights is not None:\n            # Match weights and x axis so `indices` will be set appropriately\n            if x.shape[0] == weights.shape[0]:\n                x = x.tocsc()\n            elif x.shape[1] == weights.shape[0]:\n                x = x.tocsr()\n\n            zero_weights = sparse_implicit_zero_weights(x, weights).sum()\n            weights = weights[x.indices]\n        else:\n            zero_weights = sparse_count_implicit_zeros(x)\n\n        x = x.data\n\n    x = np.asanyarray(x, dtype=float)\n    if bn.anynan(x):\n        nonnan = ~np.isnan(x)\n        x = x[nonnan]\n        if weights is not None:\n            nans = (~nonnan * weights).sum(axis=0)\n            weights = weights[nonnan]\n        else:\n            nans = (~nonnan).sum(axis=0)\n    else:\n        nans = 0. if x.ndim == 1 else np.zeros(x.shape[1], dtype=float)\n\n    if minlength == 0 and max_val is not None:\n        minlength = max_val + 1\n\n    bc = np.bincount(\n        x.astype(np.int32, copy=False), weights=weights, minlength=minlength\n    ).astype(float)\n    # Since `csr_matrix.values` only contain non-zero values or explicit\n    # zeros, we must count implicit zeros separately and add them to the\n    # explicit ones found before\n    if sp.issparse(x_original):\n        # If x contains only NaNs, then bc will be an empty array\n        if zero_weights and bc.size == 0:\n            bc = [zero_weights]\n        elif zero_weights:\n            bc[0] += zero_weights\n\n    return bc, nans\n\n\ndef countnans(x, weights=None, axis=None, dtype=None, keepdims=False):\n    \"\"\"\n    Count the undefined elements in an array along given axis.\n\n    Parameters\n    ----------\n    x : array_like\n    weights : array_like, optional\n        Weights to weight the nans with, before or after counting (depending\n        on the weights shape).\n    axis : int, optional\n    dtype : dtype, optional\n        The data type of the returned array.\n\n    Returns\n    -------\n    Union[np.ndarray, float]\n\n    \"\"\"\n    if not sp.issparse(x):\n        x = np.asanyarray(x)\n        is_nan = np.isnan(x)\n        if weights is not None and weights.shape == x.shape:\n            is_nan = is_nan * weights\n\n        counts = is_nan.sum(axis=axis, dtype=dtype, keepdims=keepdims)\n        if weights is not None and weights.shape != x.shape:\n            counts = counts * weights\n    else:\n        assert axis in [None, 0, 1], 'Only axis 0 and 1 are currently supported'\n        # To have consistent behaviour with dense matrices, raise error when\n        # `axis=1` and the array is 1d (e.g. [[1 2 3]])\n        if x.shape[0] == 1 and axis == 1:\n            raise ValueError('Axis %d is out of bounds' % axis)\n\n        arr = x if axis == 1 else x.T\n\n        if weights is not None:\n            weights = weights if axis == 1 else weights.T\n\n        arr = arr.tocsr()\n        counts = _count_nans_per_row_sparse(arr, weights, dtype=dtype)\n\n        # We want a scalar value if `axis=None` or if the sparse matrix is\n        # actually a vector (e.g. [[1 2 3]]), but has `ndim=2` due to scipy\n        # implementation\n        if axis is None or x.shape[0] == 1:\n            counts = counts.sum(dtype=dtype)\n\n    return counts\n\n\ndef contingency(X, y, max_X=None, max_y=None, weights=None, mask=None):\n    \"\"\"\n    Compute the contingency matrices for each column of X (excluding the masked)\n    versus the vector y.\n\n    If the array is 1-dimensional, a 2d contingency matrix is returned. If the\n    array is 2d, the function returns a 3d array, with the first dimension\n    corresponding to column index (variable in the input array).\n\n    The column of contingency matrix correspond to values of variables, the\n    row correspond to values in vector `y`.\n\n    Rows in the input array can be weighted (argument `weights`). A subset of\n    columns can be selected by additional argument `mask`.\n\n    The function also returns a count of NaN values per each value of `y`.\n\n    Parameters\n    ----------\n    X : array_like\n        With values in columns.\n    y : 1d array\n        Vector of true values.\n    max_X : int\n        The maximal value in the array\n    max_y : int\n        The maximal value in `y`\n    weights : array_like\n        Row weights. When not None, contingencies contain weighted counts\n    mask : sequence\n        Discrete columns of X.\n\n    Returns\n    -------\n    contingencies: (m × ny × nx) array\n        m number of masked (used) columns (all if mask=None), i.e.\n        for each column of X;\n        ny number of uniques in y,\n        nx number of uniques in column of X.\n    nans_cols : array_like\n        Number of nans in each column of X for each unique value of y.\n    nans_rows : array_like\n        Number of nans in y for each unique value in columns of X.\n    nans : array_like\n        Number of nans in column of X and y at the same time.\n    \"\"\"\n    was_1d = False\n    if X.ndim == 1:\n        X = X[..., np.newaxis]\n        was_1d = True\n\n    contingencies, nans_cols, nans_rows, nans = [], [], [], []\n    ny = np.unique(y).size if max_y is None else max_y + 1\n    for i in range(X.shape[1]):\n        if mask is not None and not mask[i]:\n            contingencies.append(np.zeros((ny, max_X + 1)))\n            nans_cols.append(np.zeros(ny))\n            nans_rows.append(None)\n            nans.append(0)\n            continue\n        col = X[..., i]\n        nx = np.unique(col[~np.isnan(col)]).size if max_X is None else max_X + 1\n        if sp.issparse(col):\n            col = np.ravel(col.todense())\n        contingencies.append(\n            bincount(y + ny * col,\n                     minlength=ny * nx,\n                     weights=weights)[0].reshape(nx, ny).T)\n\n        nan_col_mask = np.isnan(col)\n        nan_row_mask = np.isnan(y)\n        nan_mask = nan_col_mask & nan_row_mask\n        weights_ = np.ones(len(y)) if weights is None else weights\n\n        nans_cols.append(\n            bincount(y[nan_col_mask], weights=weights_[nan_col_mask],\n                     minlength=ny)[0])\n        nans_rows.append(\n            bincount(col[nan_row_mask], weights=weights_[nan_row_mask],\n                     minlength=nx)[0])\n        nans.append(np.sum(nan_mask * weights_))\n    if was_1d:\n        return contingencies[0], nans_cols[0], nans_rows[0], nans[0]\n    return np.array(contingencies), np.array(nans_cols), nans_rows, nans\n\n\ndef stats(X, weights=None, compute_variance=False):\n    \"\"\"\n    Compute min, max, #nans, mean and variance.\n\n    Result is a tuple (min, max, mean, variance, #nans, #non-nans) or an\n    array of shape (len(X), 6).\n\n    The mean and the number of nans and non-nans are weighted.\n\n    Computation of variance requires an additional pass and is not enabled\n    by default. Zeros are filled in instead of variance.\n\n    Parameters\n    ----------\n    X : array_like, 1 or 2 dimensions\n        Input array.\n    weights : array_like, optional\n        Weights, array of the same length as `x`.\n    compute_variance : bool, optional\n        If set to True, the function also computes variance.\n\n    Returns\n    -------\n    out : a 6-element tuple or an array of shape (len(x), 6)\n        Computed (min, max, mean, variance or 0, #nans, #non-nans)\n\n    Raises\n    ------\n    ValueError\n        If the length of the weight vector does not match the length of the\n        array\n    \"\"\"\n    is_numeric = np.issubdtype(X.dtype, np.number)\n    is_sparse = sp.issparse(X)\n\n    if X.size and is_numeric:\n        if is_sparse:\n            X = X.tocsc()\n        if compute_variance:\n            means, vars = nan_mean_var(X, axis=0, weights=weights)\n        else:\n            means = nanmean(X, axis=0, weights=weights)\n            vars = np.zeros(X.shape[1] if X.ndim == 2 else 1)\n\n    if X.size and is_numeric and not is_sparse:\n        nans = np.isnan(X).sum(axis=0)\n        return np.column_stack((\n            np.nanmin(X, axis=0),\n            np.nanmax(X, axis=0),\n            means,\n            vars,\n            nans,\n            X.shape[0] - nans))\n    elif is_sparse and X.size:\n        non_zero = np.bincount(X.nonzero()[1], minlength=X.shape[1])\n        return np.column_stack((\n            nanmin(X, axis=0),\n            nanmax(X, axis=0),\n            means,\n            vars,\n            X.shape[0] - non_zero,\n            non_zero))\n    else:\n        if X.ndim == 1:\n            X = X[:, None]\n        nans = (pandas.isnull(X).sum(axis=0) + (X == \"\").sum(axis=0)) \\\n            if X.size else np.zeros(X.shape[1])\n        return np.column_stack((\n            np.tile(np.inf, X.shape[1]),\n            np.tile(-np.inf, X.shape[1]),\n            np.zeros(X.shape[1]),\n            np.zeros(X.shape[1]),\n            nans,\n            X.shape[0] - nans))\n\n\ndef _nan_min_max(x, func, axis=0):\n    if not sp.issparse(x):\n        return func(x, axis=axis)\n    if axis is None:\n        extreme = func(x.data, axis=axis) if x.nnz else float('nan')\n        if sparse_has_implicit_zeros(x):\n            extreme = func([0, extreme])\n        return extreme\n    if axis == 0:\n        x = x.T\n    else:\n        assert axis == 1\n\n    # TODO check & transform to correct format\n    r = []\n    for row in x:\n        values = row.data\n        extreme = func(values) if values.size else float('nan')\n        if sparse_has_implicit_zeros(row):\n            extreme = func([0, extreme])\n        r.append(extreme)\n    return np.array(r)\n\n\ndef nanmin(x, axis=None):\n    \"\"\" Equivalent of np.nammin that supports sparse or dense matrices. \"\"\"\n    return _nan_min_max(x, np.nanmin, axis)\n\n\ndef nanmax(x, axis=None):\n    \"\"\" Equivalent of np.nammax that supports sparse or dense matrices. \"\"\"\n    return _nan_min_max(x, np.nanmax, axis)\n\n\ndef mean(x):\n    \"\"\" Equivalent of np.mean that supports sparse or dense matrices. \"\"\"\n    m = (np.sum(x.data) / np.prod(x.shape)\n         if sp.issparse(x) else\n         np.mean(x))\n    if np.isnan(m):\n        warnings.warn('mean() resulted in nan. If input can contain nan values,'\n                      ' perhaps you meant nanmean?', stacklevel=2)\n    return m\n\n\ndef _apply_func(x, dense_func, sparse_func, axis=None):\n    \"\"\" General wrapper for a function depending on sparse or dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return dense_func(x, axis=axis)\n    if axis is None:\n        return sparse_func(x)\n    if axis in [0, 1]:\n        arr = x if axis == 1 else x.T\n        arr = arr.tocsr()\n        return np.fromiter((sparse_func(row) for row in arr),\n                           dtype=np.double, count=arr.shape[0])\n    else:\n        raise NotImplementedError\n\n\ndef nansum(x, axis=None):\n    \"\"\" Equivalent of np.nansum that supports sparse or dense matrices. \"\"\"\n    def nansum_sparse(x):\n        return np.nansum(x.data)\n\n    return _apply_func(x, np.nansum, nansum_sparse, axis=axis)\n\n\ndef nanmean(x, axis=None, weights=None):\n    \"\"\" Equivalent of np.nanmean that supports sparse or dense matrices. \"\"\"\n    if axis is None and weights is not None:\n        raise NotImplementedError(\"weights are only supported if axis is defined\")\n\n    if not sp.issparse(x):\n        if weights is None:\n            means = bn.nanmean(x, axis=axis)\n        else:\n            if axis == 0:\n                weights = weights.reshape(-1, 1)\n            elif axis == 1:\n                weights = weights.reshape(1, -1)\n            else:\n                raise NotImplementedError\n            nanw = ~np.isnan(x) * weights  # do not divide by non-used weights\n            means = bn.nansum(x * weights, axis=axis) / np.sum(nanw, axis=axis)\n    elif axis is None:\n        means, _ = mean_variance_axis(x, axis=0)\n        means = np.nanmean(means)\n    else:\n        # mean_variance_axis is picky regarding the input type\n        if weights is not None:\n            weights = weights.astype(float)\n        means, _ = mean_variance_axis(x, axis=axis, weights=weights)\n\n    return means\n\n\ndef nan_mean_var(x, axis=None, weights=None):\n    \"\"\"\n    Computes means and variance of dense and sparse matrices.\n    Supports weights. Based on mean_variance_axis.\n    \"\"\"\n    if axis is None:\n        raise NotImplementedError(\"axis=None is not supported\")\n\n    if not sp.issparse(x):\n        if weights is None:\n            means = bn.nanmean(x, axis=axis)\n            variances = bn.nanvar(x, axis=axis)\n        else:\n            if axis == 0:\n                weights = weights.reshape(-1, 1)\n            elif axis == 1:\n                weights = weights.reshape(1, -1)\n            else:\n                raise NotImplementedError\n\n            nanw = ~np.isnan(x) * weights  # do not divide by non-used weights\n            wsum = np.sum(nanw, axis=axis)\n            means = bn.nansum(x * weights, axis=axis) / wsum\n\n            if axis == 0:\n                mr = means.reshape(1, -1)\n            elif axis == 1:\n                mr = means.reshape(-1, 1)\n\n            variances = bn.nansum(((x - mr) ** 2) * weights, axis=axis) / wsum\n    else:\n        # mean_variance_axis is picky regarding the input type\n        if weights is not None:\n            weights = weights.astype(float)\n        means, variances = mean_variance_axis(x, axis=axis, weights=weights)\n\n    return means, variances\n\n\ndef nanvar(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.nanvar that supports sparse or dense matrices. \"\"\"\n    def nanvar_sparse(x):\n        n_vals = np.prod(x.shape) - np.sum(np.isnan(x.data))\n        n_zeros = np.prod(x.shape) - len(x.data)\n        avg = np.nansum(x.data) / n_vals\n        return (np.nansum((x.data - avg) ** 2) + avg ** 2 * n_zeros) / (n_vals - ddof)\n\n    return _apply_func(x, bn.nanvar, nanvar_sparse, axis=axis)\n\n\ndef nanstd(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.nanstd that supports sparse and dense matrices. \"\"\"\n    return np.sqrt(nanvar(x, axis=axis, ddof=ddof))\n\n\ndef nanmedian(x, axis=None):\n    \"\"\" Equivalent of np.nanmedian that supports sparse or dense matrices. \"\"\"\n    def nanmedian_sparse(x):\n        nz = np.logical_not(np.isnan(x.data))\n        n_nan = sum(np.isnan(x.data))\n        n_nonzero = sum(x.data[nz] != 0)\n        n_zeros = np.prod(x.shape) - n_nonzero - n_nan\n        if n_zeros > n_nonzero:\n            # Typical case if use of sparse matrices make sense\n            return 0\n        else:\n            # Possibly contains NaNs and\n            # more nz values than zeros, so allocating memory should not be too problematic\n            return np.nanmedian(x.toarray())\n\n    return _apply_func(x, np.nanmedian, nanmedian_sparse, axis=axis)\n\n\ndef nanmode(x, axis=0):\n    \"\"\" A temporary replacement for a scipy.stats.mode.\n\n    This function returns mode NaN if all values are NaN (scipy<1.2.0 wrongly\n    returns zero). Also, this function returns count NaN if all values are NaN\n    (scipy=1.3.0 returns some number).\"\"\"\n    nans = np.isnan(np.array(x)).sum(axis=axis, keepdims=True) == x.shape[axis]\n    res = scipy.stats.mode(x, axis, keepdims=True)\n    # type(res) is ModeResult. ModeResult is defined in scipy.stats.stats; this\n    # namespace is deprecated, but ModeResult is not exported to scipy.stats\n    # Hence we use type(res) to avoid a warning.\n    return type(res)(np.where(nans, np.nan, res.mode),\n                     np.where(nans, np.nan, res.count))\n\n\ndef unique(x, return_counts=False):\n    \"\"\" Equivalent of np.unique that supports sparse or dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.unique(x, return_counts=return_counts)\n\n    implicit_zeros = sparse_count_implicit_zeros(x)\n    explicit_zeros = not np.all(x.data)\n    r = np.unique(x.data, return_counts=return_counts)\n    if not implicit_zeros:\n        return r\n\n    if return_counts:\n        zero_index = np.searchsorted(r[0], 0)\n        if explicit_zeros:\n            r[1][r[0] == 0.] += implicit_zeros\n            return r\n        return np.insert(r[0], zero_index, 0), np.insert(r[1], zero_index, implicit_zeros)\n    else:\n        if explicit_zeros:\n            return r\n        zero_index = np.searchsorted(r, 0)\n        return np.insert(r, zero_index, 0)\n\n\ndef nanunique(*args, **kwargs):\n    \"\"\" Return unique values while disregarding missing (np.nan) values.\n    Supports sparse or dense matrices. \"\"\"\n    result = unique(*args, **kwargs)\n\n    if isinstance(result, tuple):\n        result, counts = result\n        non_nan_mask = ~np.isnan(result)\n        return result[non_nan_mask], counts[non_nan_mask]\n\n    return result[~np.isnan(result)]\n\n\ndef digitize(x, bins, right=False):\n    \"\"\"Equivalent of np.digitize that supports sparse and dense matrices.\n\n    If a sparse matrix is provided and the '0's belong to the '0'th bin, then\n    a sparse matrix is returned.\n\n    Because this can return both sparse and dense matrices, we must keep the\n    return shape consistent. Since sparse matrices don't support 1d matrices,\n    we reshape any returned 1d numpy array to a 2d matrix, with the first\n    dimension shape being 1. This is equivalent to the behaviour of sparse\n    matrices.\n\n    Parameters\n    ----------\n    x : Union[np.ndarry, sp.csr_matrix, sp.csc_matrix]\n    bins : np.ndarray\n    right : Optional[bool]\n\n    Returns\n    -------\n    Union[np.ndarray, sp.csr_matrix]\n\n    \"\"\"\n    if not sp.issparse(x):\n        # TODO Remove reshaping logic when support for numpy==1.9 is dropped\n        original_shape = x.shape\n        x = x.flatten()\n        result = np.digitize(x, bins, right)\n        result = result.reshape(original_shape)\n        # In order to keep the return shape consistent, and sparse matrices\n        # don't support 1d matrices, make sure to convert 1d to 2d matrices\n        if result.ndim == 1:\n            result = result.reshape(((1,) + result.shape))\n        return result\n\n    # Find the bin where zeros belong, depending on the `right` parameter\n    zero_bin = np.searchsorted(bins, 0, side=['right', 'left'][right])\n\n    if zero_bin == 0:\n        r = sp.lil_matrix(x.shape, dtype=np.int64)\n    else:\n        r = zero_bin * np.ones(x.shape, dtype=np.int64)\n\n    for idx, row in enumerate(x.tocsr()):\n        # TODO Remove this check when support for numpy==1.9 is dropped\n        if row.nnz > 0:\n            r[idx, row.indices] = np.digitize(row.data, bins, right)\n\n    # Orange mainly deals with `csr_matrix`, but `lil_matrix` is more efficient\n    # for incremental building\n    if sp.issparse(r):\n        r = r.tocsr()\n\n    return r\n\n\ndef var(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.var that supports sparse and dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.var(x, axis, ddof=ddof)\n\n    result = x.multiply(x).mean(axis) - np.square(x.mean(axis))\n    result = np.squeeze(np.asarray(result))\n\n    # Apply correction for degrees of freedom\n    n = np.prod(x.shape) if axis is None else x.shape[axis]\n    result *= n / (n - ddof)\n\n    return result\n\n\ndef std(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.std that supports sparse and dense matrices. \"\"\"\n    return np.sqrt(var(x, axis=axis, ddof=ddof))\n\n\ndef nan_to_num(x, copy=True):\n    \"\"\" Equivalent of np.nan_to_num that supports sparse and dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.nan_to_num(x, copy=copy)\n\n    if copy:\n        x = x.copy()\n    np.nan_to_num(x.data, copy=False)\n    _eliminate_zeros(x)\n    return x\n\n\ndef isnan(x, out=None):\n    \"\"\" Equivalent of np.isnan that supports sparse and dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.isnan(x, out=out)\n\n    if out is None:\n        x = x.copy()\n    elif out is not x:\n        raise ValueError(\n            \"The `out` parameter can only be set `x` when using sparse matrices\"\n        )\n\n    np.isnan(x.data, out=x.data)\n    _eliminate_zeros(x)\n    return x\n\n\ndef any_nan(x, axis=None):\n    \"\"\" Check if any of the values in a matrix is nan. \"\"\"\n    if not sp.issparse(x):\n        return np.isnan(x).any(axis=axis)\n\n    if axis is None:\n        return np.isnan(x.data).any()\n\n    if axis == 0:\n        x = x.tocsc()\n    elif axis == 1:\n        x = x.tocsr()\n\n    ax = x.ndim - axis - 1\n    result = np.zeros(x.shape[ax], dtype=bool)\n    for i in range(x.shape[ax]):\n        vals = x.data[x.indptr[i]:x.indptr[i + 1]]\n        result[i] = np.isnan(vals).any()\n\n    return result\n\n\ndef all_nan(x, axis=None):\n    \"\"\"\n    Check if all of the values in a matrix is nan. Works for sparse matrix too.\n    \"\"\"\n    if not sp.issparse(x):\n        return np.isnan(x).all(axis=axis)\n\n    if axis is None:\n        # when x.nnz < actual shape there are zero values which are not nan\n        return np.prod(x.shape) == x.nnz and np.isnan(x.data).all()\n\n    if axis == 0:\n        x = x.tocsc()\n    elif axis == 1:\n        x = x.tocsr()\n\n    ax = x.ndim - axis - 1\n    axis_len = x.shape[axis]\n    result = np.zeros(x.shape[ax], dtype=bool)\n    for i in range(x.shape[ax]):\n        vals = x.data[x.indptr[i]:x.indptr[i + 1]]\n        result[i] = axis_len == len(vals) and np.isnan(vals).all()\n\n    return result\n\n\ndef FDR(p_values: Iterable, dependent=False, m=None, ordered=False) -> Iterable:\n    \"\"\" `False Discovery Rate <http://en.wikipedia.org/wiki/False_discovery_rate>`_\n        correction on a list of p-values.\n\n    :param p_values: list or np.ndarray of p-values.\n    :param dependent: use correction for dependent hypotheses (default False).\n    :param m: number of hypotheses tested (default ``len(p_values)``).\n    :param ordered: prevent sorting of p-values if they are already sorted\n        (default False).\n    :return: list or np.ndarray, same as the input\n    \"\"\"\n    if p_values is None or len(p_values) == 0 or \\\n            (m is not None and m <= 0):\n        return None\n\n    is_list = isinstance(p_values, list)\n    p_values = np.array(p_values)\n    if m is None:\n        m = len(p_values)\n    if not ordered:\n        ordered = (np.diff(p_values) >= 0).all()\n        if not ordered:\n            indices = np.argsort(p_values)\n            p_values = p_values[indices]\n\n    if dependent:  # correct q for dependent tests\n        m *= sum(1 / np.arange(1, m + 1))\n\n    fdrs = (p_values * m / np.arange(1, len(p_values) + 1))[::-1]\n    fdrs = np.array(np.minimum.accumulate(fdrs)[::-1])\n    if not ordered:\n        fdrs[indices] = fdrs.copy()\n    return fdrs if not is_list else list(fdrs)\n",
            "new_file_content": "\"\"\"\nThis module provides alternatives for the few additional functions found in\nand once used from the bottlechest package (fork of bottleneck).\n\nIt also patches bottleneck to contain these functions.\n\"\"\"\nimport warnings\nfrom typing import Iterable\n\nimport bottleneck as bn\nimport numpy as np\nimport pandas\nimport scipy.stats.stats\nfrom scipy import sparse as sp\n\nfrom sklearn.utils.sparsefuncs import mean_variance_axis\n\n\ndef _eliminate_zeros(x):\n    \"\"\"Eliminate zeros from sparse matrix, or raise appropriate warning.\"\"\"\n    if hasattr(x, \"eliminate_zeros\"):\n        x.eliminate_zeros()\n    else:\n        warnings.warn(\n            f\"`{x.__type__}` does not implement `eliminate_zeros`. Some values \"\n            f\"in the sparse matrix may by explicit zeros.\"\n        )\n\n\ndef _count_nans_per_row_sparse(X, weights, dtype=None):\n    \"\"\" Count the number of nans (undefined) values per row. \"\"\"\n    if weights is not None:\n        X = X.tocoo(copy=False)\n        nonzero_mask = np.isnan(X.data)\n        nan_rows, nan_cols = X.row[nonzero_mask], X.col[nonzero_mask]\n\n        if weights.ndim == 1:\n            data_weights = weights[nan_rows]\n        else:\n            data_weights = weights[nan_rows, nan_cols]\n\n        w = sp.coo_matrix((data_weights, (nan_rows, nan_cols)), shape=X.shape)\n        w = w.tocsr()\n        return np.asarray(w.sum(axis=1), dtype=dtype).ravel()\n\n    if isinstance(X, (sp.csr_matrix, sp.csc_matrix)):\n        X = type(X)((np.isnan(X.data), X.indices, X.indptr), X.shape)\n        return np.asarray(X.sum(axis=1), dtype=dtype).ravel()\n    else:  # pragma: no cover\n        raise TypeError(\"unsupported type '{}'\".format(type(X).__name__))\n\n\ndef sparse_count_implicit_zeros(x):\n    \"\"\" Count the number of implicit zeros in a sparse matrix. \"\"\"\n    if not sp.issparse(x):\n        raise TypeError('The matrix provided was not sparse.')\n    return np.prod(x.shape) - x.nnz\n\n\ndef sparse_has_implicit_zeros(x):\n    \"\"\" Check if sparse matrix contains any implicit zeros. \"\"\"\n    if not sp.issparse(x):\n        raise TypeError('The matrix provided was not sparse.')\n    return np.prod(x.shape) != x.nnz\n\n\ndef sparse_implicit_zero_weights(x, weights):\n    \"\"\" Extract the weight values of all zeros in a sparse matrix. \"\"\"\n    if not sp.issparse(x):\n        raise TypeError('The matrix provided was not sparse.')\n\n    if weights.ndim == 1:\n        # Match weights and x axis so `indices` will be set appropriately\n        if x.shape[0] == weights.shape[0]:\n            x = x.tocsc()\n        elif x.shape[1] == weights.shape[0]:\n            x = x.tocsr()\n        n_items = np.prod(x.shape)\n        zero_indices = np.setdiff1d(np.arange(n_items), x.indices, assume_unique=True)\n        return weights[zero_indices]\n    else:\n        # Can easily be implemented using a coo_matrix\n        raise NotImplementedError(\n            'Computing zero weights on ndimensinal weight matrix is not implemented'\n        )\n\n\ndef bincount(x, weights=None, max_val=None, minlength=0):\n    \"\"\"Return counts of values in array X.\n\n    Works kind of like np.bincount(), except that it also supports\n    arrays with nans.\n\n    Parameters\n    ----------\n    x : array_like, 1 dimension, nonnegative ints\n        Input array.\n    weights : array_like, optional\n        Weights, array of the same shape as x.\n    max_val : int, optional\n        Indicates the maximum value we expect to find in X and sets the result\n        array size accordingly. E.g. if we set `max_val=2` yet the largest\n        value in X is 1, the result will contain a bin for the value 2, and\n        will be set to 0. See examples for usage.\n    minlength : int, optional\n        A minimum number of bins for the output array. See numpy docs for info.\n\n    Returns\n    -------\n    Tuple[np.ndarray, int]\n        Returns the bincounts and the number of NaN values.\n\n    Examples\n    --------\n    In case `max_val` is provided, the return shape includes bins for these\n    values as well, even if they do not appear in the data. However, this will\n    not truncate the bincount if values larger than `max_count` are found.\n    >>> bincount([0, 0, 1, 1, 2], max_val=4)\n    (array([ 2.,  2.,  1.,  0.,  0.]), 0.0)\n    >>> bincount([0, 1, 2, 3, 4], max_val=2)\n    (array([ 1.,  1.,  1.,  1.,  1.]), 0.0)\n\n    \"\"\"\n    # Store the original matrix before any manipulation to check for sparse\n    x_original = x\n    if sp.issparse(x):\n        if weights is not None:\n            # Match weights and x axis so `indices` will be set appropriately\n            if x.shape[0] == weights.shape[0]:\n                x = x.tocsc()\n            elif x.shape[1] == weights.shape[0]:\n                x = x.tocsr()\n\n            zero_weights = sparse_implicit_zero_weights(x, weights).sum()\n            weights = weights[x.indices]\n        else:\n            zero_weights = sparse_count_implicit_zeros(x)\n\n        x = x.data\n\n    x = np.asanyarray(x, dtype=float)\n    if bn.anynan(x):\n        nonnan = ~np.isnan(x)\n        x = x[nonnan]\n        if weights is not None:\n            nans = (~nonnan * weights).sum(axis=0)\n            weights = weights[nonnan]\n        else:\n            nans = (~nonnan).sum(axis=0)\n    else:\n        nans = 0. if x.ndim == 1 else np.zeros(x.shape[1], dtype=float)\n\n    if minlength == 0 and max_val is not None:\n        minlength = max_val + 1\n\n    bc = np.bincount(\n        x.astype(np.int32, copy=False), weights=weights, minlength=minlength\n    ).astype(float)\n    # Since `csr_matrix.values` only contain non-zero values or explicit\n    # zeros, we must count implicit zeros separately and add them to the\n    # explicit ones found before\n    if sp.issparse(x_original):\n        # If x contains only NaNs, then bc will be an empty array\n        if zero_weights and bc.size == 0:\n            bc = [zero_weights]\n        elif zero_weights:\n            bc[0] += zero_weights\n\n    return bc, nans\n\n\ndef countnans(x, weights=None, axis=None, dtype=None, keepdims=False):\n    \"\"\"\n    Count the undefined elements in an array along given axis.\n\n    Parameters\n    ----------\n    x : array_like\n    weights : array_like, optional\n        Weights to weight the nans with, before or after counting (depending\n        on the weights shape).\n    axis : int, optional\n    dtype : dtype, optional\n        The data type of the returned array.\n\n    Returns\n    -------\n    Union[np.ndarray, float]\n\n    \"\"\"\n    if not sp.issparse(x):\n        x = np.asanyarray(x)\n        is_nan = np.isnan(x)\n        if weights is not None and weights.shape == x.shape:\n            is_nan = is_nan * weights\n\n        counts = is_nan.sum(axis=axis, dtype=dtype, keepdims=keepdims)\n        if weights is not None and weights.shape != x.shape:\n            counts = counts * weights\n    else:\n        assert axis in [None, 0, 1], 'Only axis 0 and 1 are currently supported'\n        # To have consistent behaviour with dense matrices, raise error when\n        # `axis=1` and the array is 1d (e.g. [[1 2 3]])\n        if x.shape[0] == 1 and axis == 1:\n            raise ValueError('Axis %d is out of bounds' % axis)\n\n        arr = x if axis == 1 else x.T\n\n        if weights is not None:\n            weights = weights if axis == 1 else weights.T\n\n        arr = arr.tocsr()\n        counts = _count_nans_per_row_sparse(arr, weights, dtype=dtype)\n\n        # We want a scalar value if `axis=None` or if the sparse matrix is\n        # actually a vector (e.g. [[1 2 3]]), but has `ndim=2` due to scipy\n        # implementation\n        if axis is None or x.shape[0] == 1:\n            counts = counts.sum(dtype=dtype)\n\n    return counts\n\n\ndef contingency(X, y, max_X=None, max_y=None, weights=None, mask=None):\n    \"\"\"\n    Compute the contingency matrices for each column of X (excluding the masked)\n    versus the vector y.\n\n    If the array is 1-dimensional, a 2d contingency matrix is returned. If the\n    array is 2d, the function returns a 3d array, with the first dimension\n    corresponding to column index (variable in the input array).\n\n    The column of contingency matrix correspond to values of variables, the\n    row correspond to values in vector `y`.\n\n    Rows in the input array can be weighted (argument `weights`). A subset of\n    columns can be selected by additional argument `mask`.\n\n    The function also returns a count of NaN values per each value of `y`.\n\n    Parameters\n    ----------\n    X : array_like\n        With values in columns.\n    y : 1d array\n        Vector of true values.\n    max_X : int\n        The maximal value in the array\n    max_y : int\n        The maximal value in `y`\n    weights : array_like\n        Row weights. When not None, contingencies contain weighted counts\n    mask : sequence\n        Discrete columns of X.\n\n    Returns\n    -------\n    contingencies: (m × ny × nx) array\n        m number of masked (used) columns (all if mask=None), i.e.\n        for each column of X;\n        ny number of uniques in y,\n        nx number of uniques in column of X.\n    nans_cols : array_like\n        Number of nans in each column of X for each unique value of y.\n    nans_rows : array_like\n        Number of nans in y for each unique value in columns of X.\n    nans : array_like\n        Number of nans in column of X and y at the same time.\n    \"\"\"\n    was_1d = False\n    if X.ndim == 1:\n        X = X[..., np.newaxis]\n        was_1d = True\n\n    contingencies, nans_cols, nans_rows, nans = [], [], [], []\n    ny = np.unique(y).size if max_y is None else max_y + 1\n    for i in range(X.shape[1]):\n        if mask is not None and not mask[i]:\n            contingencies.append(np.zeros((ny, max_X + 1)))\n            nans_cols.append(np.zeros(ny))\n            nans_rows.append(None)\n            nans.append(0)\n            continue\n        col = X[..., i]\n        nx = np.unique(col[~np.isnan(col)]).size if max_X is None else max_X + 1\n        if sp.issparse(col):\n            col = np.ravel(col.todense())\n        contingencies.append(\n            bincount(y + ny * col,\n                     minlength=ny * nx,\n                     weights=weights)[0].reshape(nx, ny).T)\n\n        nan_col_mask = np.isnan(col)\n        nan_row_mask = np.isnan(y)\n        nan_mask = nan_col_mask & nan_row_mask\n        weights_ = np.ones(len(y)) if weights is None else weights\n\n        nans_cols.append(\n            bincount(y[nan_col_mask], weights=weights_[nan_col_mask],\n                     minlength=ny)[0])\n        nans_rows.append(\n            bincount(col[nan_row_mask], weights=weights_[nan_row_mask],\n                     minlength=nx)[0])\n        nans.append(np.sum(nan_mask * weights_))\n    if was_1d:\n        return contingencies[0], nans_cols[0], nans_rows[0], nans[0]\n    return np.array(contingencies), np.array(nans_cols), nans_rows, nans\n\n\ndef stats(X, weights=None, compute_variance=False):\n    \"\"\"\n    Compute min, max, #nans, mean and variance.\n\n    Result is a tuple (min, max, mean, variance, #nans, #non-nans) or an\n    array of shape (len(X), 6).\n\n    The mean and the number of nans and non-nans are weighted.\n\n    Computation of variance requires an additional pass and is not enabled\n    by default. Zeros are filled in instead of variance.\n\n    Parameters\n    ----------\n    X : array_like, 1 or 2 dimensions\n        Input array.\n    weights : array_like, optional\n        Weights, array of the same length as `x`.\n    compute_variance : bool, optional\n        If set to True, the function also computes variance.\n\n    Returns\n    -------\n    out : a 6-element tuple or an array of shape (len(x), 6)\n        Computed (min, max, mean, variance or 0, #nans, #non-nans)\n\n    Raises\n    ------\n    ValueError\n        If the length of the weight vector does not match the length of the\n        array\n    \"\"\"\n    is_numeric = np.issubdtype(X.dtype, np.number)\n    is_sparse = sp.issparse(X)\n\n    if X.size and is_numeric:\n        if is_sparse:\n            nans = countnans(X, axis=0)\n            X = X.tocsc()\n        else:\n            nans = np.isnan(X).sum(axis=0)\n        if compute_variance:\n            means, vars = nan_mean_var(X, axis=0, weights=weights)\n        else:\n            means = nanmean(X, axis=0, weights=weights)\n            vars = np.zeros(X.shape[1] if X.ndim == 2 else 1)\n        return np.column_stack((\n            nanmin(X, axis=0),\n            nanmax(X, axis=0),\n            means,\n            vars,\n            nans,\n            X.shape[0] - nans))\n    else:\n        if X.ndim == 1:\n            X = X[:, None]\n        nans = (pandas.isnull(X).sum(axis=0) + (X == \"\").sum(axis=0)) \\\n            if X.size else np.zeros(X.shape[1])\n        return np.column_stack((\n            np.tile(np.inf, X.shape[1]),\n            np.tile(-np.inf, X.shape[1]),\n            np.zeros(X.shape[1]),\n            np.zeros(X.shape[1]),\n            nans,\n            X.shape[0] - nans))\n\n\ndef _nan_min_max(x, func, axis=0):\n    if not sp.issparse(x):\n        return func(x, axis=axis)\n    if axis is None:\n        extreme = func(x.data, axis=axis) if x.nnz else float('nan')\n        if sparse_has_implicit_zeros(x):\n            extreme = func([0, extreme])\n        return extreme\n    if axis == 0:\n        x = x.T\n    else:\n        assert axis == 1\n\n    # TODO check & transform to correct format\n    r = []\n    for row in x:\n        values = row.data\n        extreme = func(values) if values.size else float('nan')\n        if sparse_has_implicit_zeros(row):\n            extreme = func([0, extreme])\n        r.append(extreme)\n    return np.array(r)\n\n\ndef nanmin(x, axis=None):\n    \"\"\" Equivalent of np.nammin that supports sparse or dense matrices. \"\"\"\n    return _nan_min_max(x, np.nanmin, axis)\n\n\ndef nanmax(x, axis=None):\n    \"\"\" Equivalent of np.nammax that supports sparse or dense matrices. \"\"\"\n    return _nan_min_max(x, np.nanmax, axis)\n\n\ndef mean(x):\n    \"\"\" Equivalent of np.mean that supports sparse or dense matrices. \"\"\"\n    m = (np.sum(x.data) / np.prod(x.shape)\n         if sp.issparse(x) else\n         np.mean(x))\n    if np.isnan(m):\n        warnings.warn('mean() resulted in nan. If input can contain nan values,'\n                      ' perhaps you meant nanmean?', stacklevel=2)\n    return m\n\n\ndef _apply_func(x, dense_func, sparse_func, axis=None):\n    \"\"\" General wrapper for a function depending on sparse or dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return dense_func(x, axis=axis)\n    if axis is None:\n        return sparse_func(x)\n    if axis in [0, 1]:\n        arr = x if axis == 1 else x.T\n        arr = arr.tocsr()\n        return np.fromiter((sparse_func(row) for row in arr),\n                           dtype=np.double, count=arr.shape[0])\n    else:\n        raise NotImplementedError\n\n\ndef nansum(x, axis=None):\n    \"\"\" Equivalent of np.nansum that supports sparse or dense matrices. \"\"\"\n    def nansum_sparse(x):\n        return np.nansum(x.data)\n\n    return _apply_func(x, np.nansum, nansum_sparse, axis=axis)\n\n\ndef nanmean(x, axis=None, weights=None):\n    \"\"\" Equivalent of np.nanmean that supports sparse or dense matrices. \"\"\"\n    if axis is None and weights is not None:\n        raise NotImplementedError(\"weights are only supported if axis is defined\")\n\n    if not sp.issparse(x):\n        if weights is None:\n            means = bn.nanmean(x, axis=axis)\n        else:\n            if axis == 0:\n                weights = weights.reshape(-1, 1)\n            elif axis == 1:\n                weights = weights.reshape(1, -1)\n            else:\n                raise NotImplementedError\n            nanw = ~np.isnan(x) * weights  # do not divide by non-used weights\n            means = bn.nansum(x * weights, axis=axis) / np.sum(nanw, axis=axis)\n    elif axis is None:\n        means, _ = mean_variance_axis(x, axis=0)\n        means = np.nanmean(means)\n    else:\n        # mean_variance_axis is picky regarding the input type\n        if weights is not None:\n            weights = weights.astype(float)\n        means, _ = mean_variance_axis(x, axis=axis, weights=weights)\n\n    return means\n\n\ndef nan_mean_var(x, axis=None, weights=None):\n    \"\"\"\n    Computes means and variance of dense and sparse matrices.\n    Supports weights. Based on mean_variance_axis.\n    \"\"\"\n    if axis is None:\n        raise NotImplementedError(\"axis=None is not supported\")\n\n    if not sp.issparse(x):\n        if weights is None:\n            means = bn.nanmean(x, axis=axis)\n            variances = bn.nanvar(x, axis=axis)\n        else:\n            if axis == 0:\n                weights = weights.reshape(-1, 1)\n            elif axis == 1:\n                weights = weights.reshape(1, -1)\n            else:\n                raise NotImplementedError\n\n            nanw = ~np.isnan(x) * weights  # do not divide by non-used weights\n            wsum = np.sum(nanw, axis=axis)\n            means = bn.nansum(x * weights, axis=axis) / wsum\n\n            if axis == 0:\n                mr = means.reshape(1, -1)\n            elif axis == 1:\n                mr = means.reshape(-1, 1)\n\n            variances = bn.nansum(((x - mr) ** 2) * weights, axis=axis) / wsum\n    else:\n        # mean_variance_axis is picky regarding the input type\n        if weights is not None:\n            weights = weights.astype(float)\n        means, variances = mean_variance_axis(x, axis=axis, weights=weights)\n\n    return means, variances\n\n\ndef nanvar(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.nanvar that supports sparse or dense matrices. \"\"\"\n    def nanvar_sparse(x):\n        n_vals = np.prod(x.shape) - np.sum(np.isnan(x.data))\n        n_zeros = np.prod(x.shape) - len(x.data)\n        avg = np.nansum(x.data) / n_vals\n        return (np.nansum((x.data - avg) ** 2) + avg ** 2 * n_zeros) / (n_vals - ddof)\n\n    return _apply_func(x, bn.nanvar, nanvar_sparse, axis=axis)\n\n\ndef nanstd(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.nanstd that supports sparse and dense matrices. \"\"\"\n    return np.sqrt(nanvar(x, axis=axis, ddof=ddof))\n\n\ndef nanmedian(x, axis=None):\n    \"\"\" Equivalent of np.nanmedian that supports sparse or dense matrices. \"\"\"\n    def nanmedian_sparse(x):\n        nz = np.logical_not(np.isnan(x.data))\n        n_nan = sum(np.isnan(x.data))\n        n_nonzero = sum(x.data[nz] != 0)\n        n_zeros = np.prod(x.shape) - n_nonzero - n_nan\n        if n_zeros > n_nonzero:\n            # Typical case if use of sparse matrices make sense\n            return 0\n        else:\n            # Possibly contains NaNs and\n            # more nz values than zeros, so allocating memory should not be too problematic\n            return np.nanmedian(x.toarray())\n\n    return _apply_func(x, np.nanmedian, nanmedian_sparse, axis=axis)\n\n\ndef nanmode(x, axis=0):\n    \"\"\" A temporary replacement for a scipy.stats.mode.\n\n    This function returns mode NaN if all values are NaN (scipy<1.2.0 wrongly\n    returns zero). Also, this function returns count NaN if all values are NaN\n    (scipy=1.3.0 returns some number).\"\"\"\n    nans = np.isnan(np.array(x)).sum(axis=axis, keepdims=True) == x.shape[axis]\n    res = scipy.stats.mode(x, axis, keepdims=True)\n    # type(res) is ModeResult. ModeResult is defined in scipy.stats.stats; this\n    # namespace is deprecated, but ModeResult is not exported to scipy.stats\n    # Hence we use type(res) to avoid a warning.\n    return type(res)(np.where(nans, np.nan, res.mode),\n                     np.where(nans, np.nan, res.count))\n\n\ndef unique(x, return_counts=False):\n    \"\"\" Equivalent of np.unique that supports sparse or dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.unique(x, return_counts=return_counts)\n\n    implicit_zeros = sparse_count_implicit_zeros(x)\n    explicit_zeros = not np.all(x.data)\n    r = np.unique(x.data, return_counts=return_counts)\n    if not implicit_zeros:\n        return r\n\n    if return_counts:\n        zero_index = np.searchsorted(r[0], 0)\n        if explicit_zeros:\n            r[1][r[0] == 0.] += implicit_zeros\n            return r\n        return np.insert(r[0], zero_index, 0), np.insert(r[1], zero_index, implicit_zeros)\n    else:\n        if explicit_zeros:\n            return r\n        zero_index = np.searchsorted(r, 0)\n        return np.insert(r, zero_index, 0)\n\n\ndef nanunique(*args, **kwargs):\n    \"\"\" Return unique values while disregarding missing (np.nan) values.\n    Supports sparse or dense matrices. \"\"\"\n    result = unique(*args, **kwargs)\n\n    if isinstance(result, tuple):\n        result, counts = result\n        non_nan_mask = ~np.isnan(result)\n        return result[non_nan_mask], counts[non_nan_mask]\n\n    return result[~np.isnan(result)]\n\n\ndef digitize(x, bins, right=False):\n    \"\"\"Equivalent of np.digitize that supports sparse and dense matrices.\n\n    If a sparse matrix is provided and the '0's belong to the '0'th bin, then\n    a sparse matrix is returned.\n\n    Because this can return both sparse and dense matrices, we must keep the\n    return shape consistent. Since sparse matrices don't support 1d matrices,\n    we reshape any returned 1d numpy array to a 2d matrix, with the first\n    dimension shape being 1. This is equivalent to the behaviour of sparse\n    matrices.\n\n    Parameters\n    ----------\n    x : Union[np.ndarry, sp.csr_matrix, sp.csc_matrix]\n    bins : np.ndarray\n    right : Optional[bool]\n\n    Returns\n    -------\n    Union[np.ndarray, sp.csr_matrix]\n\n    \"\"\"\n    if not sp.issparse(x):\n        # TODO Remove reshaping logic when support for numpy==1.9 is dropped\n        original_shape = x.shape\n        x = x.flatten()\n        result = np.digitize(x, bins, right)\n        result = result.reshape(original_shape)\n        # In order to keep the return shape consistent, and sparse matrices\n        # don't support 1d matrices, make sure to convert 1d to 2d matrices\n        if result.ndim == 1:\n            result = result.reshape(((1,) + result.shape))\n        return result\n\n    # Find the bin where zeros belong, depending on the `right` parameter\n    zero_bin = np.searchsorted(bins, 0, side=['right', 'left'][right])\n\n    if zero_bin == 0:\n        r = sp.lil_matrix(x.shape, dtype=np.int64)\n    else:\n        r = zero_bin * np.ones(x.shape, dtype=np.int64)\n\n    for idx, row in enumerate(x.tocsr()):\n        # TODO Remove this check when support for numpy==1.9 is dropped\n        if row.nnz > 0:\n            r[idx, row.indices] = np.digitize(row.data, bins, right)\n\n    # Orange mainly deals with `csr_matrix`, but `lil_matrix` is more efficient\n    # for incremental building\n    if sp.issparse(r):\n        r = r.tocsr()\n\n    return r\n\n\ndef var(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.var that supports sparse and dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.var(x, axis, ddof=ddof)\n\n    result = x.multiply(x).mean(axis) - np.square(x.mean(axis))\n    result = np.squeeze(np.asarray(result))\n\n    # Apply correction for degrees of freedom\n    n = np.prod(x.shape) if axis is None else x.shape[axis]\n    result *= n / (n - ddof)\n\n    return result\n\n\ndef std(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.std that supports sparse and dense matrices. \"\"\"\n    return np.sqrt(var(x, axis=axis, ddof=ddof))\n\n\ndef nan_to_num(x, copy=True):\n    \"\"\" Equivalent of np.nan_to_num that supports sparse and dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.nan_to_num(x, copy=copy)\n\n    if copy:\n        x = x.copy()\n    np.nan_to_num(x.data, copy=False)\n    _eliminate_zeros(x)\n    return x\n\n\ndef isnan(x, out=None):\n    \"\"\" Equivalent of np.isnan that supports sparse and dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.isnan(x, out=out)\n\n    if out is None:\n        x = x.copy()\n    elif out is not x:\n        raise ValueError(\n            \"The `out` parameter can only be set `x` when using sparse matrices\"\n        )\n\n    np.isnan(x.data, out=x.data)\n    _eliminate_zeros(x)\n    return x\n\n\ndef any_nan(x, axis=None):\n    \"\"\" Check if any of the values in a matrix is nan. \"\"\"\n    if not sp.issparse(x):\n        return np.isnan(x).any(axis=axis)\n\n    if axis is None:\n        return np.isnan(x.data).any()\n\n    if axis == 0:\n        x = x.tocsc()\n    elif axis == 1:\n        x = x.tocsr()\n\n    ax = x.ndim - axis - 1\n    result = np.zeros(x.shape[ax], dtype=bool)\n    for i in range(x.shape[ax]):\n        vals = x.data[x.indptr[i]:x.indptr[i + 1]]\n        result[i] = np.isnan(vals).any()\n\n    return result\n\n\ndef all_nan(x, axis=None):\n    \"\"\"\n    Check if all of the values in a matrix is nan. Works for sparse matrix too.\n    \"\"\"\n    if not sp.issparse(x):\n        return np.isnan(x).all(axis=axis)\n\n    if axis is None:\n        # when x.nnz < actual shape there are zero values which are not nan\n        return np.prod(x.shape) == x.nnz and np.isnan(x.data).all()\n\n    if axis == 0:\n        x = x.tocsc()\n    elif axis == 1:\n        x = x.tocsr()\n\n    ax = x.ndim - axis - 1\n    axis_len = x.shape[axis]\n    result = np.zeros(x.shape[ax], dtype=bool)\n    for i in range(x.shape[ax]):\n        vals = x.data[x.indptr[i]:x.indptr[i + 1]]\n        result[i] = axis_len == len(vals) and np.isnan(vals).all()\n\n    return result\n\n\ndef FDR(p_values: Iterable, dependent=False, m=None, ordered=False) -> Iterable:\n    \"\"\" `False Discovery Rate <http://en.wikipedia.org/wiki/False_discovery_rate>`_\n        correction on a list of p-values.\n\n    :param p_values: list or np.ndarray of p-values.\n    :param dependent: use correction for dependent hypotheses (default False).\n    :param m: number of hypotheses tested (default ``len(p_values)``).\n    :param ordered: prevent sorting of p-values if they are already sorted\n        (default False).\n    :return: list or np.ndarray, same as the input\n    \"\"\"\n    if p_values is None or len(p_values) == 0 or \\\n            (m is not None and m <= 0):\n        return None\n\n    is_list = isinstance(p_values, list)\n    p_values = np.array(p_values)\n    if m is None:\n        m = len(p_values)\n    if not ordered:\n        ordered = (np.diff(p_values) >= 0).all()\n        if not ordered:\n            indices = np.argsort(p_values)\n            p_values = p_values[indices]\n\n    if dependent:  # correct q for dependent tests\n        m *= sum(1 / np.arange(1, m + 1))\n\n    fdrs = (p_values * m / np.arange(1, len(p_values) + 1))[::-1]\n    fdrs = np.array(np.minimum.accumulate(fdrs)[::-1])\n    if not ordered:\n        fdrs[indices] = fdrs.copy()\n    return fdrs if not is_list else list(fdrs)\n",
            "header": {
                "file": {
                    "path": "Orange/statistics/util.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "c37715e47",
                "new_commit_hash": "0aaf1024e",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Orange/statistics/util.py"
            },
            "plus_file": {
                "path": "b/Orange/statistics/util.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 344,
                            "length": 31
                        },
                        "new_range": {
                            "start": 344,
                            "length": 22
                        },
                        "section": "def stats(X, weights=None, compute_variance=False):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    if X.size and is_numeric:",
                                "type": "context"
                            },
                            {
                                "content": "        if is_sparse:",
                                "type": "context"
                            },
                            {
                                "content": "            nans = countnans(X, axis=0)",
                                "type": "added"
                            },
                            {
                                "content": "            X = X.tocsc()",
                                "type": "context"
                            },
                            {
                                "content": "        else:",
                                "type": "added"
                            },
                            {
                                "content": "            nans = np.isnan(X).sum(axis=0)",
                                "type": "added"
                            },
                            {
                                "content": "        if compute_variance:",
                                "type": "context"
                            },
                            {
                                "content": "            means, vars = nan_mean_var(X, axis=0, weights=weights)",
                                "type": "context"
                            },
                            {
                                "content": "        else:",
                                "type": "context"
                            },
                            {
                                "content": "            means = nanmean(X, axis=0, weights=weights)",
                                "type": "context"
                            },
                            {
                                "content": "            vars = np.zeros(X.shape[1] if X.ndim == 2 else 1)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "deleted"
                            },
                            {
                                "content": "    if X.size and is_numeric and not is_sparse:",
                                "type": "deleted"
                            },
                            {
                                "content": "        nans = np.isnan(X).sum(axis=0)",
                                "type": "deleted"
                            },
                            {
                                "content": "        return np.column_stack((",
                                "type": "deleted"
                            },
                            {
                                "content": "            np.nanmin(X, axis=0),",
                                "type": "deleted"
                            },
                            {
                                "content": "            np.nanmax(X, axis=0),",
                                "type": "deleted"
                            },
                            {
                                "content": "            means,",
                                "type": "deleted"
                            },
                            {
                                "content": "            vars,",
                                "type": "deleted"
                            },
                            {
                                "content": "            nans,",
                                "type": "deleted"
                            },
                            {
                                "content": "            X.shape[0] - nans))",
                                "type": "deleted"
                            },
                            {
                                "content": "    elif is_sparse and X.size:",
                                "type": "deleted"
                            },
                            {
                                "content": "        non_zero = np.bincount(X.nonzero()[1], minlength=X.shape[1])",
                                "type": "deleted"
                            },
                            {
                                "content": "        return np.column_stack((",
                                "type": "context"
                            },
                            {
                                "content": "            nanmin(X, axis=0),",
                                "type": "context"
                            },
                            {
                                "content": "            nanmax(X, axis=0),",
                                "type": "context"
                            },
                            {
                                "content": "            means,",
                                "type": "context"
                            },
                            {
                                "content": "            vars,",
                                "type": "context"
                            },
                            {
                                "content": "            X.shape[0] - non_zero,",
                                "type": "deleted"
                            },
                            {
                                "content": "            non_zero))",
                                "type": "deleted"
                            },
                            {
                                "content": "            nans,",
                                "type": "added"
                            },
                            {
                                "content": "            X.shape[0] - nans))",
                                "type": "added"
                            },
                            {
                                "content": "    else:",
                                "type": "context"
                            },
                            {
                                "content": "        if X.ndim == 1:",
                                "type": "context"
                            },
                            {
                                "content": "            X = X[:, None]",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/statistics/util.py",
                            "type": "function",
                            "name": "stats",
                            "content": "def stats(X, weights=None, compute_variance=False):\n    \"\"\"\n    Compute min, max, #nans, mean and variance.\n\n    Result is a tuple (min, max, mean, variance, #nans, #non-nans) or an\n    array of shape (len(X), 6).\n\n    The mean and the number of nans and non-nans are weighted.\n\n    Computation of variance requires an additional pass and is not enabled\n    by default. Zeros are filled in instead of variance.\n\n    Parameters\n    ----------\n    X : array_like, 1 or 2 dimensions\n        Input array.\n    weights : array_like, optional\n        Weights, array of the same length as `x`.\n    compute_variance : bool, optional\n        If set to True, the function also computes variance.\n\n    Returns\n    -------\n    out : a 6-element tuple or an array of shape (len(x), 6)\n        Computed (min, max, mean, variance or 0, #nans, #non-nans)\n\n    Raises\n    ------\n    ValueError\n        If the length of the weight vector does not match the length of the\n        array\n    \"\"\"\n    is_numeric = np.issubdtype(X.dtype, np.number)\n    is_sparse = sp.issparse(X)\n\n    if X.size and is_numeric:\n        if is_sparse:\n            X = X.tocsc()\n        if compute_variance:\n            means, vars = nan_mean_var(X, axis=0, weights=weights)\n        else:\n            means = nanmean(X, axis=0, weights=weights)\n            vars = np.zeros(X.shape[1] if X.ndim == 2 else 1)\n\n    if X.size and is_numeric and not is_sparse:\n        nans = np.isnan(X).sum(axis=0)\n        return np.column_stack((\n            np.nanmin(X, axis=0),\n            np.nanmax(X, axis=0),\n            means,\n            vars,\n            nans,\n            X.shape[0] - nans))\n    elif is_sparse and X.size:\n        non_zero = np.bincount(X.nonzero()[1], minlength=X.shape[1])\n        return np.column_stack((\n            nanmin(X, axis=0),\n            nanmax(X, axis=0),\n            means,\n            vars,\n            X.shape[0] - non_zero,\n            non_zero))\n    else:\n        if X.ndim == 1:\n            X = X[:, None]\n        nans = (pandas.isnull(X).sum(axis=0) + (X == \"\").sum(axis=0)) \\\n            if X.size else np.zeros(X.shape[1])\n        return np.column_stack((\n            np.tile(np.inf, X.shape[1]),\n            np.tile(-np.inf, X.shape[1]),\n            np.zeros(X.shape[1]),\n            np.zeros(X.shape[1]),\n            nans,\n            X.shape[0] - nans))",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 310,
                            "end_lineno": 383,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "# pylint: disable=no-self-use\nimport time\nimport unittest\nimport warnings\nfrom itertools import chain\nfrom functools import partial, wraps\n\nimport numpy as np\nfrom scipy.sparse import csr_matrix, issparse, lil_matrix, csc_matrix, \\\n    SparseEfficiencyWarning\n\nfrom Orange.data import Table, Domain, ContinuousVariable\nfrom Orange.data.util import assure_array_dense\nfrom Orange.statistics.distribution import get_distributions_for_columns\nfrom Orange.statistics.util import bincount, countnans, contingency, digitize, \\\n    mean, nanmax, nanmean, nanmedian, nanmin, nansum, nanunique, stats, std, \\\n    unique, var, nanstd, nanvar, nanmode, nan_to_num, FDR, isnan, any_nan, \\\n    all_nan, nan_mean_var\nfrom sklearn.utils import check_random_state\n\n\ndef dense_sparse(test_case):\n    # type: (Callable) -> Callable\n    \"\"\"Run a single test case on both dense and sparse data.\"\"\"\n    @wraps(test_case)\n    def _wrapper(self):\n\n        def sparse_with_explicit_zero(x, array):\n            \"\"\"Inject one explicit zero into a sparse array.\"\"\"\n            np_array, sp_array = np.atleast_2d(x), array(x)\n            assert issparse(sp_array), 'Can not inject explicit zero into non-sparse matrix'\n\n            zero_indices = np.argwhere(np_array == 0)\n            if zero_indices.size:\n                with warnings.catch_warnings():\n                    # this is just inefficiency in tests, not the tested code\n                    warnings.filterwarnings(\"ignore\", \".*\",\n                                            SparseEfficiencyWarning)\n                    sp_array[tuple(zero_indices[0])] = 0\n\n            return sp_array\n\n        # Make sure to call setUp and tearDown methods in between test runs so\n        # any widget state doesn't interfere between tests\n        def _setup_teardown():\n            self.tearDown()\n            self.setUp()\n\n        test_case(self, np.array)\n        _setup_teardown()\n        test_case(self, csr_matrix)\n        _setup_teardown()\n        test_case(self, csc_matrix)\n        _setup_teardown()\n        test_case(self, partial(sparse_with_explicit_zero, array=csr_matrix))\n        _setup_teardown()\n        test_case(self, partial(sparse_with_explicit_zero, array=csc_matrix))\n\n    return _wrapper\n\n\nclass TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 1, 1],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 1, 1],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)\n\n\nclass TestNanmean(unittest.TestCase):\n    def setUp(self):\n        self.random_state = check_random_state(42)\n        self.x = self.random_state.uniform(size=(10, 5))\n        np.fill_diagonal(self.x, np.nan)\n        self.y = np.array([[0, 1, 5],\n                           [3, 4, np.nan],\n                           [2, np.nan, np.nan],\n                           [np.nan, np.nan, np.nan]])\n        self.r0 = [5/3, 5/2, 5/1]\n        self.r1 = [6/3, 7/2, 2/1, np.nan]\n        self.w0 = np.array([4, 3, 2, 1])\n        self.w1 = np.array([1, 2, 3])\n        self.r0w = [13/9, 16/7, 20/4]\n        self.r1w = [17/6, 11/3, 2/1, np.nan]\n\n    @dense_sparse\n    def test_axis_none(self, array):\n        np.testing.assert_almost_equal(\n            np.nanmean(self.x), nanmean(array(self.x))\n        )\n\n    @dense_sparse\n    def test_axis_0(self, array):\n        np.testing.assert_almost_equal(\n            np.nanmean(self.x, axis=0), nanmean(array(self.x), axis=0)\n        )\n\n    @dense_sparse\n    def test_axis_1(self, array):\n        np.testing.assert_almost_equal(\n            np.nanmean(self.x, axis=1), nanmean(array(self.x), axis=1)\n        )\n\n    @dense_sparse\n    def test_weights_axis_none(self, array):\n        with self.assertRaises(NotImplementedError):\n            nanmean(array(self.x), weights=1)\n\n    @dense_sparse\n    def test_weights_axis_0(self, array):\n        np.testing.assert_almost_equal(\n            self.r0, nanmean(array(self.y), axis=0)\n        )\n        np.testing.assert_almost_equal(\n            self.r1, nanmean(array(self.y.T), axis=0)\n        )\n        np.testing.assert_almost_equal(\n            self.r0w, nanmean(array(self.y), axis=0, weights=self.w0)\n        )\n        np.testing.assert_almost_equal(\n            self.r1w, nanmean(array(self.y.T), axis=0, weights=self.w1)\n        )\n\n    @dense_sparse\n    def test_weights_axis_1(self, array):\n        np.testing.assert_almost_equal(\n            self.r1, nanmean(array(self.y), axis=1)\n        )\n        np.testing.assert_almost_equal(\n            self.r0, nanmean(array(self.y.T), axis=1)\n        )\n        np.testing.assert_almost_equal(\n            self.r1w, nanmean(array(self.y), axis=1, weights=self.w1)\n        )\n        np.testing.assert_almost_equal(\n            self.r0w, nanmean(array(self.y.T), axis=1, weights=self.w0)\n        )\n\n\nclass TestNanMeanVar(unittest.TestCase):\n    def setUp(self):\n        self.x = np.array([[0, 1, 5],\n                           [3, 4, np.nan],\n                           [2, np.nan, np.nan],\n                           [np.nan, np.nan, np.nan]])\n        self.means0 = [5/3, 5/2, 5/1]\n        self.means1 = [6/3, 7/2, 2/1, np.nan]\n        self.vars0 = [14/9, 9/4, 0]\n        self.vars1 = [14/3, 1/4, 0, np.nan]\n        self.w0 = np.array([4, 3, 2, 1])\n        self.w1 = np.array([1, 2, 3])\n        self.means0w = [13/9, 16/7, 20/4]\n        self.means1w = [17/6, 11/3, 2/1, np.nan]\n        self.vars0w = [1.8024691358024691, 2.2040816326530615, 0]\n        self.vars1w = [4.805555555555556, 0.22222222222222224, 0, np.nan]\n\n    @dense_sparse\n    def test_axis_none(self, array):\n        with self.assertRaises(NotImplementedError):\n            nan_mean_var(array(self.x))\n\n    @staticmethod\n    def compare_correct(x, weights, means_correct, vars_correct, axis=None):\n        means, variances = nan_mean_var(x, axis=axis, weights=weights)\n        np.testing.assert_almost_equal(means_correct, means)\n        np.testing.assert_almost_equal(vars_correct, variances)\n\n    @staticmethod\n    def compare_unweighted(x, axis=None):\n        means, variances = nan_mean_var(x, axis=axis)\n        np.testing.assert_almost_equal(nanmean(x, axis=axis), means)\n        np.testing.assert_almost_equal(nanvar(x, axis=axis), variances)\n\n    @staticmethod\n    def compare_distributions(x, dense, weights=None, axis=None):\n        def from_distributions(x, weights):\n            if axis == 1:\n                x = x.T\n            domain = Domain(ContinuousVariable(str(i)) for i in range(x.shape[1]))\n            table = Table.from_numpy(domain, x, W=weights)\n            dists = get_distributions_for_columns(table, list(range(x.shape[1])))\n            means = [d.mean() for d in dists]\n            variances = [d.variance() for d in dists]\n            return means, variances\n\n        means, variances = nan_mean_var(x, axis=axis, weights=weights)\n        md, vd = from_distributions(dense, weights)\n        np.testing.assert_almost_equal(md, means)\n        np.testing.assert_almost_equal(vd, variances)\n\n    @dense_sparse\n    def test_axis_0(self, array):\n        self.compare_correct(array(self.x), None, self.means0, self.vars0, axis=0)\n        self.compare_unweighted(array(self.x), axis=0)\n        self.compare_distributions(array(self.x), self.x, axis=0)\n\n        self.compare_correct(array(self.x.T), None, self.means1, self.vars1, axis=0)\n        self.compare_unweighted(array(self.x.T), axis=0)\n        self.compare_distributions(array(self.x.T), self.x.T, axis=0)\n\n        self.compare_correct(array(self.x), self.w0, self.means0w, self.vars0w, axis=0)\n        self.compare_distributions(array(self.x), self.x, weights=self.w0, axis=0)\n\n        self.compare_correct(array(self.x.T), self.w1, self.means1w, self.vars1w, axis=0)\n        self.compare_distributions(array(self.x.T), self.x.T, weights=self.w1, axis=0)\n\n    @dense_sparse\n    def test_axis_1(self, array):\n        self.compare_correct(array(self.x), None, self.means1, self.vars1, axis=1)\n        self.compare_unweighted(array(self.x), axis=1)\n        self.compare_distributions(array(self.x), self.x, axis=1)\n\n        self.compare_correct(array(self.x.T), None, self.means0, self.vars0, axis=1)\n        self.compare_unweighted(array(self.x.T), axis=1)\n        self.compare_distributions(array(self.x.T), self.x.T, axis=1)\n\n        self.compare_correct(array(self.x), self.w1, self.means1w, self.vars1w, axis=1)\n        self.compare_distributions(array(self.x), self.x, weights=self.w1, axis=1)\n\n        self.compare_correct(array(self.x.T), self.w0, self.means0w, self.vars0w, axis=1)\n        self.compare_distributions(array(self.x.T), self.x.T, weights=self.w0, axis=1)\n\n\nclass TestDigitize(unittest.TestCase):\n    def setUp(self):\n        # pylint: disable=bad-whitespace\n        self.data = [\n            np.array([\n                [0., 1.,     0., np.nan, 3.,     5.],\n                [0., 0., np.nan, np.nan, 5., np.nan],\n                [0., 0.,     0., np.nan, 7.,     6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    @dense_sparse\n    def test_digitize(self, array):\n        for x_original in self.data:\n            x = array(x_original)\n            bins = np.arange(-2, 2)\n\n            x_shape = x.shape\n            np.testing.assert_array_equal(\n                np.digitize(x_original.flatten(), bins).reshape(x_shape),\n                digitize(x, bins),\n            )\n\n    @dense_sparse\n    def test_digitize_right(self, array):\n        for x_original in self.data:\n            x = array(x_original)\n            bins = np.arange(-2, 2)\n\n            x_shape = x.shape\n            np.testing.assert_array_equal(\n                np.digitize(x_original.flatten(), bins, right=True).reshape(x_shape),\n                digitize(x, bins, right=True)\n            )\n\n    @dense_sparse\n    def test_digitize_1d_array(self, array):\n        \"\"\"A consistent return shape must be returned for both sparse and dense.\"\"\"\n        x_original = np.array([0, 1, 1, 0, np.nan, 0, 1])\n        x = array(x_original)\n        bins = np.arange(-2, 2)\n\n        x_shape = x_original.shape\n        np.testing.assert_array_equal(\n            [np.digitize(x_original.flatten(), bins).reshape(x_shape)],\n            digitize(x, bins),\n        )\n\n    def test_digitize_sparse_zeroth_bin(self):\n        # Setup the data so that the '0's will fit into the '0'th bin.\n        data = csr_matrix([\n            [0, 0, 0, 1, 1, 0, 0, 1, 0],\n            [0, 0, 1, 1, 0, 0, 1, 0, 0],\n        ])\n        bins = np.array([1])\n        # Then digitize should return a sparse matrix\n        self.assertTrue(issparse(digitize(data, bins)))\n\n\nclass TestCountnans(unittest.TestCase):\n    @dense_sparse\n    def test_1d_array(self, array):\n        x = array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1])\n        self.assertEqual(countnans(x), 2)\n\n    @dense_sparse\n    def test_1d_array_with_axis_0(self, array):\n        x = array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1])\n        expected = 2\n\n        self.assertEqual(countnans(x, axis=0), expected)\n\n    @dense_sparse\n    def test_1d_array_with_axis_1_raises_exception(self, array):\n        with self.assertRaises(ValueError):\n            countnans(array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1]), axis=1)\n\n    @dense_sparse\n    def test_shape_matches_dense_and_sparse(self, array):\n        x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1],\n                   [1, 2, 2, 1, np.nan, 1, 2, 3, np.nan, 3]])\n        expected = 4\n\n        self.assertEqual(countnans(x), expected)\n\n    @dense_sparse\n    def test_shape_matches_dense_and_sparse_with_axis_0(self, array):\n        x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1],\n                   [1, 2, 2, 1, np.nan, 1, 2, np.nan, 3, 3]])\n        expected = [0, 0, 0, 0, 1, 1, 0, 2, 0, 0]\n\n        np.testing.assert_equal(countnans(x, axis=0), expected)\n\n    @dense_sparse\n    def test_shape_matches_dense_and_sparse_with_axis_1(self, array):\n        x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1],\n                   [1, 2, 2, 1, np.nan, 1, 2, 3, np.nan, 3]])\n        expected = [2, 2]\n\n        np.testing.assert_equal(countnans(x, axis=1), expected)\n\n    @dense_sparse\n    def test_2d_matrix(self, array):\n        x = array([[1, np.nan, 1, 2],\n                   [2, np.nan, 2, 3]])\n        expected = 2\n\n        self.assertEqual(countnans(x), expected)\n\n    @dense_sparse\n    def test_on_columns(self, array):\n        x = array([[1, np.nan, 1, 2],\n                   [2, np.nan, 2, 3]])\n        expected = [0, 2, 0, 0]\n\n        np.testing.assert_equal(countnans(x, axis=0), expected)\n\n    @dense_sparse\n    def test_on_rows(self, array):\n        x = array([[1, np.nan, 1, 2],\n                   [2, np.nan, 2, 3]])\n        expected = [1, 1]\n\n        np.testing.assert_equal(countnans(x, axis=1), expected)\n\n    @dense_sparse\n    def test_1d_weights_with_axis_0(self, array):\n        x = array([[1, 1, np.nan, 1],\n                   [np.nan, 1, 1, 1]])\n        w = np.array([0.5, 1, 1, 1])\n\n        np.testing.assert_equal(countnans(x, w, axis=0), [.5, 0, 1, 0])\n\n    @dense_sparse\n    def test_1d_weights_with_axis_1(self, array):\n        x = array([[1, 1, np.nan, 1],\n                   [np.nan, 1, 1, 1]])\n        w = np.array([0.5, 1])\n\n        np.testing.assert_equal(countnans(x, w, axis=1), [.5, 1])\n\n    @dense_sparse\n    def test_2d_weights(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[np.nan, np.nan, 1,      1 ],\n                   [     0, np.nan, 2, np.nan ]])\n        w = np.array([[1, 2, 3, 4],\n                      [5, 6, 7, 8]])\n\n        np.testing.assert_equal(countnans(x, w), 17)\n        np.testing.assert_equal(countnans(x, w, axis=0), [1, 8, 0, 8])\n        np.testing.assert_equal(countnans(x, w, axis=1), [3, 14])\n\n    @dense_sparse\n    def test_dtype(self, array):\n        x = array([0, np.nan, 2, 3])\n        w = np.array([0, 1.5, 0, 0])\n\n        self.assertIsInstance(countnans(x, w, dtype=np.int32), np.int32)\n        self.assertEqual(countnans(x, w, dtype=np.int32), 1)\n        self.assertIsInstance(countnans(x, w, dtype=np.float64), np.float64)\n        self.assertEqual(countnans(x, w, dtype=np.float64), 1.5)\n\n\nclass TestBincount(unittest.TestCase):\n    @dense_sparse\n    def test_count_nans(self, array):\n        x = array([0, 0, 1, 2, np.nan, 2])\n        expected = 1\n\n        np.testing.assert_equal(bincount(x)[1], expected)\n\n    # object arrays cannot be converted to sparse, so test only for dense\n    def test_count_nans_objectarray(self):\n        x = np.array([0, 0, 1, 2, np.nan, 2], dtype=object)\n        expected = 1\n\n        np.testing.assert_equal(bincount(x)[1], expected)\n\n    @dense_sparse\n    def test_adds_empty_bins(self, array):\n        x = array([0, 1, 3, 5])\n        expected = [1, 1, 0, 1, 0, 1]\n\n        np.testing.assert_equal(bincount(x)[0], expected)\n\n    @dense_sparse\n    def test_maxval_adds_empty_bins(self, array):\n        x = array([1, 1, 1, 2, 3, 2])\n        max_val = 5\n        expected = [0, 3, 2, 1, 0, 0]\n\n        np.testing.assert_equal(bincount(x, max_val=max_val)[0], expected)\n\n    @dense_sparse\n    def test_maxval_doesnt_truncate_values_when_too_small(self, array):\n        x = array([1, 1, 1, 2, 3, 2])\n        max_val = 1\n        expected = [0, 3, 2, 1]\n\n        np.testing.assert_equal(bincount(x, max_val=max_val)[0], expected)\n\n    @dense_sparse\n    def test_minlength_adds_empty_bins(self, array):\n        x = array([1, 1, 1, 2, 3, 2])\n        minlength = 5\n        expected = [0, 3, 2, 1, 0]\n\n        np.testing.assert_equal(bincount(x, minlength=minlength)[0], expected)\n\n    @dense_sparse\n    def test_weights(self, array):\n        x = array([0, 0, 1, 1, 2, 2, 3, 3])\n        w = np.array([1, 2, 0, 0, 1, 1, 0, 1])\n\n        expected = [3, 0, 2, 1]\n        np.testing.assert_equal(bincount(x, w)[0], expected)\n\n    @dense_sparse\n    def test_weights_with_nans(self, array):\n        x = array([0, 0, 1, 1, np.nan, 2, np.nan, 3])\n        w = np.array([1, 2, 0, 0, 1, 1, 0, 1])\n\n        expected = [3, 0, 1, 1]\n        np.testing.assert_equal(bincount(x, w)[0], expected)\n\n    @dense_sparse\n    def test_weights_with_transposed_x(self, array):\n        x = array([0, 0, 1, 1, 2, 2, 3, 3]).T\n        w = np.array([1, 2, 0, 0, 1, 1, 0, 1])\n\n        expected = [3, 0, 2, 1]\n        np.testing.assert_equal(bincount(x, w)[0], expected)\n\n    @dense_sparse\n    def test_all_nans(self, array):\n        x = array([np.nan] * 5)\n        expected = []\n\n        np.testing.assert_equal(bincount(x)[0], expected)\n\n    @dense_sparse\n    def test_all_zeros_or_nans(self, array):\n        \"\"\"Sparse arrays with only nans with no explicit zeros will have no non\n        zero indices. Check that this counts the zeros properly.\"\"\"\n        x = array([np.nan] * 5 + [0] * 5)\n        expected = [5]\n\n        np.testing.assert_equal(bincount(x)[0], expected)\n\n\nclass TestUnique(unittest.TestCase):\n    @dense_sparse\n    def test_returns_unique_values(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5.,    42.],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [-1, 0, 1, 2, 3, 5, 6, 7, 42, np.nan]\n\n        np.testing.assert_equal(unique(x, return_counts=False), expected)\n\n    @dense_sparse\n    def test_returns_counts(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5.,    42.],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [-1, 0, 1, 2, 3, 5, 6, 7, 42, np.nan]\n        expected_counts = [2, 6, 2, 1, 2, 1, 1, 1, 1, 1]\n\n        vals, counts = unique(x, return_counts=True)\n\n        np.testing.assert_equal(vals, expected)\n        np.testing.assert_equal(counts, expected_counts)\n\n    def test_sparse_explicit_zeros(self):\n        # Use `lil_matrix` to fix sparse warning for matrix construction\n        x = lil_matrix(np.eye(3))\n        x[0, 1] = 0\n        x[1, 0] = 0\n        x = x.tocsr()\n        # Test against identity matrix\n        y = csr_matrix(np.eye(3))\n\n        np.testing.assert_array_equal(\n            unique(y, return_counts=True),\n            unique(x, return_counts=True),\n        )\n\n    @dense_sparse\n    def test_nanunique_ignores_nans_in_values(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5., np.nan],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [-1, 0, 1, 2, 3, 5, 6, 7]\n\n        np.testing.assert_equal(nanunique(x, return_counts=False), expected)\n\n    @dense_sparse\n    def test_nanunique_ignores_nans_in_counts(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5., np.nan],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [2, 6, 2, 1, 2, 1, 1, 1]\n\n        np.testing.assert_equal(nanunique(x, return_counts=True)[1], expected)\n\n\nclass TestNanToNum(unittest.TestCase):\n    @dense_sparse\n    def test_converts_invalid_values(self, array):\n        x = np.array([\n            [np.nan, 0, 2, np.inf],\n            [-np.inf, np.nan, 1e-18, 2],\n            [np.nan, np.nan, np.nan, np.nan],\n            [np.inf, np.inf, np.inf, np.inf],\n        ])\n        result = nan_to_num(array(x))\n        np.testing.assert_equal(assure_array_dense(result), np.nan_to_num(x))\n\n    @dense_sparse\n    def test_preserves_valid_values(self, array):\n        x = np.arange(12).reshape((3, 4))\n        result = nan_to_num(array(x))\n        np.testing.assert_equal(assure_array_dense(result), x)\n        np.testing.assert_equal(assure_array_dense(result), np.nan_to_num(x))\n\n\nclass TestIsnan(unittest.TestCase):\n    def setUp(self) -> None:\n        # pylint: disable=bad-whitespace\n        self.x = np.array([\n            [0., 1.,     0., np.nan, 3.,     5.],\n            [0., 0., np.nan, np.nan, 5., np.nan],\n            [0., 0.,     0., np.nan, 7.,     6.],\n            [0., 0.,     0.,     5., 7.,     6.],\n        ])\n\n    @dense_sparse\n    def test_functionality(self, array):\n        expected = np.isnan(self.x)\n        result = isnan(array(self.x))\n        np.testing.assert_equal(assure_array_dense(result), expected)\n\n    @dense_sparse\n    def test_out(self, array):\n        x = array(self.x)\n        x_dtype = x.dtype\n        result = isnan(x, out=x)\n        self.assertIs(result, x)\n        self.assertEqual(x_dtype, result.dtype)\n\n\nclass TestAnyNans(unittest.TestCase):\n    def setUp(self) -> None:\n        # pylint: disable=bad-whitespace\n        self.x_with_nans = np.array([\n            [0., 1.,     0., np.nan, 3.,     5.],\n            [0., 0., np.nan, np.nan, 5., np.nan],\n            [0., 0.,     0., np.nan, 7.,     6.],\n            [0., 0.,     0.,     5., 7.,     6.],\n        ])\n        self.x_no_nans = np.arange(12).reshape((3, 4))\n\n    @dense_sparse\n    def test_axis_none_without_nans(self, array):\n        self.assertFalse(any_nan(array(self.x_no_nans)))\n\n    @dense_sparse\n    def test_axis_none_with_nans(self, array):\n        self.assertTrue(any_nan(array(self.x_with_nans)))\n\n    @dense_sparse\n    def test_axis_0_without_nans(self, array):\n        expected = np.array([0, 0, 0, 0], dtype=bool)\n        result = any_nan(array(self.x_no_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_0_with_nans(self, array):\n        expected = np.array([0, 0, 1, 1, 0, 1], dtype=bool)\n        result = any_nan(array(self.x_with_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_without_nans(self, array):\n        expected = np.array([0, 0, 0], dtype=bool)\n        result = any_nan(array(self.x_no_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_with_nans(self, array):\n        expected = np.array([1, 1, 1, 0], dtype=bool)\n        result = any_nan(array(self.x_with_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n\nclass TestAllNans(unittest.TestCase):\n    def setUp(self) -> None:\n        # pylint: disable=bad-whitespace\n        self.x_with_nans = np.array([\n            [0.,     1.,     0.,     np.nan, 3.,     5.],\n            [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],\n            [0.,     0.,     0.,     np.nan, 7.,     6.],\n            [0.,     0.,     0.,     np.nan, 7.,     np.nan],\n        ])\n        self.x_no_nans = np.arange(12).reshape((3, 4))\n        self.x_only_nans = (np.ones(12) * np.nan).reshape((3, 4))\n\n    @dense_sparse\n    def test_axis_none_without_nans(self, array):\n        self.assertFalse(all_nan(array(self.x_no_nans)))\n\n    @dense_sparse\n    def test_axis_none_with_nans(self, array):\n        self.assertTrue(all_nan(array(self.x_only_nans)))\n\n    @dense_sparse\n    def test_axis_0_without_nans(self, array):\n        expected = np.array([0, 0, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_no_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_0_with_nans(self, array):\n        expected = np.array([0, 0, 0, 1, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_with_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_without_nans(self, array):\n        expected = np.array([0, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_no_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_with_nans(self, array):\n        expected = np.array([0, 1, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_with_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n\nclass TestNanModeFixedInScipy(unittest.TestCase):\n\n    @unittest.expectedFailure\n    def test_scipy_nanmode_still_wrong(self):\n        import scipy.stats\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = scipy.stats.mode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = scipy.stats.mode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n        # When Scipy's scipy.stats.mode works correcly, remove Orange.statistics.util.nanmode\n        # and this test. Also update requirements.\n",
            "new_file_content": "# pylint: disable=no-self-use\nimport time\nimport unittest\nimport warnings\nfrom itertools import chain\nfrom functools import partial, wraps\n\nimport numpy as np\nfrom scipy.sparse import csr_matrix, issparse, lil_matrix, csc_matrix, \\\n    SparseEfficiencyWarning\n\nfrom Orange.data import Table, Domain, ContinuousVariable\nfrom Orange.data.util import assure_array_dense\nfrom Orange.statistics.distribution import get_distributions_for_columns\nfrom Orange.statistics.util import bincount, countnans, contingency, digitize, \\\n    mean, nanmax, nanmean, nanmedian, nanmin, nansum, nanunique, stats, std, \\\n    unique, var, nanstd, nanvar, nanmode, nan_to_num, FDR, isnan, any_nan, \\\n    all_nan, nan_mean_var\nfrom sklearn.utils import check_random_state\n\n\ndef dense_sparse(test_case):\n    # type: (Callable) -> Callable\n    \"\"\"Run a single test case on both dense and sparse data.\"\"\"\n    @wraps(test_case)\n    def _wrapper(self):\n\n        def sparse_with_explicit_zero(x, array):\n            \"\"\"Inject one explicit zero into a sparse array.\"\"\"\n            np_array, sp_array = np.atleast_2d(x), array(x)\n            assert issparse(sp_array), 'Can not inject explicit zero into non-sparse matrix'\n\n            zero_indices = np.argwhere(np_array == 0)\n            if zero_indices.size:\n                with warnings.catch_warnings():\n                    # this is just inefficiency in tests, not the tested code\n                    warnings.filterwarnings(\"ignore\", \".*\",\n                                            SparseEfficiencyWarning)\n                    sp_array[tuple(zero_indices[0])] = 0\n\n            return sp_array\n\n        # Make sure to call setUp and tearDown methods in between test runs so\n        # any widget state doesn't interfere between tests\n        def _setup_teardown():\n            self.tearDown()\n            self.setUp()\n\n        test_case(self, np.array)\n        _setup_teardown()\n        test_case(self, csr_matrix)\n        _setup_teardown()\n        test_case(self, csc_matrix)\n        _setup_teardown()\n        test_case(self, partial(sparse_with_explicit_zero, array=csr_matrix))\n        _setup_teardown()\n        test_case(self, partial(sparse_with_explicit_zero, array=csc_matrix))\n\n    return _wrapper\n\n\nclass TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 0, 3],\n                                           [0, 1, 1/3, 0, 0, 3],\n                                           [0, 1, 1/3, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 0, 0, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 0, 2],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_nancounts(self):\n        arr = np.array([[1, 4, 9],\n                        [-2, 10, 0],\n                        [0, np.nan, np.nan],\n                        [0, np.nan, 0]])\n\n        expected = [[-2, 1, -0.25, (1.25 ** 2 + 1.75 ** 2 + .25 ** 2 + .25 ** 2) / 4, 0, 4],\n                    [4, 10, 7, 3 ** 2, 2, 2],\n                    [0, 9, 3, (6 ** 2 + 3 ** 2 + 3 ** 2) / 3, 1, 3]]\n        np.testing.assert_almost_equal(stats(arr, compute_variance=True), expected)\n\n        sparr = csc_matrix(arr)\n        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\n        sparr = sparr.tocsr()\n        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\n        weights = np.array([1, 2, 0, 3])\n        e0 = (1 * 1 - 2 * 2 + 0 * 0 + 3 * 0) / (1 + 2 + 0 + 3)\n        e1 = (1 * 4 + 2 * 10) / 3\n        e2 = (1 * 9 + 2 * 0 + 3 * 0) / 6\n        expected = [[-2, 1, e0, ((e0 - 1) ** 2 + 2 * (e0 + 2) ** 2 + 3 * e0 ** 2) / 6, 0, 4],\n                    [4, 10, e1, ((e1 - 4) ** 2 + 2 * (e1 - 10) ** 2) / 3, 2, 2],\n                    [0, 9, e2, ((e2 - 9) ** 2 + 2 * e2 ** 2 + 3 * e2 ** 2) / 6, 1, 3]]\n\n        np.testing.assert_almost_equal(\n            stats(arr, weights=weights, compute_variance=True), expected)\n\n        sparr = csc_matrix(arr)\n        np.testing.assert_almost_equal(\n            stats(sparr, weights=weights, compute_variance=True), expected)\n\n        sparr = sparr.tocsr()\n        np.testing.assert_almost_equal(\n            stats(sparr, weights=weights, compute_variance=True), expected)\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)\n\n\nclass TestNanmean(unittest.TestCase):\n    def setUp(self):\n        self.random_state = check_random_state(42)\n        self.x = self.random_state.uniform(size=(10, 5))\n        np.fill_diagonal(self.x, np.nan)\n        self.y = np.array([[0, 1, 5],\n                           [3, 4, np.nan],\n                           [2, np.nan, np.nan],\n                           [np.nan, np.nan, np.nan]])\n        self.r0 = [5/3, 5/2, 5/1]\n        self.r1 = [6/3, 7/2, 2/1, np.nan]\n        self.w0 = np.array([4, 3, 2, 1])\n        self.w1 = np.array([1, 2, 3])\n        self.r0w = [13/9, 16/7, 20/4]\n        self.r1w = [17/6, 11/3, 2/1, np.nan]\n\n    @dense_sparse\n    def test_axis_none(self, array):\n        np.testing.assert_almost_equal(\n            np.nanmean(self.x), nanmean(array(self.x))\n        )\n\n    @dense_sparse\n    def test_axis_0(self, array):\n        np.testing.assert_almost_equal(\n            np.nanmean(self.x, axis=0), nanmean(array(self.x), axis=0)\n        )\n\n    @dense_sparse\n    def test_axis_1(self, array):\n        np.testing.assert_almost_equal(\n            np.nanmean(self.x, axis=1), nanmean(array(self.x), axis=1)\n        )\n\n    @dense_sparse\n    def test_weights_axis_none(self, array):\n        with self.assertRaises(NotImplementedError):\n            nanmean(array(self.x), weights=1)\n\n    @dense_sparse\n    def test_weights_axis_0(self, array):\n        np.testing.assert_almost_equal(\n            self.r0, nanmean(array(self.y), axis=0)\n        )\n        np.testing.assert_almost_equal(\n            self.r1, nanmean(array(self.y.T), axis=0)\n        )\n        np.testing.assert_almost_equal(\n            self.r0w, nanmean(array(self.y), axis=0, weights=self.w0)\n        )\n        np.testing.assert_almost_equal(\n            self.r1w, nanmean(array(self.y.T), axis=0, weights=self.w1)\n        )\n\n    @dense_sparse\n    def test_weights_axis_1(self, array):\n        np.testing.assert_almost_equal(\n            self.r1, nanmean(array(self.y), axis=1)\n        )\n        np.testing.assert_almost_equal(\n            self.r0, nanmean(array(self.y.T), axis=1)\n        )\n        np.testing.assert_almost_equal(\n            self.r1w, nanmean(array(self.y), axis=1, weights=self.w1)\n        )\n        np.testing.assert_almost_equal(\n            self.r0w, nanmean(array(self.y.T), axis=1, weights=self.w0)\n        )\n\n\nclass TestNanMeanVar(unittest.TestCase):\n    def setUp(self):\n        self.x = np.array([[0, 1, 5],\n                           [3, 4, np.nan],\n                           [2, np.nan, np.nan],\n                           [np.nan, np.nan, np.nan]])\n        self.means0 = [5/3, 5/2, 5/1]\n        self.means1 = [6/3, 7/2, 2/1, np.nan]\n        self.vars0 = [14/9, 9/4, 0]\n        self.vars1 = [14/3, 1/4, 0, np.nan]\n        self.w0 = np.array([4, 3, 2, 1])\n        self.w1 = np.array([1, 2, 3])\n        self.means0w = [13/9, 16/7, 20/4]\n        self.means1w = [17/6, 11/3, 2/1, np.nan]\n        self.vars0w = [1.8024691358024691, 2.2040816326530615, 0]\n        self.vars1w = [4.805555555555556, 0.22222222222222224, 0, np.nan]\n\n    @dense_sparse\n    def test_axis_none(self, array):\n        with self.assertRaises(NotImplementedError):\n            nan_mean_var(array(self.x))\n\n    @staticmethod\n    def compare_correct(x, weights, means_correct, vars_correct, axis=None):\n        means, variances = nan_mean_var(x, axis=axis, weights=weights)\n        np.testing.assert_almost_equal(means_correct, means)\n        np.testing.assert_almost_equal(vars_correct, variances)\n\n    @staticmethod\n    def compare_unweighted(x, axis=None):\n        means, variances = nan_mean_var(x, axis=axis)\n        np.testing.assert_almost_equal(nanmean(x, axis=axis), means)\n        np.testing.assert_almost_equal(nanvar(x, axis=axis), variances)\n\n    @staticmethod\n    def compare_distributions(x, dense, weights=None, axis=None):\n        def from_distributions(x, weights):\n            if axis == 1:\n                x = x.T\n            domain = Domain(ContinuousVariable(str(i)) for i in range(x.shape[1]))\n            table = Table.from_numpy(domain, x, W=weights)\n            dists = get_distributions_for_columns(table, list(range(x.shape[1])))\n            means = [d.mean() for d in dists]\n            variances = [d.variance() for d in dists]\n            return means, variances\n\n        means, variances = nan_mean_var(x, axis=axis, weights=weights)\n        md, vd = from_distributions(dense, weights)\n        np.testing.assert_almost_equal(md, means)\n        np.testing.assert_almost_equal(vd, variances)\n\n    @dense_sparse\n    def test_axis_0(self, array):\n        self.compare_correct(array(self.x), None, self.means0, self.vars0, axis=0)\n        self.compare_unweighted(array(self.x), axis=0)\n        self.compare_distributions(array(self.x), self.x, axis=0)\n\n        self.compare_correct(array(self.x.T), None, self.means1, self.vars1, axis=0)\n        self.compare_unweighted(array(self.x.T), axis=0)\n        self.compare_distributions(array(self.x.T), self.x.T, axis=0)\n\n        self.compare_correct(array(self.x), self.w0, self.means0w, self.vars0w, axis=0)\n        self.compare_distributions(array(self.x), self.x, weights=self.w0, axis=0)\n\n        self.compare_correct(array(self.x.T), self.w1, self.means1w, self.vars1w, axis=0)\n        self.compare_distributions(array(self.x.T), self.x.T, weights=self.w1, axis=0)\n\n    @dense_sparse\n    def test_axis_1(self, array):\n        self.compare_correct(array(self.x), None, self.means1, self.vars1, axis=1)\n        self.compare_unweighted(array(self.x), axis=1)\n        self.compare_distributions(array(self.x), self.x, axis=1)\n\n        self.compare_correct(array(self.x.T), None, self.means0, self.vars0, axis=1)\n        self.compare_unweighted(array(self.x.T), axis=1)\n        self.compare_distributions(array(self.x.T), self.x.T, axis=1)\n\n        self.compare_correct(array(self.x), self.w1, self.means1w, self.vars1w, axis=1)\n        self.compare_distributions(array(self.x), self.x, weights=self.w1, axis=1)\n\n        self.compare_correct(array(self.x.T), self.w0, self.means0w, self.vars0w, axis=1)\n        self.compare_distributions(array(self.x.T), self.x.T, weights=self.w0, axis=1)\n\n\nclass TestDigitize(unittest.TestCase):\n    def setUp(self):\n        # pylint: disable=bad-whitespace\n        self.data = [\n            np.array([\n                [0., 1.,     0., np.nan, 3.,     5.],\n                [0., 0., np.nan, np.nan, 5., np.nan],\n                [0., 0.,     0., np.nan, 7.,     6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    @dense_sparse\n    def test_digitize(self, array):\n        for x_original in self.data:\n            x = array(x_original)\n            bins = np.arange(-2, 2)\n\n            x_shape = x.shape\n            np.testing.assert_array_equal(\n                np.digitize(x_original.flatten(), bins).reshape(x_shape),\n                digitize(x, bins),\n            )\n\n    @dense_sparse\n    def test_digitize_right(self, array):\n        for x_original in self.data:\n            x = array(x_original)\n            bins = np.arange(-2, 2)\n\n            x_shape = x.shape\n            np.testing.assert_array_equal(\n                np.digitize(x_original.flatten(), bins, right=True).reshape(x_shape),\n                digitize(x, bins, right=True)\n            )\n\n    @dense_sparse\n    def test_digitize_1d_array(self, array):\n        \"\"\"A consistent return shape must be returned for both sparse and dense.\"\"\"\n        x_original = np.array([0, 1, 1, 0, np.nan, 0, 1])\n        x = array(x_original)\n        bins = np.arange(-2, 2)\n\n        x_shape = x_original.shape\n        np.testing.assert_array_equal(\n            [np.digitize(x_original.flatten(), bins).reshape(x_shape)],\n            digitize(x, bins),\n        )\n\n    def test_digitize_sparse_zeroth_bin(self):\n        # Setup the data so that the '0's will fit into the '0'th bin.\n        data = csr_matrix([\n            [0, 0, 0, 1, 1, 0, 0, 1, 0],\n            [0, 0, 1, 1, 0, 0, 1, 0, 0],\n        ])\n        bins = np.array([1])\n        # Then digitize should return a sparse matrix\n        self.assertTrue(issparse(digitize(data, bins)))\n\n\nclass TestCountnans(unittest.TestCase):\n    @dense_sparse\n    def test_1d_array(self, array):\n        x = array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1])\n        self.assertEqual(countnans(x), 2)\n\n    @dense_sparse\n    def test_1d_array_with_axis_0(self, array):\n        x = array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1])\n        expected = 2\n\n        self.assertEqual(countnans(x, axis=0), expected)\n\n    @dense_sparse\n    def test_1d_array_with_axis_1_raises_exception(self, array):\n        with self.assertRaises(ValueError):\n            countnans(array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1]), axis=1)\n\n    @dense_sparse\n    def test_shape_matches_dense_and_sparse(self, array):\n        x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1],\n                   [1, 2, 2, 1, np.nan, 1, 2, 3, np.nan, 3]])\n        expected = 4\n\n        self.assertEqual(countnans(x), expected)\n\n    @dense_sparse\n    def test_shape_matches_dense_and_sparse_with_axis_0(self, array):\n        x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1],\n                   [1, 2, 2, 1, np.nan, 1, 2, np.nan, 3, 3]])\n        expected = [0, 0, 0, 0, 1, 1, 0, 2, 0, 0]\n\n        np.testing.assert_equal(countnans(x, axis=0), expected)\n\n    @dense_sparse\n    def test_shape_matches_dense_and_sparse_with_axis_1(self, array):\n        x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1],\n                   [1, 2, 2, 1, np.nan, 1, 2, 3, np.nan, 3]])\n        expected = [2, 2]\n\n        np.testing.assert_equal(countnans(x, axis=1), expected)\n\n    @dense_sparse\n    def test_2d_matrix(self, array):\n        x = array([[1, np.nan, 1, 2],\n                   [2, np.nan, 2, 3]])\n        expected = 2\n\n        self.assertEqual(countnans(x), expected)\n\n    @dense_sparse\n    def test_on_columns(self, array):\n        x = array([[1, np.nan, 1, 2],\n                   [2, np.nan, 2, 3]])\n        expected = [0, 2, 0, 0]\n\n        np.testing.assert_equal(countnans(x, axis=0), expected)\n\n    @dense_sparse\n    def test_on_rows(self, array):\n        x = array([[1, np.nan, 1, 2],\n                   [2, np.nan, 2, 3]])\n        expected = [1, 1]\n\n        np.testing.assert_equal(countnans(x, axis=1), expected)\n\n    @dense_sparse\n    def test_1d_weights_with_axis_0(self, array):\n        x = array([[1, 1, np.nan, 1],\n                   [np.nan, 1, 1, 1]])\n        w = np.array([0.5, 1, 1, 1])\n\n        np.testing.assert_equal(countnans(x, w, axis=0), [.5, 0, 1, 0])\n\n    @dense_sparse\n    def test_1d_weights_with_axis_1(self, array):\n        x = array([[1, 1, np.nan, 1],\n                   [np.nan, 1, 1, 1]])\n        w = np.array([0.5, 1])\n\n        np.testing.assert_equal(countnans(x, w, axis=1), [.5, 1])\n\n    @dense_sparse\n    def test_2d_weights(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[np.nan, np.nan, 1,      1 ],\n                   [     0, np.nan, 2, np.nan ]])\n        w = np.array([[1, 2, 3, 4],\n                      [5, 6, 7, 8]])\n\n        np.testing.assert_equal(countnans(x, w), 17)\n        np.testing.assert_equal(countnans(x, w, axis=0), [1, 8, 0, 8])\n        np.testing.assert_equal(countnans(x, w, axis=1), [3, 14])\n\n    @dense_sparse\n    def test_dtype(self, array):\n        x = array([0, np.nan, 2, 3])\n        w = np.array([0, 1.5, 0, 0])\n\n        self.assertIsInstance(countnans(x, w, dtype=np.int32), np.int32)\n        self.assertEqual(countnans(x, w, dtype=np.int32), 1)\n        self.assertIsInstance(countnans(x, w, dtype=np.float64), np.float64)\n        self.assertEqual(countnans(x, w, dtype=np.float64), 1.5)\n\n\nclass TestBincount(unittest.TestCase):\n    @dense_sparse\n    def test_count_nans(self, array):\n        x = array([0, 0, 1, 2, np.nan, 2])\n        expected = 1\n\n        np.testing.assert_equal(bincount(x)[1], expected)\n\n    # object arrays cannot be converted to sparse, so test only for dense\n    def test_count_nans_objectarray(self):\n        x = np.array([0, 0, 1, 2, np.nan, 2], dtype=object)\n        expected = 1\n\n        np.testing.assert_equal(bincount(x)[1], expected)\n\n    @dense_sparse\n    def test_adds_empty_bins(self, array):\n        x = array([0, 1, 3, 5])\n        expected = [1, 1, 0, 1, 0, 1]\n\n        np.testing.assert_equal(bincount(x)[0], expected)\n\n    @dense_sparse\n    def test_maxval_adds_empty_bins(self, array):\n        x = array([1, 1, 1, 2, 3, 2])\n        max_val = 5\n        expected = [0, 3, 2, 1, 0, 0]\n\n        np.testing.assert_equal(bincount(x, max_val=max_val)[0], expected)\n\n    @dense_sparse\n    def test_maxval_doesnt_truncate_values_when_too_small(self, array):\n        x = array([1, 1, 1, 2, 3, 2])\n        max_val = 1\n        expected = [0, 3, 2, 1]\n\n        np.testing.assert_equal(bincount(x, max_val=max_val)[0], expected)\n\n    @dense_sparse\n    def test_minlength_adds_empty_bins(self, array):\n        x = array([1, 1, 1, 2, 3, 2])\n        minlength = 5\n        expected = [0, 3, 2, 1, 0]\n\n        np.testing.assert_equal(bincount(x, minlength=minlength)[0], expected)\n\n    @dense_sparse\n    def test_weights(self, array):\n        x = array([0, 0, 1, 1, 2, 2, 3, 3])\n        w = np.array([1, 2, 0, 0, 1, 1, 0, 1])\n\n        expected = [3, 0, 2, 1]\n        np.testing.assert_equal(bincount(x, w)[0], expected)\n\n    @dense_sparse\n    def test_weights_with_nans(self, array):\n        x = array([0, 0, 1, 1, np.nan, 2, np.nan, 3])\n        w = np.array([1, 2, 0, 0, 1, 1, 0, 1])\n\n        expected = [3, 0, 1, 1]\n        np.testing.assert_equal(bincount(x, w)[0], expected)\n\n    @dense_sparse\n    def test_weights_with_transposed_x(self, array):\n        x = array([0, 0, 1, 1, 2, 2, 3, 3]).T\n        w = np.array([1, 2, 0, 0, 1, 1, 0, 1])\n\n        expected = [3, 0, 2, 1]\n        np.testing.assert_equal(bincount(x, w)[0], expected)\n\n    @dense_sparse\n    def test_all_nans(self, array):\n        x = array([np.nan] * 5)\n        expected = []\n\n        np.testing.assert_equal(bincount(x)[0], expected)\n\n    @dense_sparse\n    def test_all_zeros_or_nans(self, array):\n        \"\"\"Sparse arrays with only nans with no explicit zeros will have no non\n        zero indices. Check that this counts the zeros properly.\"\"\"\n        x = array([np.nan] * 5 + [0] * 5)\n        expected = [5]\n\n        np.testing.assert_equal(bincount(x)[0], expected)\n\n\nclass TestUnique(unittest.TestCase):\n    @dense_sparse\n    def test_returns_unique_values(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5.,    42.],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [-1, 0, 1, 2, 3, 5, 6, 7, 42, np.nan]\n\n        np.testing.assert_equal(unique(x, return_counts=False), expected)\n\n    @dense_sparse\n    def test_returns_counts(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5.,    42.],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [-1, 0, 1, 2, 3, 5, 6, 7, 42, np.nan]\n        expected_counts = [2, 6, 2, 1, 2, 1, 1, 1, 1, 1]\n\n        vals, counts = unique(x, return_counts=True)\n\n        np.testing.assert_equal(vals, expected)\n        np.testing.assert_equal(counts, expected_counts)\n\n    def test_sparse_explicit_zeros(self):\n        # Use `lil_matrix` to fix sparse warning for matrix construction\n        x = lil_matrix(np.eye(3))\n        x[0, 1] = 0\n        x[1, 0] = 0\n        x = x.tocsr()\n        # Test against identity matrix\n        y = csr_matrix(np.eye(3))\n\n        np.testing.assert_array_equal(\n            unique(y, return_counts=True),\n            unique(x, return_counts=True),\n        )\n\n    @dense_sparse\n    def test_nanunique_ignores_nans_in_values(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5., np.nan],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [-1, 0, 1, 2, 3, 5, 6, 7]\n\n        np.testing.assert_equal(nanunique(x, return_counts=False), expected)\n\n    @dense_sparse\n    def test_nanunique_ignores_nans_in_counts(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5., np.nan],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [2, 6, 2, 1, 2, 1, 1, 1]\n\n        np.testing.assert_equal(nanunique(x, return_counts=True)[1], expected)\n\n\nclass TestNanToNum(unittest.TestCase):\n    @dense_sparse\n    def test_converts_invalid_values(self, array):\n        x = np.array([\n            [np.nan, 0, 2, np.inf],\n            [-np.inf, np.nan, 1e-18, 2],\n            [np.nan, np.nan, np.nan, np.nan],\n            [np.inf, np.inf, np.inf, np.inf],\n        ])\n        result = nan_to_num(array(x))\n        np.testing.assert_equal(assure_array_dense(result), np.nan_to_num(x))\n\n    @dense_sparse\n    def test_preserves_valid_values(self, array):\n        x = np.arange(12).reshape((3, 4))\n        result = nan_to_num(array(x))\n        np.testing.assert_equal(assure_array_dense(result), x)\n        np.testing.assert_equal(assure_array_dense(result), np.nan_to_num(x))\n\n\nclass TestIsnan(unittest.TestCase):\n    def setUp(self) -> None:\n        # pylint: disable=bad-whitespace\n        self.x = np.array([\n            [0., 1.,     0., np.nan, 3.,     5.],\n            [0., 0., np.nan, np.nan, 5., np.nan],\n            [0., 0.,     0., np.nan, 7.,     6.],\n            [0., 0.,     0.,     5., 7.,     6.],\n        ])\n\n    @dense_sparse\n    def test_functionality(self, array):\n        expected = np.isnan(self.x)\n        result = isnan(array(self.x))\n        np.testing.assert_equal(assure_array_dense(result), expected)\n\n    @dense_sparse\n    def test_out(self, array):\n        x = array(self.x)\n        x_dtype = x.dtype\n        result = isnan(x, out=x)\n        self.assertIs(result, x)\n        self.assertEqual(x_dtype, result.dtype)\n\n\nclass TestAnyNans(unittest.TestCase):\n    def setUp(self) -> None:\n        # pylint: disable=bad-whitespace\n        self.x_with_nans = np.array([\n            [0., 1.,     0., np.nan, 3.,     5.],\n            [0., 0., np.nan, np.nan, 5., np.nan],\n            [0., 0.,     0., np.nan, 7.,     6.],\n            [0., 0.,     0.,     5., 7.,     6.],\n        ])\n        self.x_no_nans = np.arange(12).reshape((3, 4))\n\n    @dense_sparse\n    def test_axis_none_without_nans(self, array):\n        self.assertFalse(any_nan(array(self.x_no_nans)))\n\n    @dense_sparse\n    def test_axis_none_with_nans(self, array):\n        self.assertTrue(any_nan(array(self.x_with_nans)))\n\n    @dense_sparse\n    def test_axis_0_without_nans(self, array):\n        expected = np.array([0, 0, 0, 0], dtype=bool)\n        result = any_nan(array(self.x_no_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_0_with_nans(self, array):\n        expected = np.array([0, 0, 1, 1, 0, 1], dtype=bool)\n        result = any_nan(array(self.x_with_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_without_nans(self, array):\n        expected = np.array([0, 0, 0], dtype=bool)\n        result = any_nan(array(self.x_no_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_with_nans(self, array):\n        expected = np.array([1, 1, 1, 0], dtype=bool)\n        result = any_nan(array(self.x_with_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n\nclass TestAllNans(unittest.TestCase):\n    def setUp(self) -> None:\n        # pylint: disable=bad-whitespace\n        self.x_with_nans = np.array([\n            [0.,     1.,     0.,     np.nan, 3.,     5.],\n            [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],\n            [0.,     0.,     0.,     np.nan, 7.,     6.],\n            [0.,     0.,     0.,     np.nan, 7.,     np.nan],\n        ])\n        self.x_no_nans = np.arange(12).reshape((3, 4))\n        self.x_only_nans = (np.ones(12) * np.nan).reshape((3, 4))\n\n    @dense_sparse\n    def test_axis_none_without_nans(self, array):\n        self.assertFalse(all_nan(array(self.x_no_nans)))\n\n    @dense_sparse\n    def test_axis_none_with_nans(self, array):\n        self.assertTrue(all_nan(array(self.x_only_nans)))\n\n    @dense_sparse\n    def test_axis_0_without_nans(self, array):\n        expected = np.array([0, 0, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_no_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_0_with_nans(self, array):\n        expected = np.array([0, 0, 0, 1, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_with_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_without_nans(self, array):\n        expected = np.array([0, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_no_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_with_nans(self, array):\n        expected = np.array([0, 1, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_with_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n\nclass TestNanModeFixedInScipy(unittest.TestCase):\n\n    @unittest.expectedFailure\n    def test_scipy_nanmode_still_wrong(self):\n        import scipy.stats\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = scipy.stats.mode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = scipy.stats.mode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n        # When Scipy's scipy.stats.mode works correcly, remove Orange.statistics.util.nanmode\n        # and this test. Also update requirements.\n",
            "header": {
                "file": {
                    "path": "Orange/tests/test_statistics.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "121c66cee",
                "new_commit_hash": "b6ed4d568",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Orange/tests/test_statistics.py"
            },
            "plus_file": {
                "path": "b/Orange/tests/test_statistics.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 107,
                            "length": 26
                        },
                        "new_range": {
                            "start": 107,
                            "length": 26
                        },
                        "section": "class TestUtil(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_stats_sparse(self):",
                                "type": "context"
                            },
                            {
                                "content": "        X = csr_matrix(np.identity(5))",
                                "type": "context"
                            },
                            {
                                "content": "        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 4, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 1, .2, 0, 4, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 1, .2, 0, 4, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 1, .2, 0, 4, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 1, .2, 0, 4, 1]])",
                                "type": "deleted"
                            },
                            {
                                "content": "        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 0, 5],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 1, .2, 0, 0, 5],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 1, .2, 0, 0, 5],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 1, .2, 0, 0, 5],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 1, .2, 0, 0, 5]])",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        # assure last two columns have just zero elements",
                                "type": "context"
                            },
                            {
                                "content": "        X = X[:3]",
                                "type": "context"
                            },
                            {
                                "content": "        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 2, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 1, 1/3, 0, 2, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 1, 1/3, 0, 2, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 0, 0, 0, 3, 0],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 0, 0, 0, 3, 0]])",
                                "type": "deleted"
                            },
                            {
                                "content": "        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 0, 3],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 1, 1/3, 0, 0, 3],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 1, 1/3, 0, 0, 3],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 0, 0, 0, 0, 3],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 0, 0, 0, 0, 3]])",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        r = stats(X, compute_variance=True)",
                                "type": "context"
                            },
                            {
                                "content": "        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 2, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 1, 1/3, 2/9, 2, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 1, 1/3, 2/9, 2, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 0, 0, 0, 3, 0],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                           [0, 0, 0, 0, 3, 0]])",
                                "type": "deleted"
                            },
                            {
                                "content": "        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 0, 3],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 1, 1/3, 2/9, 0, 3],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 1, 1/3, 2/9, 0, 3],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 0, 0, 0, 0, 3],",
                                "type": "added"
                            },
                            {
                                "content": "                                           [0, 0, 0, 0, 0, 3]])",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_stats_weights(self):",
                                "type": "context"
                            },
                            {
                                "content": "        X = np.arange(4).reshape(2, 2).astype(float)",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/tests/test_statistics.py",
                            "type": "class",
                            "name": "TestUtil",
                            "content": "class TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 1, 1],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 1, 1],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 62,
                            "end_lineno": 373,
                            "parent": null
                        },
                        {
                            "file_name": "Orange/tests/test_statistics.py",
                            "type": "method",
                            "name": "TestUtil.test_stats_sparse",
                            "content": "class TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 1, 1],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 1, 1],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 108,
                            "end_lineno": 129,
                            "parent": {
                                "file_name": "Orange/tests/test_statistics.py",
                                "type": "class",
                                "name": "TestUtil",
                                "content": "class TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 1, 1],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 1, 1],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 62,
                                "end_lineno": 373,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 152,
                            "length": 11
                        },
                        "new_range": {
                            "start": 152,
                            "length": 11
                        },
                        "section": "class TestUtil(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        X = np.arange(4).reshape(2, 2).astype(float)",
                                "type": "context"
                            },
                            {
                                "content": "        X = csr_matrix(X)",
                                "type": "context"
                            },
                            {
                                "content": "        weights = np.array([1, 3])",
                                "type": "context"
                            },
                            {
                                "content": "        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 1, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],",
                                "type": "added"
                            },
                            {
                                "content": "                                                    [1, 3, 2.5, 0, 0, 2]])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        np.testing.assert_equal(stats(X, weights, compute_variance=True),",
                                "type": "context"
                            },
                            {
                                "content": "                                [[0, 2, 1.5, 0.75, 1, 1],",
                                "type": "deleted"
                            },
                            {
                                "content": "                                [[0, 2, 1.5, 0.75, 0, 2],",
                                "type": "added"
                            },
                            {
                                "content": "                                 [1, 3, 2.5, 0.75, 0, 2]])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_stats_non_numeric(self):",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/tests/test_statistics.py",
                            "type": "class",
                            "name": "TestUtil",
                            "content": "class TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 1, 1],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 1, 1],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 62,
                            "end_lineno": 373,
                            "parent": null
                        },
                        {
                            "file_name": "Orange/tests/test_statistics.py",
                            "type": "method",
                            "name": "TestUtil.test_stats_weights_sparse",
                            "content": "class TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 1, 1],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 1, 1],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 151,
                            "end_lineno": 160,
                            "parent": {
                                "file_name": "Orange/tests/test_statistics.py",
                                "type": "class",
                                "name": "TestUtil",
                                "content": "class TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1],\n                                           [0, 1, .2, 0, 4, 1]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 1, 1/3, 0, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 1, 1/3, 2/9, 2, 1],\n                                           [0, 0, 0, 0, 3, 0],\n                                           [0, 0, 0, 0, 3, 0]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 1, 1],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 1, 1],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 62,
                                "end_lineno": 373,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 170,
                            "length": 6
                        },
                        "new_range": {
                            "start": 170,
                            "length": 42
                        },
                        "section": "class TestUtil(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "                                           [np.inf, -np.inf, 0, 0, 2, 1],",
                                "type": "context"
                            },
                            {
                                "content": "                                           [np.inf, -np.inf, 0, 0, 0, 3]])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_stats_nancounts(self):",
                                "type": "added"
                            },
                            {
                                "content": "        arr = np.array([[1, 4, 9],",
                                "type": "added"
                            },
                            {
                                "content": "                        [-2, 10, 0],",
                                "type": "added"
                            },
                            {
                                "content": "                        [0, np.nan, np.nan],",
                                "type": "added"
                            },
                            {
                                "content": "                        [0, np.nan, 0]])",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        expected = [[-2, 1, -0.25, (1.25 ** 2 + 1.75 ** 2 + .25 ** 2 + .25 ** 2) / 4, 0, 4],",
                                "type": "added"
                            },
                            {
                                "content": "                    [4, 10, 7, 3 ** 2, 2, 2],",
                                "type": "added"
                            },
                            {
                                "content": "                    [0, 9, 3, (6 ** 2 + 3 ** 2 + 3 ** 2) / 3, 1, 3]]",
                                "type": "added"
                            },
                            {
                                "content": "        np.testing.assert_almost_equal(stats(arr, compute_variance=True), expected)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        sparr = csc_matrix(arr)",
                                "type": "added"
                            },
                            {
                                "content": "        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        sparr = sparr.tocsr()",
                                "type": "added"
                            },
                            {
                                "content": "        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        weights = np.array([1, 2, 0, 3])",
                                "type": "added"
                            },
                            {
                                "content": "        e0 = (1 * 1 - 2 * 2 + 0 * 0 + 3 * 0) / (1 + 2 + 0 + 3)",
                                "type": "added"
                            },
                            {
                                "content": "        e1 = (1 * 4 + 2 * 10) / 3",
                                "type": "added"
                            },
                            {
                                "content": "        e2 = (1 * 9 + 2 * 0 + 3 * 0) / 6",
                                "type": "added"
                            },
                            {
                                "content": "        expected = [[-2, 1, e0, ((e0 - 1) ** 2 + 2 * (e0 + 2) ** 2 + 3 * e0 ** 2) / 6, 0, 4],",
                                "type": "added"
                            },
                            {
                                "content": "                    [4, 10, e1, ((e1 - 4) ** 2 + 2 * (e1 - 10) ** 2) / 3, 2, 2],",
                                "type": "added"
                            },
                            {
                                "content": "                    [0, 9, e2, ((e2 - 9) ** 2 + 2 * e2 ** 2 + 3 * e2 ** 2) / 6, 1, 3]]",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        np.testing.assert_almost_equal(",
                                "type": "added"
                            },
                            {
                                "content": "            stats(arr, weights=weights, compute_variance=True), expected)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        sparr = csc_matrix(arr)",
                                "type": "added"
                            },
                            {
                                "content": "        np.testing.assert_almost_equal(",
                                "type": "added"
                            },
                            {
                                "content": "            stats(sparr, weights=weights, compute_variance=True), expected)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        sparr = sparr.tocsr()",
                                "type": "added"
                            },
                            {
                                "content": "        np.testing.assert_almost_equal(",
                                "type": "added"
                            },
                            {
                                "content": "            stats(sparr, weights=weights, compute_variance=True), expected)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_stats_empty(self):",
                                "type": "context"
                            },
                            {
                                "content": "        X = np.array([])",
                                "type": "context"
                            },
                            {
                                "content": "        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Orange/tests/test_statistics.py",
                            "type": "class",
                            "name": "TestUtil",
                            "content": "class TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 0, 3],\n                                           [0, 1, 1/3, 0, 0, 3],\n                                           [0, 1, 1/3, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 0, 0, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 0, 2],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_nancounts(self):\n        arr = np.array([[1, 4, 9],\n                        [-2, 10, 0],\n                        [0, np.nan, np.nan],\n                        [0, np.nan, 0]])\n\n        expected = [[-2, 1, -0.25, (1.25 ** 2 + 1.75 ** 2 + .25 ** 2 + .25 ** 2) / 4, 0, 4],\n                    [4, 10, 7, 3 ** 2, 2, 2],\n                    [0, 9, 3, (6 ** 2 + 3 ** 2 + 3 ** 2) / 3, 1, 3]]\n        np.testing.assert_almost_equal(stats(arr, compute_variance=True), expected)\n\n        sparr = csc_matrix(arr)\n        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\n        sparr = sparr.tocsr()\n        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\n        weights = np.array([1, 2, 0, 3])\n        e0 = (1 * 1 - 2 * 2 + 0 * 0 + 3 * 0) / (1 + 2 + 0 + 3)\n        e1 = (1 * 4 + 2 * 10) / 3\n        e2 = (1 * 9 + 2 * 0 + 3 * 0) / 6\n        expected = [[-2, 1, e0, ((e0 - 1) ** 2 + 2 * (e0 + 2) ** 2 + 3 * e0 ** 2) / 6, 0, 4],\n                    [4, 10, e1, ((e1 - 4) ** 2 + 2 * (e1 - 10) ** 2) / 3, 2, 2],\n                    [0, 9, e2, ((e2 - 9) ** 2 + 2 * e2 ** 2 + 3 * e2 ** 2) / 6, 1, 3]]\n\n        np.testing.assert_almost_equal(\n            stats(arr, weights=weights, compute_variance=True), expected)\n\n        sparr = csc_matrix(arr)\n        np.testing.assert_almost_equal(\n            stats(sparr, weights=weights, compute_variance=True), expected)\n\n        sparr = sparr.tocsr()\n        np.testing.assert_almost_equal(\n            stats(sparr, weights=weights, compute_variance=True), expected)\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 62,
                            "end_lineno": 409,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "Orange/tests/test_statistics.py",
                            "type": "method",
                            "name": "TestUtil.test_stats_nancounts",
                            "content": "class TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 0, 3],\n                                           [0, 1, 1/3, 0, 0, 3],\n                                           [0, 1, 1/3, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 0, 0, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 0, 2],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_nancounts(self):\n        arr = np.array([[1, 4, 9],\n                        [-2, 10, 0],\n                        [0, np.nan, np.nan],\n                        [0, np.nan, 0]])\n\n        expected = [[-2, 1, -0.25, (1.25 ** 2 + 1.75 ** 2 + .25 ** 2 + .25 ** 2) / 4, 0, 4],\n                    [4, 10, 7, 3 ** 2, 2, 2],\n                    [0, 9, 3, (6 ** 2 + 3 ** 2 + 3 ** 2) / 3, 1, 3]]\n        np.testing.assert_almost_equal(stats(arr, compute_variance=True), expected)\n\n        sparr = csc_matrix(arr)\n        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\n        sparr = sparr.tocsr()\n        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\n        weights = np.array([1, 2, 0, 3])\n        e0 = (1 * 1 - 2 * 2 + 0 * 0 + 3 * 0) / (1 + 2 + 0 + 3)\n        e1 = (1 * 4 + 2 * 10) / 3\n        e2 = (1 * 9 + 2 * 0 + 3 * 0) / 6\n        expected = [[-2, 1, e0, ((e0 - 1) ** 2 + 2 * (e0 + 2) ** 2 + 3 * e0 ** 2) / 6, 0, 4],\n                    [4, 10, e1, ((e1 - 4) ** 2 + 2 * (e1 - 10) ** 2) / 3, 2, 2],\n                    [0, 9, e2, ((e2 - 9) ** 2 + 2 * e2 ** 2 + 3 * e2 ** 2) / 6, 1, 3]]\n\n        np.testing.assert_almost_equal(\n            stats(arr, weights=weights, compute_variance=True), expected)\n\n        sparr = csc_matrix(arr)\n        np.testing.assert_almost_equal(\n            stats(sparr, weights=weights, compute_variance=True), expected)\n\n        sparr = sparr.tocsr()\n        np.testing.assert_almost_equal(\n            stats(sparr, weights=weights, compute_variance=True), expected)\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 173,
                            "end_lineno": 207,
                            "parent": {
                                "file_name": "Orange/tests/test_statistics.py",
                                "type": "class",
                                "name": "TestUtil",
                                "content": "class TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 0, 3],\n                                           [0, 1, 1/3, 0, 0, 3],\n                                           [0, 1, 1/3, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 0, 0, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 0, 2],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_nancounts(self):\n        arr = np.array([[1, 4, 9],\n                        [-2, 10, 0],\n                        [0, np.nan, np.nan],\n                        [0, np.nan, 0]])\n\n        expected = [[-2, 1, -0.25, (1.25 ** 2 + 1.75 ** 2 + .25 ** 2 + .25 ** 2) / 4, 0, 4],\n                    [4, 10, 7, 3 ** 2, 2, 2],\n                    [0, 9, 3, (6 ** 2 + 3 ** 2 + 3 ** 2) / 3, 1, 3]]\n        np.testing.assert_almost_equal(stats(arr, compute_variance=True), expected)\n\n        sparr = csc_matrix(arr)\n        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\n        sparr = sparr.tocsr()\n        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\n        weights = np.array([1, 2, 0, 3])\n        e0 = (1 * 1 - 2 * 2 + 0 * 0 + 3 * 0) / (1 + 2 + 0 + 3)\n        e1 = (1 * 4 + 2 * 10) / 3\n        e2 = (1 * 9 + 2 * 0 + 3 * 0) / 6\n        expected = [[-2, 1, e0, ((e0 - 1) ** 2 + 2 * (e0 + 2) ** 2 + 3 * e0 ** 2) / 6, 0, 4],\n                    [4, 10, e1, ((e1 - 4) ** 2 + 2 * (e1 - 10) ** 2) / 3, 2, 2],\n                    [0, 9, e2, ((e2 - 9) ** 2 + 2 * e2 ** 2 + 3 * e2 ** 2) / 6, 1, 3]]\n\n        np.testing.assert_almost_equal(\n            stats(arr, weights=weights, compute_variance=True), expected)\n\n        sparr = csc_matrix(arr)\n        np.testing.assert_almost_equal(\n            stats(sparr, weights=weights, compute_variance=True), expected)\n\n        sparr = sparr.tocsr()\n        np.testing.assert_almost_equal(\n            stats(sparr, weights=weights, compute_variance=True), expected)\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 62,
                                "end_lineno": 409,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "39cdce60dc81c3b8524e578c34d17eab61d02fe5^",
    "new_commit_hash": "39cdce60dc81c3b8524e578c34d17eab61d02fe5",
    "commit_message": "stats.utils: Don't count zeros as nans",
    "commit_date": "2023-01-26T13:59:47+01:00",
    "metadata": {}
}
{
    "repo_name": "orange3",
    "new_commit_hash": "39cdce60dc81c3b8524e578c34d17eab61d02fe5",
    "test_file_codes": [
        "# pylint: disable=no-self-use\nimport time\nimport unittest\nimport warnings\nfrom itertools import chain\nfrom functools import partial, wraps\n\nimport numpy as np\nfrom scipy.sparse import csr_matrix, issparse, lil_matrix, csc_matrix, \\\n    SparseEfficiencyWarning\n\nfrom Orange.data import Table, Domain, ContinuousVariable\nfrom Orange.data.util import assure_array_dense\nfrom Orange.statistics.distribution import get_distributions_for_columns\nfrom Orange.statistics.util import bincount, countnans, contingency, digitize, \\\n    mean, nanmax, nanmean, nanmedian, nanmin, nansum, nanunique, stats, std, \\\n    unique, var, nanstd, nanvar, nanmode, nan_to_num, FDR, isnan, any_nan, \\\n    all_nan, nan_mean_var\nfrom sklearn.utils import check_random_state\n\n\ndef dense_sparse(test_case):\n    # type: (Callable) -> Callable\n    \"\"\"Run a single test case on both dense and sparse data.\"\"\"\n    @wraps(test_case)\n    def _wrapper(self):\n\n        def sparse_with_explicit_zero(x, array):\n            \"\"\"Inject one explicit zero into a sparse array.\"\"\"\n            np_array, sp_array = np.atleast_2d(x), array(x)\n            assert issparse(sp_array), 'Can not inject explicit zero into non-sparse matrix'\n\n            zero_indices = np.argwhere(np_array == 0)\n            if zero_indices.size:\n                with warnings.catch_warnings():\n                    # this is just inefficiency in tests, not the tested code\n                    warnings.filterwarnings(\"ignore\", \".*\",\n                                            SparseEfficiencyWarning)\n                    sp_array[tuple(zero_indices[0])] = 0\n\n            return sp_array\n\n        # Make sure to call setUp and tearDown methods in between test runs so\n        # any widget state doesn't interfere between tests\n        def _setup_teardown():\n            self.tearDown()\n            self.setUp()\n\n        test_case(self, np.array)\n        _setup_teardown()\n        test_case(self, csr_matrix)\n        _setup_teardown()\n        test_case(self, csc_matrix)\n        _setup_teardown()\n        test_case(self, partial(sparse_with_explicit_zero, array=csr_matrix))\n        _setup_teardown()\n        test_case(self, partial(sparse_with_explicit_zero, array=csc_matrix))\n\n    return _wrapper\n\n\nclass TestUtil(unittest.TestCase):\n    def setUp(self):\n        nan = float('nan')\n        self.data = [\n            np.array([\n                [0., 1., 0., nan, 3., 5.],\n                [0., 0., nan, nan, 5., nan],\n                [0., 0., 0., nan, 7., 6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    def test_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        cont_table, col_nans, row_nans, nans = contingency(x, y, 2, 2)\n        np.testing.assert_equal(cont_table, [[1, 1, 0],\n                                             [1, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [1, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 1])\n        self.assertEqual(1, nans)\n\n    def test_weighted_contingency(self):\n        x = np.array([0, 1, 0, 2, np.nan, np.nan])\n        y = np.array([0, 0, 1, np.nan, 0, np.nan])\n        w = np.array([1, 2, 2, 3, 4, 2])\n        cont_table, col_nans, row_nans, nans = contingency(\n            x, y, 2, 2, weights=w)\n        np.testing.assert_equal(cont_table, [[1, 2, 0],\n                                             [2, 0, 0],\n                                             [0, 0, 0]])\n        np.testing.assert_equal(col_nans, [4, 0, 0])\n        np.testing.assert_equal(row_nans, [0, 0, 3])\n        self.assertEqual(2, nans)\n\n    def test_stats(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[1, 1] = np.nan\n        np.testing.assert_equal(stats(X), [[0, 2, 1, 0, 0, 2],\n                                           [1, 1, 1, 0, 1, 1]])\n        # empty table should return ~like metas\n        X = X[:0]\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0],\n                                           [np.inf, -np.inf, 0, 0, 0, 0]])\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n        np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5]])\n\n        # assure last two columns have just zero elements\n        X = X[:3]\n        np.testing.assert_equal(stats(X), [[0, 1, 1/3, 0, 0, 3],\n                                           [0, 1, 1/3, 0, 0, 3],\n                                           [0, 1, 1/3, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3]])\n\n        r = stats(X, compute_variance=True)\n        np.testing.assert_almost_equal(r, [[0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 1, 1/3, 2/9, 0, 3],\n                                           [0, 0, 0, 0, 0, 3],\n                                           [0, 0, 0, 0, 0, 3]])\n\n    def test_stats_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        X = np.arange(4).reshape(2, 2).astype(object)\n        np.testing.assert_equal(stats(X, weights), stats(X))\n\n    def test_stats_nans_neutral_weights(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_nans_neutral_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        X[0, 0] = np.nan\n        np.testing.assert_equal(stats(X, weights=np.array([1, 1])), stats(X))\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n        np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\n        np.testing.assert_equal(stats(X, weights, compute_variance=True),\n                                [[0, 2, 1.5, 0.75, 0, 2],\n                                 [1, 3, 2.5, 0.75, 0, 2]])\n\n    def test_stats_non_numeric(self):\n        X = np.array([\n            [\"\", \"a\", np.nan, 0],\n            [\"a\", \"\", np.nan, 1],\n            [\"a\", \"b\", 0, 0],\n        ], dtype=object)\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 1, 2],\n                                           [np.inf, -np.inf, 0, 0, 2, 1],\n                                           [np.inf, -np.inf, 0, 0, 0, 3]])\n\n    def test_stats_nancounts(self):\n        arr = np.array([[1, 4, 9],\n                        [-2, 10, 0],\n                        [0, np.nan, np.nan],\n                        [0, np.nan, 0]])\n\n        expected = [[-2, 1, -0.25, (1.25 ** 2 + 1.75 ** 2 + .25 ** 2 + .25 ** 2) / 4, 0, 4],\n                    [4, 10, 7, 3 ** 2, 2, 2],\n                    [0, 9, 3, (6 ** 2 + 3 ** 2 + 3 ** 2) / 3, 1, 3]]\n        np.testing.assert_almost_equal(stats(arr, compute_variance=True), expected)\n\n        sparr = csc_matrix(arr)\n        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\n        sparr = sparr.tocsr()\n        np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\n        weights = np.array([1, 2, 0, 3])\n        e0 = (1 * 1 - 2 * 2 + 0 * 0 + 3 * 0) / (1 + 2 + 0 + 3)\n        e1 = (1 * 4 + 2 * 10) / 3\n        e2 = (1 * 9 + 2 * 0 + 3 * 0) / 6\n        expected = [[-2, 1, e0, ((e0 - 1) ** 2 + 2 * (e0 + 2) ** 2 + 3 * e0 ** 2) / 6, 0, 4],\n                    [4, 10, e1, ((e1 - 4) ** 2 + 2 * (e1 - 10) ** 2) / 3, 2, 2],\n                    [0, 9, e2, ((e2 - 9) ** 2 + 2 * e2 ** 2 + 3 * e2 ** 2) / 6, 1, 3]]\n\n        np.testing.assert_almost_equal(\n            stats(arr, weights=weights, compute_variance=True), expected)\n\n        sparr = csc_matrix(arr)\n        np.testing.assert_almost_equal(\n            stats(sparr, weights=weights, compute_variance=True), expected)\n\n        sparr = sparr.tocsr()\n        np.testing.assert_almost_equal(\n            stats(sparr, weights=weights, compute_variance=True), expected)\n\n    def test_stats_empty(self):\n        X = np.array([])\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0,))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]])\n\n        X = np.zeros((0, 4))\n        np.testing.assert_equal(stats(X), [[np.inf, -np.inf, 0, 0, 0, 0]] * 4)\n\n\n\n    def test_stats_long_string_mem_use(self):\n        X = np.full((1000, 1000), \"a\", dtype=object)\n        t = time.time()\n        stats(X)\n        t_a = time.time() - t  # time for an array with constant-len strings\n\n        # Add one very long string\n        X[0, 0] = \"a\"*2000\n\n        # The implementation of stats() in Orange 3.30.2 used .astype(\"str\")\n        # internally. X.astype(\"str\") would take ~1000x the memory as X,\n        # because its type would be \"<U1000\" (the length of the longest string).\n        # That is about 7.5 GiB of memory on a 64-bit Linux system\n\n        # Because it is hard to measure CPU, we here measure time as\n        # memory allocation of such big tables takes time. On Marko's\n        # Linux system .astype(\"str\") took ~3 seconds.\n        t = time.time()\n        stats(X)\n        t_b = time.time() - t\n        self.assertLess(t_b, 2*t_a + 0.1)  # some grace period\n\n    def test_nanmin_nanmax(self):\n        warnings.filterwarnings(\"ignore\", r\".*All-NaN slice encountered.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            for axis in [None, 0, 1]:\n                np.testing.assert_array_equal(\n                    nanmin(X, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmin(X_sparse, axis=axis),\n                    np.nanmin(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n                np.testing.assert_array_equal(\n                    nanmax(X_sparse, axis=axis),\n                    np.nanmax(X, axis=axis))\n\n    @dense_sparse\n    def test_nansum(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nansum(X_sparse),\n                np.nansum(X))\n\n    def test_mean(self):\n        # This warning is not unexpected and it's correct\n        warnings.filterwarnings(\"ignore\", r\".*mean\\(\\) resulted in nan.*\")\n        for X in self.data:\n            X_sparse = csr_matrix(X)\n            np.testing.assert_array_equal(\n                mean(X_sparse),\n                np.mean(X))\n\n        with self.assertWarns(UserWarning):\n            mean([1, np.nan, 0])\n\n    def test_nanmode(self):\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = nanmode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = nanmode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n\n    @dense_sparse\n    def test_nanmedian(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanmedian(X_sparse),\n                np.nanmedian(X))\n\n    @dense_sparse\n    def test_nanmedian_more_nonzeros(self, array):\n        X = np.ones((10, 10))\n        X[:5, 0] = np.nan\n        X[:6, 1] = 0\n        X_sparse = array(X)\n        np.testing.assert_array_equal(\n            nanmedian(X_sparse),\n            np.nanmedian(X)\n        )\n\n    def test_var(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    var(csr_matrix(data), axis=axis),\n                    np.var(data, axis=axis)\n                )\n\n    def test_var_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.var(x, axis=axis, ddof=10),\n                var(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanvar(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_almost_equal(\n                nanvar(X_sparse),\n                np.nanvar(X), decimal=14)  # np.nanvar and bn.nanvar differ slightly\n\n    def test_nanvar_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        np.fill_diagonal(x, np.nan)\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanvar(x, axis=axis, ddof=10),\n                nanvar(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_std(self):\n        for data in self.data:\n            for axis in chain((None,), range(len(data.shape))):\n                # Can't use array_equal here due to differences on 1e-16 level\n                np.testing.assert_array_almost_equal(\n                    std(csr_matrix(data), axis=axis),\n                    np.std(data, axis=axis)\n                )\n\n    def test_std_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.std(x, axis=axis, ddof=10),\n                std(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    @dense_sparse\n    def test_nanstd(self, array):\n        for X in self.data:\n            X_sparse = array(X)\n            np.testing.assert_array_equal(\n                nanstd(X_sparse),\n                np.nanstd(X))\n\n    def test_nanstd_with_ddof(self):\n        x = np.random.uniform(0, 10, (20, 100))\n        for axis in [None, 0, 1]:\n            np.testing.assert_almost_equal(\n                np.nanstd(x, axis=axis, ddof=10),\n                nanstd(csr_matrix(x), axis=axis, ddof=10),\n            )\n\n    def test_FDR(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            FDR(p_values), decimal=5)\n\n    def test_FDR_dependent(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.00076, 0.00091, 0.00011, 0.00086, 0.00057]),\n            FDR(p_values, dependent=True), decimal=5)\n\n    def test_FDR_m(self):\n        p_values = np.array([0.0002, 0.0004, 0.00001, 0.0003, 0.0001])\n        np.testing.assert_almost_equal(\n            np.array([0.0002, 0.00024, 0.00003, 0.000225, 0.00015]),\n            FDR(p_values, m=3), decimal=5)\n\n    def test_FDR_no_values(self):\n        self.assertIsNone(FDR(None))\n        self.assertIsNone(FDR([]))\n        self.assertIsNone(FDR([0.0002, 0.0004], m=0))\n\n    def test_FDR_list(self):\n        p_values = [0.0002, 0.0004, 0.00001, 0.0003, 0.0001]\n        result = FDR(p_values)\n        self.assertIsInstance(result, list)\n        np.testing.assert_almost_equal(\n            np.array([0.00033, 0.0004, 0.00005, 0.00038, 0.00025]),\n            result, decimal=5)\n\n\nclass TestNanmean(unittest.TestCase):\n    def setUp(self):\n        self.random_state = check_random_state(42)\n        self.x = self.random_state.uniform(size=(10, 5))\n        np.fill_diagonal(self.x, np.nan)\n        self.y = np.array([[0, 1, 5],\n                           [3, 4, np.nan],\n                           [2, np.nan, np.nan],\n                           [np.nan, np.nan, np.nan]])\n        self.r0 = [5/3, 5/2, 5/1]\n        self.r1 = [6/3, 7/2, 2/1, np.nan]\n        self.w0 = np.array([4, 3, 2, 1])\n        self.w1 = np.array([1, 2, 3])\n        self.r0w = [13/9, 16/7, 20/4]\n        self.r1w = [17/6, 11/3, 2/1, np.nan]\n\n    @dense_sparse\n    def test_axis_none(self, array):\n        np.testing.assert_almost_equal(\n            np.nanmean(self.x), nanmean(array(self.x))\n        )\n\n    @dense_sparse\n    def test_axis_0(self, array):\n        np.testing.assert_almost_equal(\n            np.nanmean(self.x, axis=0), nanmean(array(self.x), axis=0)\n        )\n\n    @dense_sparse\n    def test_axis_1(self, array):\n        np.testing.assert_almost_equal(\n            np.nanmean(self.x, axis=1), nanmean(array(self.x), axis=1)\n        )\n\n    @dense_sparse\n    def test_weights_axis_none(self, array):\n        with self.assertRaises(NotImplementedError):\n            nanmean(array(self.x), weights=1)\n\n    @dense_sparse\n    def test_weights_axis_0(self, array):\n        np.testing.assert_almost_equal(\n            self.r0, nanmean(array(self.y), axis=0)\n        )\n        np.testing.assert_almost_equal(\n            self.r1, nanmean(array(self.y.T), axis=0)\n        )\n        np.testing.assert_almost_equal(\n            self.r0w, nanmean(array(self.y), axis=0, weights=self.w0)\n        )\n        np.testing.assert_almost_equal(\n            self.r1w, nanmean(array(self.y.T), axis=0, weights=self.w1)\n        )\n\n    @dense_sparse\n    def test_weights_axis_1(self, array):\n        np.testing.assert_almost_equal(\n            self.r1, nanmean(array(self.y), axis=1)\n        )\n        np.testing.assert_almost_equal(\n            self.r0, nanmean(array(self.y.T), axis=1)\n        )\n        np.testing.assert_almost_equal(\n            self.r1w, nanmean(array(self.y), axis=1, weights=self.w1)\n        )\n        np.testing.assert_almost_equal(\n            self.r0w, nanmean(array(self.y.T), axis=1, weights=self.w0)\n        )\n\n\nclass TestNanMeanVar(unittest.TestCase):\n    def setUp(self):\n        self.x = np.array([[0, 1, 5],\n                           [3, 4, np.nan],\n                           [2, np.nan, np.nan],\n                           [np.nan, np.nan, np.nan]])\n        self.means0 = [5/3, 5/2, 5/1]\n        self.means1 = [6/3, 7/2, 2/1, np.nan]\n        self.vars0 = [14/9, 9/4, 0]\n        self.vars1 = [14/3, 1/4, 0, np.nan]\n        self.w0 = np.array([4, 3, 2, 1])\n        self.w1 = np.array([1, 2, 3])\n        self.means0w = [13/9, 16/7, 20/4]\n        self.means1w = [17/6, 11/3, 2/1, np.nan]\n        self.vars0w = [1.8024691358024691, 2.2040816326530615, 0]\n        self.vars1w = [4.805555555555556, 0.22222222222222224, 0, np.nan]\n\n    @dense_sparse\n    def test_axis_none(self, array):\n        with self.assertRaises(NotImplementedError):\n            nan_mean_var(array(self.x))\n\n    @staticmethod\n    def compare_correct(x, weights, means_correct, vars_correct, axis=None):\n        means, variances = nan_mean_var(x, axis=axis, weights=weights)\n        np.testing.assert_almost_equal(means_correct, means)\n        np.testing.assert_almost_equal(vars_correct, variances)\n\n    @staticmethod\n    def compare_unweighted(x, axis=None):\n        means, variances = nan_mean_var(x, axis=axis)\n        np.testing.assert_almost_equal(nanmean(x, axis=axis), means)\n        np.testing.assert_almost_equal(nanvar(x, axis=axis), variances)\n\n    @staticmethod\n    def compare_distributions(x, dense, weights=None, axis=None):\n        def from_distributions(x, weights):\n            if axis == 1:\n                x = x.T\n            domain = Domain(ContinuousVariable(str(i)) for i in range(x.shape[1]))\n            table = Table.from_numpy(domain, x, W=weights)\n            dists = get_distributions_for_columns(table, list(range(x.shape[1])))\n            means = [d.mean() for d in dists]\n            variances = [d.variance() for d in dists]\n            return means, variances\n\n        means, variances = nan_mean_var(x, axis=axis, weights=weights)\n        md, vd = from_distributions(dense, weights)\n        np.testing.assert_almost_equal(md, means)\n        np.testing.assert_almost_equal(vd, variances)\n\n    @dense_sparse\n    def test_axis_0(self, array):\n        self.compare_correct(array(self.x), None, self.means0, self.vars0, axis=0)\n        self.compare_unweighted(array(self.x), axis=0)\n        self.compare_distributions(array(self.x), self.x, axis=0)\n\n        self.compare_correct(array(self.x.T), None, self.means1, self.vars1, axis=0)\n        self.compare_unweighted(array(self.x.T), axis=0)\n        self.compare_distributions(array(self.x.T), self.x.T, axis=0)\n\n        self.compare_correct(array(self.x), self.w0, self.means0w, self.vars0w, axis=0)\n        self.compare_distributions(array(self.x), self.x, weights=self.w0, axis=0)\n\n        self.compare_correct(array(self.x.T), self.w1, self.means1w, self.vars1w, axis=0)\n        self.compare_distributions(array(self.x.T), self.x.T, weights=self.w1, axis=0)\n\n    @dense_sparse\n    def test_axis_1(self, array):\n        self.compare_correct(array(self.x), None, self.means1, self.vars1, axis=1)\n        self.compare_unweighted(array(self.x), axis=1)\n        self.compare_distributions(array(self.x), self.x, axis=1)\n\n        self.compare_correct(array(self.x.T), None, self.means0, self.vars0, axis=1)\n        self.compare_unweighted(array(self.x.T), axis=1)\n        self.compare_distributions(array(self.x.T), self.x.T, axis=1)\n\n        self.compare_correct(array(self.x), self.w1, self.means1w, self.vars1w, axis=1)\n        self.compare_distributions(array(self.x), self.x, weights=self.w1, axis=1)\n\n        self.compare_correct(array(self.x.T), self.w0, self.means0w, self.vars0w, axis=1)\n        self.compare_distributions(array(self.x.T), self.x.T, weights=self.w0, axis=1)\n\n\nclass TestDigitize(unittest.TestCase):\n    def setUp(self):\n        # pylint: disable=bad-whitespace\n        self.data = [\n            np.array([\n                [0., 1.,     0., np.nan, 3.,     5.],\n                [0., 0., np.nan, np.nan, 5., np.nan],\n                [0., 0.,     0., np.nan, 7.,     6.]]),\n            np.zeros((2, 3)),\n            np.ones((2, 3)),\n        ]\n\n    @dense_sparse\n    def test_digitize(self, array):\n        for x_original in self.data:\n            x = array(x_original)\n            bins = np.arange(-2, 2)\n\n            x_shape = x.shape\n            np.testing.assert_array_equal(\n                np.digitize(x_original.flatten(), bins).reshape(x_shape),\n                digitize(x, bins),\n            )\n\n    @dense_sparse\n    def test_digitize_right(self, array):\n        for x_original in self.data:\n            x = array(x_original)\n            bins = np.arange(-2, 2)\n\n            x_shape = x.shape\n            np.testing.assert_array_equal(\n                np.digitize(x_original.flatten(), bins, right=True).reshape(x_shape),\n                digitize(x, bins, right=True)\n            )\n\n    @dense_sparse\n    def test_digitize_1d_array(self, array):\n        \"\"\"A consistent return shape must be returned for both sparse and dense.\"\"\"\n        x_original = np.array([0, 1, 1, 0, np.nan, 0, 1])\n        x = array(x_original)\n        bins = np.arange(-2, 2)\n\n        x_shape = x_original.shape\n        np.testing.assert_array_equal(\n            [np.digitize(x_original.flatten(), bins).reshape(x_shape)],\n            digitize(x, bins),\n        )\n\n    def test_digitize_sparse_zeroth_bin(self):\n        # Setup the data so that the '0's will fit into the '0'th bin.\n        data = csr_matrix([\n            [0, 0, 0, 1, 1, 0, 0, 1, 0],\n            [0, 0, 1, 1, 0, 0, 1, 0, 0],\n        ])\n        bins = np.array([1])\n        # Then digitize should return a sparse matrix\n        self.assertTrue(issparse(digitize(data, bins)))\n\n\nclass TestCountnans(unittest.TestCase):\n    @dense_sparse\n    def test_1d_array(self, array):\n        x = array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1])\n        self.assertEqual(countnans(x), 2)\n\n    @dense_sparse\n    def test_1d_array_with_axis_0(self, array):\n        x = array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1])\n        expected = 2\n\n        self.assertEqual(countnans(x, axis=0), expected)\n\n    @dense_sparse\n    def test_1d_array_with_axis_1_raises_exception(self, array):\n        with self.assertRaises(ValueError):\n            countnans(array([0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1]), axis=1)\n\n    @dense_sparse\n    def test_shape_matches_dense_and_sparse(self, array):\n        x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1],\n                   [1, 2, 2, 1, np.nan, 1, 2, 3, np.nan, 3]])\n        expected = 4\n\n        self.assertEqual(countnans(x), expected)\n\n    @dense_sparse\n    def test_shape_matches_dense_and_sparse_with_axis_0(self, array):\n        x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1],\n                   [1, 2, 2, 1, np.nan, 1, 2, np.nan, 3, 3]])\n        expected = [0, 0, 0, 0, 1, 1, 0, 2, 0, 0]\n\n        np.testing.assert_equal(countnans(x, axis=0), expected)\n\n    @dense_sparse\n    def test_shape_matches_dense_and_sparse_with_axis_1(self, array):\n        x = array([[0, 1, 0, 2, 2, np.nan, 1, np.nan, 0, 1],\n                   [1, 2, 2, 1, np.nan, 1, 2, 3, np.nan, 3]])\n        expected = [2, 2]\n\n        np.testing.assert_equal(countnans(x, axis=1), expected)\n\n    @dense_sparse\n    def test_2d_matrix(self, array):\n        x = array([[1, np.nan, 1, 2],\n                   [2, np.nan, 2, 3]])\n        expected = 2\n\n        self.assertEqual(countnans(x), expected)\n\n    @dense_sparse\n    def test_on_columns(self, array):\n        x = array([[1, np.nan, 1, 2],\n                   [2, np.nan, 2, 3]])\n        expected = [0, 2, 0, 0]\n\n        np.testing.assert_equal(countnans(x, axis=0), expected)\n\n    @dense_sparse\n    def test_on_rows(self, array):\n        x = array([[1, np.nan, 1, 2],\n                   [2, np.nan, 2, 3]])\n        expected = [1, 1]\n\n        np.testing.assert_equal(countnans(x, axis=1), expected)\n\n    @dense_sparse\n    def test_1d_weights_with_axis_0(self, array):\n        x = array([[1, 1, np.nan, 1],\n                   [np.nan, 1, 1, 1]])\n        w = np.array([0.5, 1, 1, 1])\n\n        np.testing.assert_equal(countnans(x, w, axis=0), [.5, 0, 1, 0])\n\n    @dense_sparse\n    def test_1d_weights_with_axis_1(self, array):\n        x = array([[1, 1, np.nan, 1],\n                   [np.nan, 1, 1, 1]])\n        w = np.array([0.5, 1])\n\n        np.testing.assert_equal(countnans(x, w, axis=1), [.5, 1])\n\n    @dense_sparse\n    def test_2d_weights(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[np.nan, np.nan, 1,      1 ],\n                   [     0, np.nan, 2, np.nan ]])\n        w = np.array([[1, 2, 3, 4],\n                      [5, 6, 7, 8]])\n\n        np.testing.assert_equal(countnans(x, w), 17)\n        np.testing.assert_equal(countnans(x, w, axis=0), [1, 8, 0, 8])\n        np.testing.assert_equal(countnans(x, w, axis=1), [3, 14])\n\n    @dense_sparse\n    def test_dtype(self, array):\n        x = array([0, np.nan, 2, 3])\n        w = np.array([0, 1.5, 0, 0])\n\n        self.assertIsInstance(countnans(x, w, dtype=np.int32), np.int32)\n        self.assertEqual(countnans(x, w, dtype=np.int32), 1)\n        self.assertIsInstance(countnans(x, w, dtype=np.float64), np.float64)\n        self.assertEqual(countnans(x, w, dtype=np.float64), 1.5)\n\n\nclass TestBincount(unittest.TestCase):\n    @dense_sparse\n    def test_count_nans(self, array):\n        x = array([0, 0, 1, 2, np.nan, 2])\n        expected = 1\n\n        np.testing.assert_equal(bincount(x)[1], expected)\n\n    # object arrays cannot be converted to sparse, so test only for dense\n    def test_count_nans_objectarray(self):\n        x = np.array([0, 0, 1, 2, np.nan, 2], dtype=object)\n        expected = 1\n\n        np.testing.assert_equal(bincount(x)[1], expected)\n\n    @dense_sparse\n    def test_adds_empty_bins(self, array):\n        x = array([0, 1, 3, 5])\n        expected = [1, 1, 0, 1, 0, 1]\n\n        np.testing.assert_equal(bincount(x)[0], expected)\n\n    @dense_sparse\n    def test_maxval_adds_empty_bins(self, array):\n        x = array([1, 1, 1, 2, 3, 2])\n        max_val = 5\n        expected = [0, 3, 2, 1, 0, 0]\n\n        np.testing.assert_equal(bincount(x, max_val=max_val)[0], expected)\n\n    @dense_sparse\n    def test_maxval_doesnt_truncate_values_when_too_small(self, array):\n        x = array([1, 1, 1, 2, 3, 2])\n        max_val = 1\n        expected = [0, 3, 2, 1]\n\n        np.testing.assert_equal(bincount(x, max_val=max_val)[0], expected)\n\n    @dense_sparse\n    def test_minlength_adds_empty_bins(self, array):\n        x = array([1, 1, 1, 2, 3, 2])\n        minlength = 5\n        expected = [0, 3, 2, 1, 0]\n\n        np.testing.assert_equal(bincount(x, minlength=minlength)[0], expected)\n\n    @dense_sparse\n    def test_weights(self, array):\n        x = array([0, 0, 1, 1, 2, 2, 3, 3])\n        w = np.array([1, 2, 0, 0, 1, 1, 0, 1])\n\n        expected = [3, 0, 2, 1]\n        np.testing.assert_equal(bincount(x, w)[0], expected)\n\n    @dense_sparse\n    def test_weights_with_nans(self, array):\n        x = array([0, 0, 1, 1, np.nan, 2, np.nan, 3])\n        w = np.array([1, 2, 0, 0, 1, 1, 0, 1])\n\n        expected = [3, 0, 1, 1]\n        np.testing.assert_equal(bincount(x, w)[0], expected)\n\n    @dense_sparse\n    def test_weights_with_transposed_x(self, array):\n        x = array([0, 0, 1, 1, 2, 2, 3, 3]).T\n        w = np.array([1, 2, 0, 0, 1, 1, 0, 1])\n\n        expected = [3, 0, 2, 1]\n        np.testing.assert_equal(bincount(x, w)[0], expected)\n\n    @dense_sparse\n    def test_all_nans(self, array):\n        x = array([np.nan] * 5)\n        expected = []\n\n        np.testing.assert_equal(bincount(x)[0], expected)\n\n    @dense_sparse\n    def test_all_zeros_or_nans(self, array):\n        \"\"\"Sparse arrays with only nans with no explicit zeros will have no non\n        zero indices. Check that this counts the zeros properly.\"\"\"\n        x = array([np.nan] * 5 + [0] * 5)\n        expected = [5]\n\n        np.testing.assert_equal(bincount(x)[0], expected)\n\n\nclass TestUnique(unittest.TestCase):\n    @dense_sparse\n    def test_returns_unique_values(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5.,    42.],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [-1, 0, 1, 2, 3, 5, 6, 7, 42, np.nan]\n\n        np.testing.assert_equal(unique(x, return_counts=False), expected)\n\n    @dense_sparse\n    def test_returns_counts(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5.,    42.],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [-1, 0, 1, 2, 3, 5, 6, 7, 42, np.nan]\n        expected_counts = [2, 6, 2, 1, 2, 1, 1, 1, 1, 1]\n\n        vals, counts = unique(x, return_counts=True)\n\n        np.testing.assert_equal(vals, expected)\n        np.testing.assert_equal(counts, expected_counts)\n\n    def test_sparse_explicit_zeros(self):\n        # Use `lil_matrix` to fix sparse warning for matrix construction\n        x = lil_matrix(np.eye(3))\n        x[0, 1] = 0\n        x[1, 0] = 0\n        x = x.tocsr()\n        # Test against identity matrix\n        y = csr_matrix(np.eye(3))\n\n        np.testing.assert_array_equal(\n            unique(y, return_counts=True),\n            unique(x, return_counts=True),\n        )\n\n    @dense_sparse\n    def test_nanunique_ignores_nans_in_values(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5., np.nan],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [-1, 0, 1, 2, 3, 5, 6, 7]\n\n        np.testing.assert_equal(nanunique(x, return_counts=False), expected)\n\n    @dense_sparse\n    def test_nanunique_ignores_nans_in_counts(self, array):\n        # pylint: disable=bad-whitespace\n        x = array([[-1., 1., 0., 2., 3., np.nan],\n                   [ 0., 0., 0., 3., 5., np.nan],\n                   [-1., 0., 0., 1., 7.,     6.]])\n        expected = [2, 6, 2, 1, 2, 1, 1, 1]\n\n        np.testing.assert_equal(nanunique(x, return_counts=True)[1], expected)\n\n\nclass TestNanToNum(unittest.TestCase):\n    @dense_sparse\n    def test_converts_invalid_values(self, array):\n        x = np.array([\n            [np.nan, 0, 2, np.inf],\n            [-np.inf, np.nan, 1e-18, 2],\n            [np.nan, np.nan, np.nan, np.nan],\n            [np.inf, np.inf, np.inf, np.inf],\n        ])\n        result = nan_to_num(array(x))\n        np.testing.assert_equal(assure_array_dense(result), np.nan_to_num(x))\n\n    @dense_sparse\n    def test_preserves_valid_values(self, array):\n        x = np.arange(12).reshape((3, 4))\n        result = nan_to_num(array(x))\n        np.testing.assert_equal(assure_array_dense(result), x)\n        np.testing.assert_equal(assure_array_dense(result), np.nan_to_num(x))\n\n\nclass TestIsnan(unittest.TestCase):\n    def setUp(self) -> None:\n        # pylint: disable=bad-whitespace\n        self.x = np.array([\n            [0., 1.,     0., np.nan, 3.,     5.],\n            [0., 0., np.nan, np.nan, 5., np.nan],\n            [0., 0.,     0., np.nan, 7.,     6.],\n            [0., 0.,     0.,     5., 7.,     6.],\n        ])\n\n    @dense_sparse\n    def test_functionality(self, array):\n        expected = np.isnan(self.x)\n        result = isnan(array(self.x))\n        np.testing.assert_equal(assure_array_dense(result), expected)\n\n    @dense_sparse\n    def test_out(self, array):\n        x = array(self.x)\n        x_dtype = x.dtype\n        result = isnan(x, out=x)\n        self.assertIs(result, x)\n        self.assertEqual(x_dtype, result.dtype)\n\n\nclass TestAnyNans(unittest.TestCase):\n    def setUp(self) -> None:\n        # pylint: disable=bad-whitespace\n        self.x_with_nans = np.array([\n            [0., 1.,     0., np.nan, 3.,     5.],\n            [0., 0., np.nan, np.nan, 5., np.nan],\n            [0., 0.,     0., np.nan, 7.,     6.],\n            [0., 0.,     0.,     5., 7.,     6.],\n        ])\n        self.x_no_nans = np.arange(12).reshape((3, 4))\n\n    @dense_sparse\n    def test_axis_none_without_nans(self, array):\n        self.assertFalse(any_nan(array(self.x_no_nans)))\n\n    @dense_sparse\n    def test_axis_none_with_nans(self, array):\n        self.assertTrue(any_nan(array(self.x_with_nans)))\n\n    @dense_sparse\n    def test_axis_0_without_nans(self, array):\n        expected = np.array([0, 0, 0, 0], dtype=bool)\n        result = any_nan(array(self.x_no_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_0_with_nans(self, array):\n        expected = np.array([0, 0, 1, 1, 0, 1], dtype=bool)\n        result = any_nan(array(self.x_with_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_without_nans(self, array):\n        expected = np.array([0, 0, 0], dtype=bool)\n        result = any_nan(array(self.x_no_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_with_nans(self, array):\n        expected = np.array([1, 1, 1, 0], dtype=bool)\n        result = any_nan(array(self.x_with_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n\nclass TestAllNans(unittest.TestCase):\n    def setUp(self) -> None:\n        # pylint: disable=bad-whitespace\n        self.x_with_nans = np.array([\n            [0.,     1.,     0.,     np.nan, 3.,     5.],\n            [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],\n            [0.,     0.,     0.,     np.nan, 7.,     6.],\n            [0.,     0.,     0.,     np.nan, 7.,     np.nan],\n        ])\n        self.x_no_nans = np.arange(12).reshape((3, 4))\n        self.x_only_nans = (np.ones(12) * np.nan).reshape((3, 4))\n\n    @dense_sparse\n    def test_axis_none_without_nans(self, array):\n        self.assertFalse(all_nan(array(self.x_no_nans)))\n\n    @dense_sparse\n    def test_axis_none_with_nans(self, array):\n        self.assertTrue(all_nan(array(self.x_only_nans)))\n\n    @dense_sparse\n    def test_axis_0_without_nans(self, array):\n        expected = np.array([0, 0, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_no_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_0_with_nans(self, array):\n        expected = np.array([0, 0, 0, 1, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_with_nans), axis=0)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_without_nans(self, array):\n        expected = np.array([0, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_no_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n    @dense_sparse\n    def test_axis_1_with_nans(self, array):\n        expected = np.array([0, 1, 0, 0], dtype=bool)\n        result = all_nan(array(self.x_with_nans), axis=1)\n        np.testing.assert_equal(result, expected)\n\n\nclass TestNanModeFixedInScipy(unittest.TestCase):\n\n    @unittest.expectedFailure\n    def test_scipy_nanmode_still_wrong(self):\n        import scipy.stats\n        X = np.array([[np.nan, np.nan, 1, 1],\n                      [2, np.nan, 1, 1]])\n        mode, count = scipy.stats.mode(X, 0)\n        np.testing.assert_array_equal(mode, [[2, np.nan, 1, 1]])\n        np.testing.assert_array_equal(count, [[1, np.nan, 2, 2]])\n        mode, count = scipy.stats.mode(X, 1)\n        np.testing.assert_array_equal(mode, [[1], [1]])\n        np.testing.assert_array_equal(count, [[2], [2]])\n        # When Scipy's scipy.stats.mode works correcly, remove Orange.statistics.util.nanmode\n        # and this test. Also update requirements.\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Orange installation attempts...\nAttempting installation with Python 3.7...\nrunning build_ext\nCompiling Orange/classification/_tree_scorers.pyx because it changed.\nCompiling Orange/data/_contingency.pyx because it changed.\nCompiling Orange/data/_io.pyx because it changed.\nCompiling Orange/data/_valuecount.pyx because it changed.\nCompiling Orange/data/_variable.pyx because it changed.\nCompiling Orange/distance/_distance.pyx because it changed.\nCompiling Orange/preprocess/_discretize.pyx because it changed.\nCompiling Orange/preprocess/_relieff.pyx because it changed.\nCompiling Orange/projection/_som.pyx because it changed.\n[1/9] Cythonizing Orange/classification/_tree_scorers.pyx\n[2/9] Cythonizing Orange/data/_contingency.pyx\n[3/9] Cythonizing Orange/data/_io.pyx\n[4/9] Cythonizing Orange/data/_valuecount.pyx\n[5/9] Cythonizing Orange/data/_variable.pyx\n[6/9] Cythonizing Orange/distance/_distance.pyx\n[7/9] Cythonizing Orange/preprocess/_discretize.pyx\n[8/9] Cythonizing Orange/preprocess/_relieff.pyx\n[9/9] Cythonizing Orange/projection/_som.pyx\nbuilding 'Orange.classification._tree_scorers' extension\ncreating build\ncreating build/temp.linux-x86_64-3.7\ncreating build/temp.linux-x86_64-3.7/Orange\ncreating build/temp.linux-x86_64-3.7/Orange/classification\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/classification/_tree_scorers.c -o build/temp.linux-x86_64-3.7/Orange/classification/_tree_scorers.o\ncreating build/lib.linux-x86_64-3.7\ncreating build/lib.linux-x86_64-3.7/Orange\ncreating build/lib.linux-x86_64-3.7/Orange/classification\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/classification/_tree_scorers.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/classification/_tree_scorers.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._contingency' extension\ncreating build/temp.linux-x86_64-3.7/Orange/data\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/data/_contingency.c -o build/temp.linux-x86_64-3.7/Orange/data/_contingency.o\ncreating build/lib.linux-x86_64-3.7/Orange/data\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_contingency.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/data/_contingency.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._io' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/data/_io.c -o build/temp.linux-x86_64-3.7/Orange/data/_io.o\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_io.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/data/_io.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._valuecount' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/data/_valuecount.c -o build/temp.linux-x86_64-3.7/Orange/data/_valuecount.o\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_valuecount.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/data/_valuecount.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.data._variable' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/data/_variable.c -o build/temp.linux-x86_64-3.7/Orange/data/_variable.o\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/data/_variable.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/data/_variable.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.distance._distance' extension\ncreating build/temp.linux-x86_64-3.7/Orange/distance\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/distance/_distance.c -o build/temp.linux-x86_64-3.7/Orange/distance/_distance.o\ncreating build/lib.linux-x86_64-3.7/Orange/distance\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/distance/_distance.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/distance/_distance.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._discretize' extension\ncreating build/temp.linux-x86_64-3.7/Orange/preprocess\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/preprocess/_discretize.c -o build/temp.linux-x86_64-3.7/Orange/preprocess/_discretize.o\ncreating build/lib.linux-x86_64-3.7/Orange/preprocess\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/preprocess/_discretize.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/preprocess/_discretize.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._relieff' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/preprocess/_relieff.cpp -o build/temp.linux-x86_64-3.7/Orange/preprocess/_relieff.o\nc++ -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/preprocess/_relieff.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/preprocess/_relieff.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.projection._som' extension\ncreating build/temp.linux-x86_64-3.7/Orange/projection\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/projection/_som.c -o build/temp.linux-x86_64-3.7/Orange/projection/_som.o\ncreating build/lib.linux-x86_64-3.7/Orange/projection\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/projection/_som.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/projection/_som.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.classification._simple_tree' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/classification/_simple_tree.c -o build/temp.linux-x86_64-3.7/Orange/classification/_simple_tree.o\ncc -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/classification/_simple_tree.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/classification/_simple_tree.cpython-37m-x86_64-linux-gnu.so\nbuilding 'Orange.widgets.utils._grid_density' extension\ncreating build/temp.linux-x86_64-3.7/Orange/widgets\ncreating build/temp.linux-x86_64-3.7/Orange/widgets/utils\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/tools/deps/include -I/tools/deps/include/ncursesw -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/include/python3.7m -c Orange/widgets/utils/_grid_density.cpp -o build/temp.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.o\ncreating build/lib.linux-x86_64-3.7/Orange/widgets\ncreating build/lib.linux-x86_64-3.7/Orange/widgets/utils\nc++ -pthread -shared -L/tools/deps/lib build/temp.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.o -L/home/gcpuser/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/lib -lm -lpython3.7m -o build/lib.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.cpython-37m-x86_64-linux-gnu.so\ncopying build/lib.linux-x86_64-3.7/Orange/classification/_tree_scorers.cpython-37m-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-3.7/Orange/data/_contingency.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_io.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_valuecount.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_variable.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/distance/_distance.cpython-37m-x86_64-linux-gnu.so -> Orange/distance\ncopying build/lib.linux-x86_64-3.7/Orange/preprocess/_discretize.cpython-37m-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-3.7/Orange/preprocess/_relieff.cpython-37m-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-3.7/Orange/projection/_som.cpython-37m-x86_64-linux-gnu.so -> Orange/projection\ncopying build/lib.linux-x86_64-3.7/Orange/classification/_simple_tree.cpython-37m-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.cpython-37m-x86_64-linux-gnu.so -> Orange/widgets/utils\nrunning develop\nrunning egg_info\ncreating Orange3.egg-info\nwriting Orange3.egg-info/PKG-INFO\nwriting dependency_links to Orange3.egg-info/dependency_links.txt\nwriting entry points to Orange3.egg-info/entry_points.txt\nwriting requirements to Orange3.egg-info/requires.txt\nwriting top-level names to Orange3.egg-info/top_level.txt\nwriting manifest file 'Orange3.egg-info/SOURCES.txt'\nreading manifest file 'Orange3.egg-info/SOURCES.txt'\nreading manifest template 'MANIFEST.in'\nadding license file 'LICENSE'\nwriting manifest file 'Orange3.egg-info/SOURCES.txt'\nrunning build_ext\ncopying build/lib.linux-x86_64-3.7/Orange/classification/_tree_scorers.cpython-37m-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-3.7/Orange/data/_contingency.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_io.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_valuecount.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/data/_variable.cpython-37m-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-3.7/Orange/distance/_distance.cpython-37m-x86_64-linux-gnu.so -> Orange/distance\ncopying build/lib.linux-x86_64-3.7/Orange/preprocess/_discretize.cpython-37m-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-3.7/Orange/preprocess/_relieff.cpython-37m-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-3.7/Orange/projection/_som.cpython-37m-x86_64-linux-gnu.so -> Orange/projection\ncopying build/lib.linux-x86_64-3.7/Orange/classification/_simple_tree.cpython-37m-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-3.7/Orange/widgets/utils/_grid_density.cpython-37m-x86_64-linux-gnu.so -> Orange/widgets/utils\nCreating /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/Orange3.egg-link (link to .)\nAdding Orange3 3.35.0.dev0+39cdce6 to easy-install.pth file\nInstalling orange-canvas script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nInstalled /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5\nProcessing dependencies for Orange3==3.35.0.dev0+39cdce6\nSearching for xlsxwriter\nReading https://pypi.org/simple/xlsxwriter/\nDownloading https://files.pythonhosted.org/packages/a7/ea/53d1fe468e63e092cf16e2c18d16f50c29851242f9dd12d6a66e0d7f0d02/XlsxWriter-3.2.0-py3-none-any.whl#sha256=ecfd5405b3e0e228219bcaf24c2ca0915e012ca9464a14048021d21a995d490e\nBest match: XlsxWriter 3.2.0\nProcessing XlsxWriter-3.2.0-py3-none-any.whl\nInstalling XlsxWriter-3.2.0-py3-none-any.whl to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages\nAdding XlsxWriter 3.2.0 to easy-install.pth file\nInstalling vba_extract.py script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nInstalled /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/XlsxWriter-3.2.0-py3.7.egg\nSearching for xlrd>=1.2.0\nReading https://pypi.org/simple/xlrd/\nDownloading https://files.pythonhosted.org/packages/a6/0c/c2a72d51fe56e08a08acc85d13013558a2d793028ae7385448a6ccdfae64/xlrd-2.0.1-py2.py3-none-any.whl#sha256=6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd\nBest match: xlrd 2.0.1\nProcessing xlrd-2.0.1-py2.py3-none-any.whl\nInstalling xlrd-2.0.1-py2.py3-none-any.whl to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages\nAdding xlrd 2.0.1 to easy-install.pth file\nInstalling runxlrd.py script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nInstalled /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/xlrd-2.0.1-py3.7.egg\nSearching for serverfiles\nReading https://pypi.org/simple/serverfiles/\nDownloading https://files.pythonhosted.org/packages/33/36/794fe1c4ed29b0f56a26d72e956baf0285d8fe9e29faf36797a28a8ad45b/serverfiles-0.3.1.tar.gz#sha256=5e10fc32e758791e3735bc08bce2ed4702a83b1e45ab96c5d59cc8aeecfbebe1\nBest match: serverfiles 0.3.1\nProcessing serverfiles-0.3.1.tar.gz\nWriting /tmp/easy_install-_2dke9uh/serverfiles-0.3.1/setup.cfg\nRunning serverfiles-0.3.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-_2dke9uh/serverfiles-0.3.1/egg-dist-tmp-ii6i6356\ncreating /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/serverfiles-0.3.1-py3.7.egg\nExtracting serverfiles-0.3.1-py3.7.egg to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages\nAdding serverfiles 0.3.1 to easy-install.pth file\n\nInstalled /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/serverfiles-0.3.1-py3.7.egg\nSearching for scipy>=1.9\nReading https://pypi.org/simple/scipy/\nDownloading https://files.pythonhosted.org/packages/d9/7b/2b8ac283cf32465ed08bc20a83d559fe7b174a484781702ba8accea001d6/scipy-1.15.0.tar.gz#sha256=300742e2cc94e36a2880ebe464a1c8b4352a7b0f3e36ec3d2ac006cdbe0219ac\nBest match: scipy 1.15.0\nProcessing scipy-1.15.0.tar.gz\nVerifying Orange installation...\n❌ Orange verification failed\nPython 3.7 installation failed, trying Python 3.8...\nAttempting installation with Python 3.8...\nrunning build_ext\nbuilding 'Orange.classification._tree_scorers' extension\ncreating build/temp.linux-x86_64-cpython-38/Orange/classification\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/classification/_tree_scorers.c -o build/temp.linux-x86_64-cpython-38/Orange/classification/_tree_scorers.o\ncreating build/lib.linux-x86_64-cpython-38/Orange/classification\ncc -pthread -shared -Wl,--exclude-libs,ALL build/temp.linux-x86_64-cpython-38/Orange/classification/_tree_scorers.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/classification/_tree_scorers.cpython-38-x86_64-linux-gnu.so\nbuilding 'Orange.data._contingency' extension\ncreating build/temp.linux-x86_64-cpython-38/Orange/data\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/data/_contingency.c -o build/temp.linux-x86_64-cpython-38/Orange/data/_contingency.o\ncreating build/lib.linux-x86_64-cpython-38/Orange/data\ncc -pthread -shared -Wl,--exclude-libs,ALL build/temp.linux-x86_64-cpython-38/Orange/data/_contingency.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/data/_contingency.cpython-38-x86_64-linux-gnu.so\nbuilding 'Orange.data._io' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/data/_io.c -o build/temp.linux-x86_64-cpython-38/Orange/data/_io.o\ncc -pthread -shared -Wl,--exclude-libs,ALL build/temp.linux-x86_64-cpython-38/Orange/data/_io.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/data/_io.cpython-38-x86_64-linux-gnu.so\nbuilding 'Orange.data._valuecount' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/data/_valuecount.c -o build/temp.linux-x86_64-cpython-38/Orange/data/_valuecount.o\ncc -pthread -shared -Wl,--exclude-libs,ALL build/temp.linux-x86_64-cpython-38/Orange/data/_valuecount.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/data/_valuecount.cpython-38-x86_64-linux-gnu.so\nbuilding 'Orange.data._variable' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/data/_variable.c -o build/temp.linux-x86_64-cpython-38/Orange/data/_variable.o\ncc -pthread -shared -Wl,--exclude-libs,ALL build/temp.linux-x86_64-cpython-38/Orange/data/_variable.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/data/_variable.cpython-38-x86_64-linux-gnu.so\nbuilding 'Orange.distance._distance' extension\ncreating build/temp.linux-x86_64-cpython-38/Orange/distance\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/distance/_distance.c -o build/temp.linux-x86_64-cpython-38/Orange/distance/_distance.o\ncreating build/lib.linux-x86_64-cpython-38/Orange/distance\ncc -pthread -shared -Wl,--exclude-libs,ALL build/temp.linux-x86_64-cpython-38/Orange/distance/_distance.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/distance/_distance.cpython-38-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._discretize' extension\ncreating build/temp.linux-x86_64-cpython-38/Orange/preprocess\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/preprocess/_discretize.c -o build/temp.linux-x86_64-cpython-38/Orange/preprocess/_discretize.o\ncreating build/lib.linux-x86_64-cpython-38/Orange/preprocess\ncc -pthread -shared -Wl,--exclude-libs,ALL build/temp.linux-x86_64-cpython-38/Orange/preprocess/_discretize.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/preprocess/_discretize.cpython-38-x86_64-linux-gnu.so\nbuilding 'Orange.preprocess._relieff' extension\nc++ -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/preprocess/_relieff.cpp -o build/temp.linux-x86_64-cpython-38/Orange/preprocess/_relieff.o\nc++ -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -pthread -shared build/temp.linux-x86_64-cpython-38/Orange/preprocess/_relieff.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/preprocess/_relieff.cpython-38-x86_64-linux-gnu.so\nbuilding 'Orange.projection._som' extension\ncreating build/temp.linux-x86_64-cpython-38/Orange/projection\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/projection/_som.c -o build/temp.linux-x86_64-cpython-38/Orange/projection/_som.o\ncreating build/lib.linux-x86_64-cpython-38/Orange/projection\ncc -pthread -shared -Wl,--exclude-libs,ALL build/temp.linux-x86_64-cpython-38/Orange/projection/_som.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/projection/_som.cpython-38-x86_64-linux-gnu.so\nbuilding 'Orange.classification._simple_tree' extension\ncc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/classification/_simple_tree.c -o build/temp.linux-x86_64-cpython-38/Orange/classification/_simple_tree.o\ncc -pthread -shared -Wl,--exclude-libs,ALL build/temp.linux-x86_64-cpython-38/Orange/classification/_simple_tree.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/classification/_simple_tree.cpython-38-x86_64-linux-gnu.so\nbuilding 'Orange.widgets.utils._grid_density' extension\ncreating build/temp.linux-x86_64-cpython-38/Orange/widgets/utils\nc++ -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -fPIC -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include -I/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/include -I/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/include/python3.8 -c Orange/widgets/utils/_grid_density.cpp -o build/temp.linux-x86_64-cpython-38/Orange/widgets/utils/_grid_density.o\ncreating build/lib.linux-x86_64-cpython-38/Orange/widgets/utils\nc++ -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -pthread -shared build/temp.linux-x86_64-cpython-38/Orange/widgets/utils/_grid_density.o -L/home/gcpuser/.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib -lm -o build/lib.linux-x86_64-cpython-38/Orange/widgets/utils/_grid_density.cpython-38-x86_64-linux-gnu.so\ncopying build/lib.linux-x86_64-cpython-38/Orange/classification/_tree_scorers.cpython-38-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-cpython-38/Orange/data/_contingency.cpython-38-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-cpython-38/Orange/data/_io.cpython-38-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-cpython-38/Orange/data/_valuecount.cpython-38-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-cpython-38/Orange/data/_variable.cpython-38-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-cpython-38/Orange/distance/_distance.cpython-38-x86_64-linux-gnu.so -> Orange/distance\ncopying build/lib.linux-x86_64-cpython-38/Orange/preprocess/_discretize.cpython-38-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-cpython-38/Orange/preprocess/_relieff.cpython-38-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-cpython-38/Orange/projection/_som.cpython-38-x86_64-linux-gnu.so -> Orange/projection\ncopying build/lib.linux-x86_64-cpython-38/Orange/classification/_simple_tree.cpython-38-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-cpython-38/Orange/widgets/utils/_grid_density.cpython-38-x86_64-linux-gnu.so -> Orange/widgets/utils\nrunning develop\nrunning egg_info\nwriting Orange3.egg-info/PKG-INFO\nwriting dependency_links to Orange3.egg-info/dependency_links.txt\nwriting entry points to Orange3.egg-info/entry_points.txt\nwriting requirements to Orange3.egg-info/requires.txt\nwriting top-level names to Orange3.egg-info/top_level.txt\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayscalars.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_math.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ufuncobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayscalars.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_math.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ufuncobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayscalars.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_math.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ufuncobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayscalars.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_math.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ufuncobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayscalars.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ufuncobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayscalars.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_math.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ufuncobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayscalars.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_math.h won't be automatically included in the manifest: the path must be relative\ndependency /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ufuncobject.h won't be automatically included in the manifest: the path must be relative\nreading manifest file 'Orange3.egg-info/SOURCES.txt'\nreading manifest template 'MANIFEST.in'\nadding license file 'LICENSE'\nwriting manifest file 'Orange3.egg-info/SOURCES.txt'\nrunning build_ext\ncopying build/lib.linux-x86_64-cpython-38/Orange/classification/_tree_scorers.cpython-38-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-cpython-38/Orange/data/_contingency.cpython-38-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-cpython-38/Orange/data/_io.cpython-38-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-cpython-38/Orange/data/_valuecount.cpython-38-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-cpython-38/Orange/data/_variable.cpython-38-x86_64-linux-gnu.so -> Orange/data\ncopying build/lib.linux-x86_64-cpython-38/Orange/distance/_distance.cpython-38-x86_64-linux-gnu.so -> Orange/distance\ncopying build/lib.linux-x86_64-cpython-38/Orange/preprocess/_discretize.cpython-38-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-cpython-38/Orange/preprocess/_relieff.cpython-38-x86_64-linux-gnu.so -> Orange/preprocess\ncopying build/lib.linux-x86_64-cpython-38/Orange/projection/_som.cpython-38-x86_64-linux-gnu.so -> Orange/projection\ncopying build/lib.linux-x86_64-cpython-38/Orange/classification/_simple_tree.cpython-38-x86_64-linux-gnu.so -> Orange/classification\ncopying build/lib.linux-x86_64-cpython-38/Orange/widgets/utils/_grid_density.cpython-38-x86_64-linux-gnu.so -> Orange/widgets/utils\nCreating /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/Orange3.egg-link (link to .)\nAdding Orange3 3.35.0.dev0+39cdce6 to easy-install.pth file\nInstalling orange-canvas script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nInstalled /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5\nProcessing dependencies for Orange3==3.35.0.dev0+39cdce6\nSearching for XlsxWriter==3.2.0\nBest match: XlsxWriter 3.2.0\nAdding XlsxWriter 3.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for xlrd==2.0.1\nBest match: xlrd 2.0.1\nAdding xlrd 2.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for setuptools==75.3.0\nBest match: setuptools 75.3.0\nAdding setuptools 75.3.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for serverfiles==0.3.1\nBest match: serverfiles 0.3.1\nAdding serverfiles 0.3.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for scipy==1.10.1\nBest match: scipy 1.10.1\nAdding scipy 1.10.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for scikit-learn==1.1.3\nBest match: scikit-learn 1.1.3\nAdding scikit-learn 1.1.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for requests==2.32.3\nBest match: requests 2.32.3\nAdding requests 2.32.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for qtconsole==5.6.1\nBest match: qtconsole 5.6.1\nAdding qtconsole 5.6.1 to easy-install.pth file\nInstalling jupyter-qtconsole script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for PyYAML==6.0.2\nBest match: PyYAML 6.0.2\nAdding PyYAML 6.0.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for python-louvain==0.16\nBest match: python-louvain 0.16\nAdding python-louvain 0.16 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pyqtgraph==0.13.3\nBest match: pyqtgraph 0.13.3\nAdding pyqtgraph 0.13.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pygments==2.19.1\nBest match: pygments 2.19.1\nAdding pygments 2.19.1 to easy-install.pth file\nInstalling pygmentize script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pip==24.3.1\nBest match: pip 24.3.1\nAdding pip 24.3.1 to easy-install.pth file\nInstalling pip script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling pip3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pandas==2.0.3\nBest match: pandas 2.0.3\nAdding pandas 2.0.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for orange-widget-base==4.22.0\nBest match: orange-widget-base 4.22.0\nAdding orange-widget-base 4.22.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for orange-canvas-core==0.1.35\nBest match: orange-canvas-core 0.1.35\nAdding orange-canvas-core 0.1.35 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for openpyxl==3.1.5\nBest match: openpyxl 3.1.5\nAdding openpyxl 3.1.5 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for openTSNE==1.0.1\nBest match: openTSNE 1.0.1\nAdding openTSNE 1.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for numpy==1.24.4\nBest match: numpy 1.24.4\nAdding numpy 1.24.4 to easy-install.pth file\nInstalling f2py script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling f2py3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling f2py3.8 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for networkx==3.1\nBest match: networkx 3.1\nAdding networkx 3.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for matplotlib==3.7.5\nBest match: matplotlib 3.7.5\nAdding matplotlib 3.7.5 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for keyrings.alt==5.0.2\nBest match: keyrings.alt 5.0.2\nAdding keyrings.alt 5.0.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for keyring==25.5.0\nBest match: keyring 25.5.0\nAdding keyring 25.5.0 to easy-install.pth file\nInstalling keyring script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for joblib==1.4.2\nBest match: joblib 1.4.2\nAdding joblib 1.4.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for httpx==0.28.1\nBest match: httpx 0.28.1\nAdding httpx 0.28.1 to easy-install.pth file\nInstalling httpx script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for chardet==5.2.0\nBest match: chardet 5.2.0\nAdding chardet 5.2.0 to easy-install.pth file\nInstalling chardetect script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for Bottleneck==1.4.0\nBest match: Bottleneck 1.4.0\nAdding Bottleneck 1.4.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for baycomp==1.0.3\nBest match: baycomp 1.0.3\nAdding baycomp 1.0.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for AnyQt==0.2.0\nBest match: AnyQt 0.2.0\nAdding AnyQt 0.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for threadpoolctl==3.5.0\nBest match: threadpoolctl 3.5.0\nAdding threadpoolctl 3.5.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for certifi==2024.12.14\nBest match: certifi 2024.12.14\nAdding certifi 2024.12.14 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for urllib3==2.2.3\nBest match: urllib3 2.2.3\nAdding urllib3 2.2.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for idna==3.10\nBest match: idna 3.10\nAdding idna 3.10 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for charset-normalizer==3.4.1\nBest match: charset-normalizer 3.4.1\nAdding charset-normalizer 3.4.1 to easy-install.pth file\nInstalling normalizer script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for packaging==24.2\nBest match: packaging 24.2\nAdding packaging 24.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for QtPy==2.4.2\nBest match: QtPy 2.4.2\nAdding QtPy 2.4.2 to easy-install.pth file\nInstalling qtpy script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for ipykernel==6.29.5\nBest match: ipykernel 6.29.5\nAdding ipykernel 6.29.5 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for jupyter-client==8.6.3\nBest match: jupyter-client 8.6.3\nAdding jupyter-client 8.6.3 to easy-install.pth file\nInstalling jupyter-kernel script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling jupyter-kernelspec script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling jupyter-run script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for jupyter-core==5.7.2\nBest match: jupyter-core 5.7.2\nAdding jupyter-core 5.7.2 to easy-install.pth file\nInstalling jupyter script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling jupyter-migrate script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling jupyter-troubleshoot script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for traitlets==5.14.3\nBest match: traitlets 5.14.3\nAdding traitlets 5.14.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for tzdata==2024.2\nBest match: tzdata 2024.2\nAdding tzdata 2024.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pytz==2024.2\nBest match: pytz 2024.2\nAdding pytz 2024.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for python-dateutil==2.9.0.post0\nBest match: python-dateutil 2.9.0.post0\nAdding python-dateutil 2.9.0.post0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for typing-extensions==4.12.2\nBest match: typing-extensions 4.12.2\nAdding typing-extensions 4.12.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/setuptools/_vendor\nSearching for qasync==0.27.1\nBest match: qasync 0.27.1\nAdding qasync 0.27.1 to easy-install.pth file\ndetected new path './setuptools/_vendor'\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for dictdiffer==0.9.0\nBest match: dictdiffer 0.9.0\nAdding dictdiffer 0.9.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for requests-cache==1.2.1\nBest match: requests-cache 1.2.1\nAdding requests-cache 1.2.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for commonmark==0.9.1\nBest match: commonmark 0.9.1\nAdding commonmark 0.9.1 to easy-install.pth file\nInstalling cmark script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for docutils==0.20.1\nBest match: docutils 0.20.1\nAdding docutils 0.20.1 to easy-install.pth file\nInstalling docutils script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for et-xmlfile==2.0.0\nBest match: et-xmlfile 2.0.0\nAdding et-xmlfile 2.0.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for importlib-resources==6.4.5\nBest match: importlib-resources 6.4.5\nAdding importlib-resources 6.4.5 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pyparsing==3.1.4\nBest match: pyparsing 3.1.4\nAdding pyparsing 3.1.4 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pillow==10.4.0\nBest match: pillow 10.4.0\nAdding pillow 10.4.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for kiwisolver==1.4.7\nBest match: kiwisolver 1.4.7\nAdding kiwisolver 1.4.7 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for fonttools==4.55.3\nBest match: fonttools 4.55.3\nAdding fonttools 4.55.3 to easy-install.pth file\nInstalling fonttools script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling pyftmerge script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling pyftsubset script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling ttx script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for cycler==0.12.1\nBest match: cycler 0.12.1\nAdding cycler 0.12.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for contourpy==1.1.1\nBest match: contourpy 1.1.1\nAdding contourpy 1.1.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for jaraco.context==6.0.1\nBest match: jaraco.context 6.0.1\nAdding jaraco.context 6.0.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for jaraco.classes==3.4.0\nBest match: jaraco.classes 3.4.0\nAdding jaraco.classes 3.4.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for jeepney==0.8.0\nBest match: jeepney 0.8.0\nAdding jeepney 0.8.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for SecretStorage==3.3.3\nBest match: SecretStorage 3.3.3\nAdding SecretStorage 3.3.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for importlib-metadata==8.5.0\nBest match: importlib-metadata 8.5.0\nAdding importlib-metadata 8.5.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for jaraco.functools==4.1.0\nBest match: jaraco.functools 4.1.0\nAdding jaraco.functools 4.1.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for httpcore==1.0.7\nBest match: httpcore 1.0.7\nAdding httpcore 1.0.7 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for anyio==4.5.2\nBest match: anyio 4.5.2\nAdding anyio 4.5.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for tornado==6.4.2\nBest match: tornado 6.4.2\nAdding tornado 6.4.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pyzmq==26.2.0\nBest match: pyzmq 26.2.0\nAdding pyzmq 26.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for psutil==6.1.1\nBest match: psutil 6.1.1\nAdding psutil 6.1.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for nest-asyncio==1.6.0\nBest match: nest-asyncio 1.6.0\nAdding nest-asyncio 1.6.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for matplotlib-inline==0.1.7\nBest match: matplotlib-inline 0.1.7\nAdding matplotlib-inline 0.1.7 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for ipython==8.12.3\nBest match: ipython 8.12.3\nAdding ipython 8.12.3 to easy-install.pth file\nInstalling ipython script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\nInstalling ipython3 script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for debugpy==1.8.11\nBest match: debugpy 1.8.11\nAdding debugpy 1.8.11 to easy-install.pth file\nInstalling debugpy script to /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/bin\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for comm==0.2.2\nBest match: comm 0.2.2\nAdding comm 0.2.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for platformdirs==4.3.6\nBest match: platformdirs 4.3.6\nAdding platformdirs 4.3.6 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for six==1.17.0\nBest match: six 1.17.0\nAdding six 1.17.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for url-normalize==1.4.3\nBest match: url-normalize 1.4.3\nAdding url-normalize 1.4.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for cattrs==24.1.2\nBest match: cattrs 24.1.2\nAdding cattrs 24.1.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for attrs==24.3.0\nBest match: attrs 24.3.0\nAdding attrs 24.3.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for zipp==3.20.2\nBest match: zipp 3.20.2\nAdding zipp 3.20.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for backports.tarfile==1.2.0\nBest match: backports.tarfile 1.2.0\nbackports.tarfile 1.2.0 is already the active version in easy-install.pth\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/setuptools/_vendor\nSearching for more-itertools==10.5.0\nBest match: more-itertools 10.5.0\nAdding more-itertools 10.5.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for cryptography==44.0.0\nBest match: cryptography 44.0.0\nAdding cryptography 44.0.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for h11==0.14.0\nBest match: h11 0.14.0\nAdding h11 0.14.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for exceptiongroup==1.2.2\nBest match: exceptiongroup 1.2.2\nAdding exceptiongroup 1.2.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for sniffio==1.3.1\nBest match: sniffio 1.3.1\nAdding sniffio 1.3.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pexpect==4.9.0\nBest match: pexpect 4.9.0\nAdding pexpect 4.9.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for stack-data==0.6.3\nBest match: stack-data 0.6.3\nAdding stack-data 0.6.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for prompt-toolkit==3.0.48\nBest match: prompt-toolkit 3.0.48\nAdding prompt-toolkit 3.0.48 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pickleshare==0.7.5\nBest match: pickleshare 0.7.5\nAdding pickleshare 0.7.5 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for jedi==0.19.2\nBest match: jedi 0.19.2\nAdding jedi 0.19.2 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for decorator==5.1.1\nBest match: decorator 5.1.1\nAdding decorator 5.1.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for backcall==0.2.0\nBest match: backcall 0.2.0\nAdding backcall 0.2.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for cffi==1.17.1\nBest match: cffi 1.17.1\nAdding cffi 1.17.1 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for ptyprocess==0.7.0\nBest match: ptyprocess 0.7.0\nAdding ptyprocess 0.7.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pure-eval==0.2.3\nBest match: pure-eval 0.2.3\nAdding pure-eval 0.2.3 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for asttokens==3.0.0\nBest match: asttokens 3.0.0\nAdding asttokens 3.0.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for executing==2.1.0\nBest match: executing 2.1.0\nAdding executing 2.1.0 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for wcwidth==0.2.13\nBest match: wcwidth 0.2.13\nAdding wcwidth 0.2.13 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for parso==0.8.4\nBest match: parso 0.8.4\nAdding parso 0.8.4 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nSearching for pycparser==2.22\nBest match: pycparser 2.22\nAdding pycparser 2.22 to easy-install.pth file\n\nUsing /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages\nFinished processing dependencies for Orange3==3.35.0.dev0+39cdce6\nVerifying Orange installation...\n✅ Orange installation successful!\nSuccessfully installed orange using Python 3.8\n",
    "setup_res_stderr": "Using CPython 3.7.9\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 18 packages in 156ms\nPrepared 18 packages in 5ms\nInstalled 18 packages in 150ms\n + cython==0.29.37\n + exceptiongroup==1.2.2\n + importlib-metadata==6.7.0\n + iniconfig==2.0.0\n + numpy==1.17.5\n + packaging==24.0\n + pluggy==1.2.0\n + pyqt5==5.15.10\n + pyqt5-qt5==5.15.16\n + pyqt5-sip==12.13.0\n + pyqtwebengine==5.15.6\n + pyqtwebengine-qt5==5.15.16\n + pytest==7.4.4\n + setuptools==59.8.0\n + tomli==2.0.1\n + typing-extensions==4.7.1\n + wheel==0.42.0\n + zipp==3.15.0\n  × No solution found when resolving dependencies:\n  ╰─▶ Because the current Python version (3.7.9) does not satisfy Python>=3.8 and all of:\n          scipy>=1.9.0,<=1.9.1\n          scipy>=1.10.0,<=1.10.1\n      depend on Python>=3.8,<3.12, we can conclude that all of:\n          scipy>=1.9.0,<=1.9.1\n          scipy>=1.10.0,<=1.10.1\n       cannot be used.\n      And because only the following versions of scipy are available:\n          scipy<=1.9.0\n          scipy==1.9.1\n          scipy==1.9.2\n          scipy==1.9.3\n          scipy==1.10.0\n          scipy==1.10.1\n          scipy==1.11.0\n          scipy==1.11.1\n          scipy==1.11.2\n          scipy==1.11.3\n          scipy==1.11.4\n          scipy==1.12.0\n          scipy==1.13.0\n          scipy==1.13.1\n          scipy==1.14.0\n          scipy==1.14.1\n          scipy==1.15.0\n      we can conclude that all of:\n          scipy>=1.9.0,<1.9.2\n          scipy>1.9.3,<1.11.0\n       cannot be used. (1)\n\n      Because the current Python version (3.7.9) does not satisfy Python>=3.8 and scipy>=1.9.2,<=1.9.3 depends on Python>=3.8,\n      we can conclude that scipy>=1.9.2,<=1.9.3 cannot be used.\n      And because we know from (1) that all of:\n          scipy>=1.9.0,<1.9.2\n          scipy>1.9.3,<1.11.0\n       cannot be used, we can conclude that scipy>=1.9.0,<1.11.0 cannot be used.\n      And because scipy==1.11.0 was yanked (reason: License Violation), we can conclude that scipy>=1.9.0,<1.11.1 cannot be\n      used. (2)\n\n      Because the current Python version (3.7.9) does not satisfy Python>=3.8 and scipy>=1.11.1,<=1.11.3 depends on\n      Python>=3.9,<3.13, we can conclude that scipy>=1.11.1,<=1.11.3 cannot be used.\n      And because we know from (2) that scipy>=1.9.0,<1.11.1 cannot be used, we can conclude that scipy>=1.9.0,<1.11.4 cannot\n      be used. (3)\n\n      Because the current Python version (3.7.9) does not satisfy Python>=3.8 and scipy>=1.11.4,<=1.13.1 depends on\n      Python>=3.9, we can conclude that scipy>=1.11.4,<=1.13.1 cannot be used.\n      And because we know from (3) that scipy>=1.9.0,<1.11.4 cannot be used, we can conclude that scipy>=1.9.0,<1.14.0 cannot\n      be used. (4)\n\n      Because the current Python version (3.7.9) does not satisfy Python>=3.8 and scipy>=1.14.0 depends on Python>=3.10, we can\n      conclude that scipy>=1.14.0 cannot be used.\n      And because we know from (4) that scipy>=1.9.0,<1.14.0 cannot be used, we can conclude that scipy>=1.9.0 cannot be used.\n      And because you require scipy>=1.9, we can conclude that your requirements are unsatisfiable.\n\n      hint: Pre-releases are available for `scipy` in the requested range (e.g., 1.15.0rc2), but pre-releases weren't enabled\n      (try: `--prerelease=allow`)\n  × No solution found when resolving dependencies:\n  ╰─▶ Because the current Python version (3.7.9) does not satisfy Python>=3.8 and pyqtgraph>=0.13.1,<=0.13.3 depends on\n      Python>=3.8, we can conclude that pyqtgraph>=0.13.1,<=0.13.3 cannot be used.\n      And because only the following versions of pyqtgraph are available:\n          pyqtgraph<=0.13.1\n          pyqtgraph==0.13.2\n          pyqtgraph==0.13.3\n          pyqtgraph==0.13.4\n          pyqtgraph==0.13.5\n          pyqtgraph==0.13.6\n          pyqtgraph==0.13.7\n      we can conclude that pyqtgraph>=0.13.1,<0.13.4 cannot be used. (1)\n\n      Because the current Python version (3.7.9) does not satisfy Python>=3.9 and pyqtgraph>=0.13.4 depends on Python>=3.9, we\n      can conclude that pyqtgraph>=0.13.4 cannot be used.\n      And because we know from (1) that pyqtgraph>=0.13.1,<0.13.4 cannot be used, we can conclude that pyqtgraph>=0.13.1 cannot\n      be used.\n      And because you require pyqtgraph>=0.13.1, we can conclude that your requirements are unsatisfiable.\nResolved 2 packages in 3ms\nInstalled 2 packages in 27ms\n + psycopg2==2.9.9\n + pymssql==2.3.2\nResolved 19 packages in 106ms\nInstalled 16 packages in 1.99s\n + catboost==1.2.7\n + cycler==0.11.0\n + fonttools==4.38.0\n + graphviz==0.20.1\n + kiwisolver==1.4.5\n + matplotlib==3.5.3\n + pandas==1.3.5\n + pillow==9.5.0\n + plotly==5.18.0\n + pyparsing==3.1.4\n + python-dateutil==2.9.0.post0\n + pytz==2024.2\n + scipy==1.7.3\n + six==1.17.0\n + tenacity==8.2.3\n + xgboost==1.6.2\nResolved 5 packages in 13ms\nInstalled 3 packages in 125ms\n + joblib==1.3.2\n + scikit-learn==1.0.2\n + threadpoolctl==3.1.0\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/classification/_tree_scorers.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_2find_threshold_entropy’:\nOrange/classification/_tree_scorers.c:3427:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 3427 |   __pyx_t_7 = ((__pyx_v_N <= __pyx_v_min_leaf) != 0);\n      |                           ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_6find_threshold_MSE’:\nOrange/classification/_tree_scorers.c:4883:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 4883 |   __pyx_t_1 = ((__pyx_v_N <= __pyx_v_min_leaf) != 0);\n      |                           ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_8find_binarization_MSE’:\nOrange/classification/_tree_scorers.c:5629:43: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5629 |           for (__pyx_t_19 = 0; __pyx_t_19 < __pyx_t_18; __pyx_t_19+=1) {\n      |                                           ^\nOrange/classification/_tree_scorers.c:5750:39: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5750 |           __pyx_t_20 = ((__pyx_v_left >= __pyx_v_min_leaf) != 0);\n      |                                       ^~\nOrange/classification/_tree_scorers.c:5756:53: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5756 |           __pyx_t_20 = (((__pyx_v_N - __pyx_v_left) >= __pyx_v_min_leaf) != 0);\n      |                                                     ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_14compute_predictions_csr’:\nOrange/classification/_tree_scorers.c:7217:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7217 |         for (__pyx_t_12 = 0; __pyx_t_12 < __pyx_t_11; __pyx_t_12+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_16compute_predictions_csc’:\nOrange/classification/_tree_scorers.c:7874:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7874 |         for (__pyx_t_12 = 0; __pyx_t_12 < __pyx_t_11; __pyx_t_12+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c:7934:150: warning: comparison of integer expressions of different signedness: ‘__pyx_t_5numpy_int32_t’ {aka ‘int’} and ‘unsigned int’ [-Wsign-compare]\n 7934 |               __pyx_t_16 = (((*((__pyx_t_5numpy_int32_t const  *) ( /* dim=0 */ (__pyx_v_indices.data + __pyx_t_15 * __pyx_v_indices.strides[0]) ))) != __pyx_v_i) != 0);\n      |                                                                                                                                                      ^~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/data/_contingency.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/data/_io.c: In function ‘__pyx_pf_6Orange_4data_3_io_sparse_read_float.constprop’:\nOrange/data/_io.c:4120:43: warning: ‘__pyx_v_decs’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4120 |           __pyx_v_value = ((__pyx_v_value * __pyx_v_decs) + (__pyx_v_c & 0xf));\n      |                            ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/data/_io.c:4318:24: warning: ‘__pyx_v_value’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4318 |           __pyx_t_10 = PyFloat_FromDouble(__pyx_v_value); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 223, __pyx_L5_error)\n      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:683:40: warning: ‘__pyx_v_attr_index’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n  683 |   #define PyInt_FromLong               PyLong_FromLong\n      |                                        ^~~~~~~~~~~~~~~\nOrange/data/_io.c:1590:7: note: ‘__pyx_v_attr_index’ was declared here\n 1590 |   int __pyx_v_attr_index;\n      |       ^~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:3183:25: warning: ‘__pyx_v_atomp’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3183 |           __pyx_v_atomp = (__pyx_v_atomp + 1);\n      |           ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/data/_valuecount.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/distance/_distance.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/preprocess/_discretize.c:774:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/preprocess/_relieff.cpp:790:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1830,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,\n                 from Orange/projection/_som.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_5update_hex’:\nOrange/projection/_som.c:3863:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3863 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:3862:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3862 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pf_6Orange_10projection_4_som_8update_sparse.constprop’:\nOrange/projection/_som.c:4934:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4934 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:4933:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4933 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_7get_winners_sparse’:\nOrange/projection/_som.c:4732:223: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4732 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_26, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_27, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_y;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:4307:7: note: ‘__pyx_v_win_y’ was declared here\n 4307 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:4721:223: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4721 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_27, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_26, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_x;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:4306:7: note: ‘__pyx_v_win_x’ was declared here\n 4306 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pf_6Orange_10projection_4_som_10update_sparse_hex.constprop’:\nOrange/projection/_som.c:5682:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 5682 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:5681:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 5681 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_1get_winners’:\nOrange/projection/_som.c:3184:223: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3184 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_22, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_23, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_y;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:2887:7: note: ‘__pyx_v_win_y’ was declared here\n 2887 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:3173:223: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3173 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_23, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_22, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_x;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:2886:7: note: ‘__pyx_v_win_x’ was declared here\n 2886 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_3update’:\nOrange/projection/_som.c:3357:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3357 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/classification/_simple_tree.c: In function ‘gain_ratio_c’:\nOrange/classification/_simple_tree.c:63:9: warning: implicit declaration of function ‘qsort_r’; did you mean ‘qsort’? [-Wimplicit-function-declaration]\n   63 |         qsort_r(base, nel, size, compar, thunk)\n      |         ^~~~~~~\nOrange/classification/_simple_tree.c:147:9: note: in expansion of macro ‘QSORT_R_FUNC’\n  147 |         QSORT_R_FUNC(examples, size, sizeof(struct Example), (void*) &compar_attr, compar_examples);\n      |         ^~~~~~~~~~~~\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/setuptools/command/easy_install.py:159: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.\n  EasyInstallDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/setuptools/command/install.py:37: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n  setuptools.SetuptoolsDeprecationWarning,\nwarning: no files found matching 'README*' under directory 'Orange'\nwarning: no files found matching 'LICENSE' under directory 'Orange'\nwarning: no files found matching '*.basket' under directory 'Orange/datasets'\nwarning: no files found matching '*.svg' under directory 'Orange/canvas'\nwarning: no files found matching '*.js' under directory 'Orange/widgets'\nwarning: no files found matching '*.css' under directory 'Orange/widgets'\nwarning: no files found matching '*.html' under directory 'Orange/widgets'\nwarning: no files found matching '*.svg' under directory 'distribute'\nwarning: no files found matching 'COPYING'\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/pkg_resources/__init__.py:119: PkgResourcesDeprecationWarning:  is an invalid version and will not be supported in a future release\n  PkgResourcesDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/setuptools/command/install.py:37: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n  setuptools.SetuptoolsDeprecationWarning,\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.7/site-packages/pkg_resources/__init__.py:119: PkgResourcesDeprecationWarning:  is an invalid version and will not be supported in a future release\n  PkgResourcesDeprecationWarning,\nerror: Couldn't find a setup script in /tmp/easy_install-cvivb7y4/scipy-1.15.0.tar.gz\nUsing CPython 3.8.20\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 15 packages in 126ms\nPrepared 15 packages in 1ms\nInstalled 15 packages in 35ms\n + cython==0.29.37\n + exceptiongroup==1.2.2\n + iniconfig==2.0.0\n + numpy==1.24.4\n + packaging==24.2\n + pluggy==1.5.0\n + pyqt5==5.15.11\n + pyqt5-qt5==5.15.16\n + pyqt5-sip==12.15.0\n + pyqtwebengine==5.15.7\n + pyqtwebengine-qt5==5.15.16\n + pytest==8.3.4\n + setuptools==75.3.0\n + tomli==2.2.1\n + wheel==0.45.1\nResolved 59 packages in 98ms\nInstalled 55 packages in 86ms\n + anyio==4.5.2\n + backports-tarfile==1.2.0\n + baycomp==1.0.3\n + bottleneck==1.4.0\n + certifi==2024.12.14\n + cffi==1.17.1\n + chardet==5.2.0\n + charset-normalizer==3.4.1\n + contourpy==1.1.1\n + cryptography==44.0.0\n + cycler==0.12.1\n + et-xmlfile==2.0.0\n + fonttools==4.55.3\n + h11==0.14.0\n + httpcore==1.0.7\n + httpx==0.28.1\n + idna==3.10\n + importlib-metadata==8.5.0\n + importlib-resources==6.4.5\n + jaraco-classes==3.4.0\n + jaraco-context==6.0.1\n + jaraco-functools==4.1.0\n + jeepney==0.8.0\n + joblib==1.4.2\n + keyring==25.5.0\n + keyrings-alt==5.0.2\n + kiwisolver==1.4.7\n + matplotlib==3.7.5\n + more-itertools==10.5.0\n + networkx==3.1\n + openpyxl==3.1.5\n + opentsne==1.0.1\n + pandas==2.0.3\n + pillow==10.4.0\n + pip==24.3.1\n + pycparser==2.22\n + pyparsing==3.1.4\n + python-dateutil==2.9.0.post0\n + python-louvain==0.16\n + pytz==2024.2\n + pyyaml==6.0.2\n + requests==2.32.3\n + scikit-learn==1.1.3\n + scipy==1.10.1\n + secretstorage==3.3.3\n + serverfiles==0.3.1\n + six==1.17.0\n + sniffio==1.3.1\n + threadpoolctl==3.5.0\n + typing-extensions==4.12.2\n + tzdata==2024.2\n + urllib3==2.2.3\n + xlrd==2.0.1\n + xlsxwriter==3.2.0\n + zipp==3.20.2\nResolved 64 packages in 53ms\nInstalled 41 packages in 85ms\n + anyqt==0.2.0\n + asttokens==3.0.0\n + attrs==24.3.0\n + backcall==0.2.0\n + cattrs==24.1.2\n + comm==0.2.2\n + commonmark==0.9.1\n + debugpy==1.8.11\n + decorator==5.1.1\n + dictdiffer==0.9.0\n + docutils==0.20.1\n + executing==2.1.0\n + ipykernel==6.29.5\n + ipython==8.12.3\n + jedi==0.19.2\n + jupyter-client==8.6.3\n + jupyter-core==5.7.2\n + matplotlib-inline==0.1.7\n + nest-asyncio==1.6.0\n + orange-canvas-core==0.1.35\n + orange-widget-base==4.22.0\n + parso==0.8.4\n + pexpect==4.9.0\n + pickleshare==0.7.5\n + platformdirs==4.3.6\n + prompt-toolkit==3.0.48\n + psutil==6.1.1\n + ptyprocess==0.7.0\n + pure-eval==0.2.3\n + pygments==2.19.1\n + pyqtgraph==0.13.3\n + pyzmq==26.2.0\n + qasync==0.27.1\n + qtconsole==5.6.1\n + qtpy==2.4.2\n + requests-cache==1.2.1\n + stack-data==0.6.3\n + tornado==6.4.2\n + traitlets==5.14.3\n + url-normalize==1.4.3\n + wcwidth==0.2.13\nResolved 2 packages in 7ms\nInstalled 2 packages in 12ms\n + psycopg2==2.9.10\n + pymssql==2.3.2\nResolved 23 packages in 15ms\nInstalled 6 packages in 372ms\n + catboost==1.2.7\n + graphviz==0.20.3\n + nvidia-nccl-cu12==2.24.3\n + plotly==5.24.1\n + tenacity==9.0.0\n + xgboost==2.1.3\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h:1940,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h:5,\n                 from Orange/classification/_tree_scorers.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_2find_threshold_entropy’:\nOrange/classification/_tree_scorers.c:3427:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 3427 |   __pyx_t_7 = ((__pyx_v_N <= __pyx_v_min_leaf) != 0);\n      |                           ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_6find_threshold_MSE’:\nOrange/classification/_tree_scorers.c:4883:27: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 4883 |   __pyx_t_1 = ((__pyx_v_N <= __pyx_v_min_leaf) != 0);\n      |                           ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_8find_binarization_MSE’:\nOrange/classification/_tree_scorers.c:5629:43: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5629 |           for (__pyx_t_19 = 0; __pyx_t_19 < __pyx_t_18; __pyx_t_19+=1) {\n      |                                           ^\nOrange/classification/_tree_scorers.c:5750:39: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5750 |           __pyx_t_20 = ((__pyx_v_left >= __pyx_v_min_leaf) != 0);\n      |                                       ^~\nOrange/classification/_tree_scorers.c:5756:53: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 5756 |           __pyx_t_20 = (((__pyx_v_N - __pyx_v_left) >= __pyx_v_min_leaf) != 0);\n      |                                                     ^~\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_14compute_predictions_csr’:\nOrange/classification/_tree_scorers.c:7217:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7217 |         for (__pyx_t_12 = 0; __pyx_t_12 < __pyx_t_11; __pyx_t_12+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c: In function ‘__pyx_pf_6Orange_14classification_13_tree_scorers_16compute_predictions_csc’:\nOrange/classification/_tree_scorers.c:7874:41: warning: comparison of integer expressions of different signedness: ‘unsigned int’ and ‘int’ [-Wsign-compare]\n 7874 |         for (__pyx_t_12 = 0; __pyx_t_12 < __pyx_t_11; __pyx_t_12+=1) {\n      |                                         ^\nOrange/classification/_tree_scorers.c:7934:150: warning: comparison of integer expressions of different signedness: ‘__pyx_t_5numpy_int32_t’ {aka ‘int’} and ‘unsigned int’ [-Wsign-compare]\n 7934 |               __pyx_t_16 = (((*((__pyx_t_5numpy_int32_t const  *) ( /* dim=0 */ (__pyx_v_indices.data + __pyx_t_15 * __pyx_v_indices.strides[0]) ))) != __pyx_v_i) != 0);\n      |                                                                                                                                                      ^~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h:1940,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h:5,\n                 from Orange/data/_contingency.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/data/_io.c: In function ‘__pyx_pf_6Orange_4data_3_io_sparse_read_float.constprop’:\nOrange/data/_io.c:4120:43: warning: ‘__pyx_v_decs’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4120 |           __pyx_v_value = ((__pyx_v_value * __pyx_v_decs) + (__pyx_v_c & 0xf));\n      |                            ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/data/_io.c:4318:24: warning: ‘__pyx_v_value’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4318 |           __pyx_t_10 = PyFloat_FromDouble(__pyx_v_value); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 223, __pyx_L5_error)\n      |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:683:40: warning: ‘__pyx_v_attr_index’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n  683 |   #define PyInt_FromLong               PyLong_FromLong\n      |                                        ^~~~~~~~~~~~~~~\nOrange/data/_io.c:1590:7: note: ‘__pyx_v_attr_index’ was declared here\n 1590 |   int __pyx_v_attr_index;\n      |       ^~~~~~~~~~~~~~~~~~\nOrange/data/_io.c:3183:25: warning: ‘__pyx_v_atomp’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3183 |           __pyx_v_atomp = (__pyx_v_atomp + 1);\n      |           ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h:1940,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h:5,\n                 from Orange/data/_valuecount.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h:1940,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h:5,\n                 from Orange/distance/_distance.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h:1940,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h:5,\n                 from Orange/preprocess/_discretize.c:774:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h:1940,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h:5,\n                 from Orange/preprocess/_relieff.cpp:790:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nIn file included from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarraytypes.h:1940,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/ndarrayobject.h:12,\n                 from /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/arrayobject.h:5,\n                 from Orange/projection/_som.c:775:\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning \"Using deprecated NumPy API, disable it with \" \"#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-Wcpp]\n   17 | #warning \"Using deprecated NumPy API, disable it with \" \\\n      |  ^~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_5update_hex’:\nOrange/projection/_som.c:3863:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3863 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:3862:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3862 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pf_6Orange_10projection_4_som_8update_sparse.constprop’:\nOrange/projection/_som.c:4934:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4934 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:4933:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4933 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pf_6Orange_10projection_4_som_10update_sparse_hex.constprop’:\nOrange/projection/_som.c:5682:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 5682 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:5681:7: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 5681 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_1get_winners’:\nOrange/projection/_som.c:3184:223: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3184 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_22, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_23, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_y;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:2887:7: note: ‘__pyx_v_win_y’ was declared here\n 2887 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:3173:223: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3173 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_23, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_22, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_x;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:2886:7: note: ‘__pyx_v_win_x’ was declared here\n 2886 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_3update’:\nOrange/projection/_som.c:3357:7: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 3357 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c: In function ‘__pyx_pw_6Orange_10projection_4_som_7get_winners_sparse’:\nOrange/projection/_som.c:4732:223: warning: ‘__pyx_v_win_y’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4732 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_26, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_27, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_y;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:4307:7: note: ‘__pyx_v_win_y’ was declared here\n 4307 |   int __pyx_v_win_y;\n      |       ^~~~~~~~~~~~~\nOrange/projection/_som.c:4721:223: warning: ‘__pyx_v_win_x’ may be used uninitialized in this function [-Wmaybe-uninitialized]\n 4721 |           *__Pyx_BufPtrStrided2d(__pyx_t_5numpy_int16_t *, __pyx_pybuffernd_winners.rcbuffer->pybuffer.buf, __pyx_t_27, __pyx_pybuffernd_winners.diminfo[0].strides, __pyx_t_26, __pyx_pybuffernd_winners.diminfo[1].strides) = __pyx_v_win_x;\n      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~\nOrange/projection/_som.c:4306:7: note: ‘__pyx_v_win_x’ was declared here\n 4306 |   int __pyx_v_win_x;\n      |       ^~~~~~~~~~~~~\nOrange/classification/_simple_tree.c: In function ‘gain_ratio_c’:\nOrange/classification/_simple_tree.c:63:9: warning: implicit declaration of function ‘qsort_r’; did you mean ‘qsort’? [-Wimplicit-function-declaration]\n   63 |         qsort_r(base, nel, size, compar, thunk)\n      |         ^~~~~~~\nOrange/classification/_simple_tree.c:147:9: note: in expansion of macro ‘QSORT_R_FUNC’\n  147 |         QSORT_R_FUNC(examples, size, sizeof(struct Example), (void*) &compar_attr, compar_examples);\n      |         ^~~~~~~~~~~~\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/setuptools/_distutils/dist.py:261: UserWarning: Unknown distribution option: 'test_suite'\n  warnings.warn(msg)\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/setuptools/_distutils/dist.py:261: UserWarning: Unknown distribution option: 'test_suite'\n  warnings.warn(msg)\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/setuptools/command/develop.py:41: EasyInstallDeprecationWarning: easy_install command is deprecated.\n!!\n\n        ********************************************************************************\n        Please avoid running ``setup.py`` and ``easy_install``.\n        Instead, use pypa/build, pypa/installer or other\n        standards-based tools.\n\n        See https://github.com/pypa/setuptools/issues/917 for details.\n        ********************************************************************************\n\n!!\n  easy_install.initialize_options(self)\n/home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5/.venv/lib/python3.8/site-packages/setuptools/_distutils/cmd.py:66: SetuptoolsDeprecationWarning: setup.py install is deprecated.\n!!\n\n        ********************************************************************************\n        Please avoid running ``setup.py`` directly.\n        Instead, use pypa/build, pypa/installer or other\n        standards-based tools.\n\n        See https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html for details.\n        ********************************************************************************\n\n!!\n  self.initialize_options()\nwarning: no files found matching 'README*' under directory 'Orange'\nwarning: no files found matching 'LICENSE' under directory 'Orange'\nwarning: no files found matching '*.basket' under directory 'Orange/datasets'\nwarning: no files found matching '*.svg' under directory 'Orange/canvas'\nwarning: no files found matching '*.js' under directory 'Orange/widgets'\nwarning: no files found matching '*.css' under directory 'Orange/widgets'\nwarning: no files found matching '*.html' under directory 'Orange/widgets'\nwarning: no files found matching '*.svg' under directory 'distribute'\nwarning: no files found matching 'COPYING'\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.8.20, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5\nconfigfile: pyproject.toml\nplugins: anyio-4.5.2, typeguard-4.3.0\ncollected 90 items\n\nr2e_tests/test_1.py .................................................... [ 57%]\n.....................................x                                   [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestUtil::test_FDR\nPASSED r2e_tests/test_1.py::TestUtil::test_FDR_dependent\nPASSED r2e_tests/test_1.py::TestUtil::test_FDR_list\nPASSED r2e_tests/test_1.py::TestUtil::test_FDR_m\nPASSED r2e_tests/test_1.py::TestUtil::test_FDR_no_values\nPASSED r2e_tests/test_1.py::TestUtil::test_contingency\nPASSED r2e_tests/test_1.py::TestUtil::test_mean\nPASSED r2e_tests/test_1.py::TestUtil::test_nanmedian\nPASSED r2e_tests/test_1.py::TestUtil::test_nanmedian_more_nonzeros\nPASSED r2e_tests/test_1.py::TestUtil::test_nanmin_nanmax\nPASSED r2e_tests/test_1.py::TestUtil::test_nanmode\nPASSED r2e_tests/test_1.py::TestUtil::test_nanstd\nPASSED r2e_tests/test_1.py::TestUtil::test_nanstd_with_ddof\nPASSED r2e_tests/test_1.py::TestUtil::test_nansum\nPASSED r2e_tests/test_1.py::TestUtil::test_nanvar\nPASSED r2e_tests/test_1.py::TestUtil::test_nanvar_with_ddof\nPASSED r2e_tests/test_1.py::TestUtil::test_stats\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_empty\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_long_string_mem_use\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_nancounts\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_nans_neutral_weights\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_nans_neutral_weights_sparse\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_non_numeric\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_sparse\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_weights\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_weights_sparse\nPASSED r2e_tests/test_1.py::TestUtil::test_std\nPASSED r2e_tests/test_1.py::TestUtil::test_std_with_ddof\nPASSED r2e_tests/test_1.py::TestUtil::test_var\nPASSED r2e_tests/test_1.py::TestUtil::test_var_with_ddof\nPASSED r2e_tests/test_1.py::TestUtil::test_weighted_contingency\nPASSED r2e_tests/test_1.py::TestNanmean::test_axis_0\nPASSED r2e_tests/test_1.py::TestNanmean::test_axis_1\nPASSED r2e_tests/test_1.py::TestNanmean::test_axis_none\nPASSED r2e_tests/test_1.py::TestNanmean::test_weights_axis_0\nPASSED r2e_tests/test_1.py::TestNanmean::test_weights_axis_1\nPASSED r2e_tests/test_1.py::TestNanmean::test_weights_axis_none\nPASSED r2e_tests/test_1.py::TestNanMeanVar::test_axis_0\nPASSED r2e_tests/test_1.py::TestNanMeanVar::test_axis_1\nPASSED r2e_tests/test_1.py::TestNanMeanVar::test_axis_none\nPASSED r2e_tests/test_1.py::TestDigitize::test_digitize\nPASSED r2e_tests/test_1.py::TestDigitize::test_digitize_1d_array\nPASSED r2e_tests/test_1.py::TestDigitize::test_digitize_right\nPASSED r2e_tests/test_1.py::TestDigitize::test_digitize_sparse_zeroth_bin\nPASSED r2e_tests/test_1.py::TestCountnans::test_1d_array\nPASSED r2e_tests/test_1.py::TestCountnans::test_1d_array_with_axis_0\nPASSED r2e_tests/test_1.py::TestCountnans::test_1d_array_with_axis_1_raises_exception\nPASSED r2e_tests/test_1.py::TestCountnans::test_1d_weights_with_axis_0\nPASSED r2e_tests/test_1.py::TestCountnans::test_1d_weights_with_axis_1\nPASSED r2e_tests/test_1.py::TestCountnans::test_2d_matrix\nPASSED r2e_tests/test_1.py::TestCountnans::test_2d_weights\nPASSED r2e_tests/test_1.py::TestCountnans::test_dtype\nPASSED r2e_tests/test_1.py::TestCountnans::test_on_columns\nPASSED r2e_tests/test_1.py::TestCountnans::test_on_rows\nPASSED r2e_tests/test_1.py::TestCountnans::test_shape_matches_dense_and_sparse\nPASSED r2e_tests/test_1.py::TestCountnans::test_shape_matches_dense_and_sparse_with_axis_0\nPASSED r2e_tests/test_1.py::TestCountnans::test_shape_matches_dense_and_sparse_with_axis_1\nPASSED r2e_tests/test_1.py::TestBincount::test_adds_empty_bins\nPASSED r2e_tests/test_1.py::TestBincount::test_all_nans\nPASSED r2e_tests/test_1.py::TestBincount::test_all_zeros_or_nans\nPASSED r2e_tests/test_1.py::TestBincount::test_count_nans\nPASSED r2e_tests/test_1.py::TestBincount::test_count_nans_objectarray\nPASSED r2e_tests/test_1.py::TestBincount::test_maxval_adds_empty_bins\nPASSED r2e_tests/test_1.py::TestBincount::test_maxval_doesnt_truncate_values_when_too_small\nPASSED r2e_tests/test_1.py::TestBincount::test_minlength_adds_empty_bins\nPASSED r2e_tests/test_1.py::TestBincount::test_weights\nPASSED r2e_tests/test_1.py::TestBincount::test_weights_with_nans\nPASSED r2e_tests/test_1.py::TestBincount::test_weights_with_transposed_x\nPASSED r2e_tests/test_1.py::TestUnique::test_nanunique_ignores_nans_in_counts\nPASSED r2e_tests/test_1.py::TestUnique::test_nanunique_ignores_nans_in_values\nPASSED r2e_tests/test_1.py::TestUnique::test_returns_counts\nPASSED r2e_tests/test_1.py::TestUnique::test_returns_unique_values\nPASSED r2e_tests/test_1.py::TestUnique::test_sparse_explicit_zeros\nPASSED r2e_tests/test_1.py::TestNanToNum::test_converts_invalid_values\nPASSED r2e_tests/test_1.py::TestNanToNum::test_preserves_valid_values\nPASSED r2e_tests/test_1.py::TestIsnan::test_functionality\nPASSED r2e_tests/test_1.py::TestIsnan::test_out\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_0_with_nans\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_0_without_nans\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_1_with_nans\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_1_without_nans\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_none_with_nans\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_none_without_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_0_with_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_0_without_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_1_with_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_1_without_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_none_with_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_none_without_nans\nXFAIL r2e_tests/test_1.py::TestNanModeFixedInScipy::test_scipy_nanmode_still_wrong - reason: \n======================== 89 passed, 1 xfailed in 2.22s =========================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.8.20, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/orange3_39cdce60dc81c3b8524e578c34d17eab61d02fe5\nconfigfile: pyproject.toml\nplugins: anyio-4.5.2, typeguard-4.3.0\ncollected 90 items\n\nr2e_tests/test_1.py ...................F...F.F.......................... [ 57%]\n.....................................x                                   [100%]\n\n=================================== FAILURES ===================================\n________________________ TestUtil.test_stats_nancounts _________________________\n\nself = <r2e_tests.test_1.TestUtil testMethod=test_stats_nancounts>\n\n    def test_stats_nancounts(self):\n        arr = np.array([[1, 4, 9],\n                        [-2, 10, 0],\n                        [0, np.nan, np.nan],\n                        [0, np.nan, 0]])\n    \n        expected = [[-2, 1, -0.25, (1.25 ** 2 + 1.75 ** 2 + .25 ** 2 + .25 ** 2) / 4, 0, 4],\n                    [4, 10, 7, 3 ** 2, 2, 2],\n                    [0, 9, 3, (6 ** 2 + 3 ** 2 + 3 ** 2) / 3, 1, 3]]\n        np.testing.assert_almost_equal(stats(arr, compute_variance=True), expected)\n    \n        sparr = csc_matrix(arr)\n>       np.testing.assert_almost_equal(stats(sparr, compute_variance=True), expected)\n\nr2e_tests/test_1.py:185: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n../../../../.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib/python3.8/contextlib.py:75: in inner\n    return func(*args, **kwds)\n../../../../.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib/python3.8/contextlib.py:75: in inner\n    return func(*args, **kwds)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<function assert_array_almost_equal.<locals>.compare at 0x7cbfcb0e79d0>, array([[-2.    ,  1.    , -0.25  ,  1.1875, ...   ,  3.    , 18.    ,  2.    ,  2.    ]]), [[-2, 1, -0.25, 1.1875, 0, 4], [4, 10, 7, 9, 2, 2], [0, 9, 3, 18.0, 1, 3]])\nkwds = {'err_msg': '', 'header': 'Arrays are not almost equal to 7 decimals', 'precision': 7, 'verbose': True}\n\n    @wraps(func)\n    def inner(*args, **kwds):\n        with self._recreate_cm():\n>           return func(*args, **kwds)\nE           AssertionError: \nE           Arrays are not almost equal to 7 decimals\nE           \nE           Mismatched elements: 6 / 18 (33.3%)\nE           Max absolute difference: 2.\nE           Max relative difference: 1.\nE            x: array([[-2.    ,  1.    , -0.25  ,  1.1875,  2.    ,  2.    ],\nE                  [ 4.    , 10.    ,  7.    ,  9.    ,  0.    ,  4.    ],\nE                  [ 0.    ,  9.    ,  3.    , 18.    ,  2.    ,  2.    ]])\nE            y: array([[-2.    ,  1.    , -0.25  ,  1.1875,  0.    ,  4.    ],\nE                  [ 4.    , 10.    ,  7.    ,  9.    ,  2.    ,  2.    ],\nE                  [ 0.    ,  9.    ,  3.    , 18.    ,  1.    ,  3.    ]])\n\n../../../../.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib/python3.8/contextlib.py:75: AssertionError\n__________________________ TestUtil.test_stats_sparse __________________________\n\nself = <r2e_tests.test_1.TestUtil testMethod=test_stats_sparse>\n\n    def test_stats_sparse(self):\n        X = csr_matrix(np.identity(5))\n>       np.testing.assert_equal(stats(X), [[0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5],\n                                           [0, 1, .2, 0, 0, 5]])\n\nr2e_tests/test_1.py:110: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<built-in function eq>, array([[0. , 1. , 0.2, 0. , 4. , 1. ],\n       [0. , 1. , 0.2, 0. , 4. , 1. ],\n       [0. , 1....1. ]]), [[0, 1, 0.2, 0, 0, 5], [0, 1, 0.2, 0, 0, 5], [0, 1, 0.2, 0, 0, 5], [0, 1, 0.2, 0, 0, 5], [0, 1, 0.2, 0, 0, 5]])\nkwds = {'err_msg': '', 'header': 'Arrays are not equal', 'strict': False, 'verbose': True}\n\n    @wraps(func)\n    def inner(*args, **kwds):\n        with self._recreate_cm():\n>           return func(*args, **kwds)\nE           AssertionError: \nE           Arrays are not equal\nE           \nE           Mismatched elements: 10 / 30 (33.3%)\nE           Max absolute difference: 4.\nE           Max relative difference: 0.8\nE            x: array([[0. , 1. , 0.2, 0. , 4. , 1. ],\nE                  [0. , 1. , 0.2, 0. , 4. , 1. ],\nE                  [0. , 1. , 0.2, 0. , 4. , 1. ],...\nE            y: array([[0. , 1. , 0.2, 0. , 0. , 5. ],\nE                  [0. , 1. , 0.2, 0. , 0. , 5. ],\nE                  [0. , 1. , 0.2, 0. , 0. , 5. ],...\n\n../../../../.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib/python3.8/contextlib.py:75: AssertionError\n______________________ TestUtil.test_stats_weights_sparse ______________________\n\nself = <r2e_tests.test_1.TestUtil testMethod=test_stats_weights_sparse>\n\n    def test_stats_weights_sparse(self):\n        X = np.arange(4).reshape(2, 2).astype(float)\n        X = csr_matrix(X)\n        weights = np.array([1, 3])\n>       np.testing.assert_equal(stats(X, weights), [[0, 2, 1.5, 0, 0, 2],\n                                                    [1, 3, 2.5, 0, 0, 2]])\n\nr2e_tests/test_1.py:155: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nargs = (<built-in function eq>, array([[0. , 2. , 1.5, 0. , 1. , 1. ],\n       [1. , 3. , 2.5, 0. , 0. , 2. ]]), [[0, 2, 1.5, 0, 0, 2], [1, 3, 2.5, 0, 0, 2]])\nkwds = {'err_msg': '', 'header': 'Arrays are not equal', 'strict': False, 'verbose': True}\n\n    @wraps(func)\n    def inner(*args, **kwds):\n        with self._recreate_cm():\n>           return func(*args, **kwds)\nE           AssertionError: \nE           Arrays are not equal\nE           \nE           Mismatched elements: 2 / 12 (16.7%)\nE           Max absolute difference: 1.\nE           Max relative difference: 0.5\nE            x: array([[0. , 2. , 1.5, 0. , 1. , 1. ],\nE                  [1. , 3. , 2.5, 0. , 0. , 2. ]])\nE            y: array([[0. , 2. , 1.5, 0. , 0. , 2. ],\nE                  [1. , 3. , 2.5, 0. , 0. , 2. ]])\n\n../../../../.local/share/uv/python/cpython-3.8.20-linux-x86_64-gnu/lib/python3.8/contextlib.py:75: AssertionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestUtil::test_FDR\nPASSED r2e_tests/test_1.py::TestUtil::test_FDR_dependent\nPASSED r2e_tests/test_1.py::TestUtil::test_FDR_list\nPASSED r2e_tests/test_1.py::TestUtil::test_FDR_m\nPASSED r2e_tests/test_1.py::TestUtil::test_FDR_no_values\nPASSED r2e_tests/test_1.py::TestUtil::test_contingency\nPASSED r2e_tests/test_1.py::TestUtil::test_mean\nPASSED r2e_tests/test_1.py::TestUtil::test_nanmedian\nPASSED r2e_tests/test_1.py::TestUtil::test_nanmedian_more_nonzeros\nPASSED r2e_tests/test_1.py::TestUtil::test_nanmin_nanmax\nPASSED r2e_tests/test_1.py::TestUtil::test_nanmode\nPASSED r2e_tests/test_1.py::TestUtil::test_nanstd\nPASSED r2e_tests/test_1.py::TestUtil::test_nanstd_with_ddof\nPASSED r2e_tests/test_1.py::TestUtil::test_nansum\nPASSED r2e_tests/test_1.py::TestUtil::test_nanvar\nPASSED r2e_tests/test_1.py::TestUtil::test_nanvar_with_ddof\nPASSED r2e_tests/test_1.py::TestUtil::test_stats\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_empty\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_long_string_mem_use\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_nans_neutral_weights\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_nans_neutral_weights_sparse\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_non_numeric\nPASSED r2e_tests/test_1.py::TestUtil::test_stats_weights\nPASSED r2e_tests/test_1.py::TestUtil::test_std\nPASSED r2e_tests/test_1.py::TestUtil::test_std_with_ddof\nPASSED r2e_tests/test_1.py::TestUtil::test_var\nPASSED r2e_tests/test_1.py::TestUtil::test_var_with_ddof\nPASSED r2e_tests/test_1.py::TestUtil::test_weighted_contingency\nPASSED r2e_tests/test_1.py::TestNanmean::test_axis_0\nPASSED r2e_tests/test_1.py::TestNanmean::test_axis_1\nPASSED r2e_tests/test_1.py::TestNanmean::test_axis_none\nPASSED r2e_tests/test_1.py::TestNanmean::test_weights_axis_0\nPASSED r2e_tests/test_1.py::TestNanmean::test_weights_axis_1\nPASSED r2e_tests/test_1.py::TestNanmean::test_weights_axis_none\nPASSED r2e_tests/test_1.py::TestNanMeanVar::test_axis_0\nPASSED r2e_tests/test_1.py::TestNanMeanVar::test_axis_1\nPASSED r2e_tests/test_1.py::TestNanMeanVar::test_axis_none\nPASSED r2e_tests/test_1.py::TestDigitize::test_digitize\nPASSED r2e_tests/test_1.py::TestDigitize::test_digitize_1d_array\nPASSED r2e_tests/test_1.py::TestDigitize::test_digitize_right\nPASSED r2e_tests/test_1.py::TestDigitize::test_digitize_sparse_zeroth_bin\nPASSED r2e_tests/test_1.py::TestCountnans::test_1d_array\nPASSED r2e_tests/test_1.py::TestCountnans::test_1d_array_with_axis_0\nPASSED r2e_tests/test_1.py::TestCountnans::test_1d_array_with_axis_1_raises_exception\nPASSED r2e_tests/test_1.py::TestCountnans::test_1d_weights_with_axis_0\nPASSED r2e_tests/test_1.py::TestCountnans::test_1d_weights_with_axis_1\nPASSED r2e_tests/test_1.py::TestCountnans::test_2d_matrix\nPASSED r2e_tests/test_1.py::TestCountnans::test_2d_weights\nPASSED r2e_tests/test_1.py::TestCountnans::test_dtype\nPASSED r2e_tests/test_1.py::TestCountnans::test_on_columns\nPASSED r2e_tests/test_1.py::TestCountnans::test_on_rows\nPASSED r2e_tests/test_1.py::TestCountnans::test_shape_matches_dense_and_sparse\nPASSED r2e_tests/test_1.py::TestCountnans::test_shape_matches_dense_and_sparse_with_axis_0\nPASSED r2e_tests/test_1.py::TestCountnans::test_shape_matches_dense_and_sparse_with_axis_1\nPASSED r2e_tests/test_1.py::TestBincount::test_adds_empty_bins\nPASSED r2e_tests/test_1.py::TestBincount::test_all_nans\nPASSED r2e_tests/test_1.py::TestBincount::test_all_zeros_or_nans\nPASSED r2e_tests/test_1.py::TestBincount::test_count_nans\nPASSED r2e_tests/test_1.py::TestBincount::test_count_nans_objectarray\nPASSED r2e_tests/test_1.py::TestBincount::test_maxval_adds_empty_bins\nPASSED r2e_tests/test_1.py::TestBincount::test_maxval_doesnt_truncate_values_when_too_small\nPASSED r2e_tests/test_1.py::TestBincount::test_minlength_adds_empty_bins\nPASSED r2e_tests/test_1.py::TestBincount::test_weights\nPASSED r2e_tests/test_1.py::TestBincount::test_weights_with_nans\nPASSED r2e_tests/test_1.py::TestBincount::test_weights_with_transposed_x\nPASSED r2e_tests/test_1.py::TestUnique::test_nanunique_ignores_nans_in_counts\nPASSED r2e_tests/test_1.py::TestUnique::test_nanunique_ignores_nans_in_values\nPASSED r2e_tests/test_1.py::TestUnique::test_returns_counts\nPASSED r2e_tests/test_1.py::TestUnique::test_returns_unique_values\nPASSED r2e_tests/test_1.py::TestUnique::test_sparse_explicit_zeros\nPASSED r2e_tests/test_1.py::TestNanToNum::test_converts_invalid_values\nPASSED r2e_tests/test_1.py::TestNanToNum::test_preserves_valid_values\nPASSED r2e_tests/test_1.py::TestIsnan::test_functionality\nPASSED r2e_tests/test_1.py::TestIsnan::test_out\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_0_with_nans\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_0_without_nans\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_1_with_nans\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_1_without_nans\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_none_with_nans\nPASSED r2e_tests/test_1.py::TestAnyNans::test_axis_none_without_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_0_with_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_0_without_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_1_with_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_1_without_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_none_with_nans\nPASSED r2e_tests/test_1.py::TestAllNans::test_axis_none_without_nans\nXFAIL r2e_tests/test_1.py::TestNanModeFixedInScipy::test_scipy_nanmode_still_wrong - reason: \nFAILED r2e_tests/test_1.py::TestUtil::test_stats_nancounts - AssertionError: \nFAILED r2e_tests/test_1.py::TestUtil::test_stats_sparse - AssertionError: \nFAILED r2e_tests/test_1.py::TestUtil::test_stats_weights_sparse - AssertionEr...\n=================== 3 failed, 86 passed, 1 xfailed in 2.38s ====================\n",
    "old_commit_res_stderr": ""
}
Orange/statistics/util.py Orange/tests/test_statistics.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Statistics Utility Incorrectly Counts Zeros as NaNs, Leading to Inaccurate Calculations

**Description:**
In the statistical utilities, zeros are being mistakenly counted as NaN (Not a Number) values. This miscount affects the accuracy of statistical measures such as mean, variance, and the count of valid entries.

**Example:**
When processing a sparse identity matrix, zeros should be recognized as valid numerical values, not as NaNs.

```python
import numpy as np
from scipy.sparse import csr_matrix
from Orange.statistics.util import stats

X = csr_matrix(np.identity(5))
result = stats(X)
print(result)
```

**Expected Behavior:**
Zeros should be treated as legitimate numerical entries. The NaN count should accurately reflect only the actual NaN values present in the data.

**Actual Behavior:**
Zeros are incorrectly identified as NaNs, resulting in inflated NaN counts and reduced counts of valid numerical entries. This leads to incorrect statistical outcomes.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### Orange/statistics/util.py
"""
This module provides alternatives for the few additional functions found in
and once used from the bottlechest package (fork of bottleneck).

It also patches bottleneck to contain these functions.
"""
import warnings
from typing import Iterable

import bottleneck as bn
import numpy as np
import pandas
import scipy.stats.stats
from scipy import sparse as sp

from sklearn.utils.sparsefuncs import mean_variance_axis


def _eliminate_zeros(x):
    """Eliminate zeros from sparse matrix, or raise appropriate warning."""
    if hasattr(x, "eliminate_zeros"):
        x.eliminate_zeros()
    else:
        warnings.warn(
            f"`{x.__type__}` does not implement `eliminate_zeros`. Some values "
            f"in the sparse matrix may by explicit zeros."
        )


def _count_nans_per_row_sparse(X, weights, dtype=None):
    """ Count the number of nans (undefined) values per row. """
    if weights is not None:
        X = X.tocoo(copy=False)
        nonzero_mask = np.isnan(X.data)
        nan_rows, nan_cols = X.row[nonzero_mask], X.col[nonzero_mask]

        if weights.ndim == 1:
            data_weights = weights[nan_rows]
        else:
            data_weights = weights[nan_rows, nan_cols]

        w = sp.coo_matrix((data_weights, (nan_rows, nan_cols)), shape=X.shape)
        w = w.tocsr()
        return np.asarray(w.sum(axis=1), dtype=dtype).ravel()

    if isinstance(X, (sp.csr_matrix, sp.csc_matrix)):
        X = type(X)((np.isnan(X.data), X.indices, X.indptr), X.shape)
        return np.asarray(X.sum(axis=1), dtype=dtype).ravel()
    else:  # pragma: no cover
        raise TypeError("unsupported type '{}'".format(type(X).__name__))


def sparse_count_implicit_zeros(x):
    """ Count the number of implicit zeros in a sparse matrix. """
    if not sp.issparse(x):
        raise TypeError('The matrix provided was not sparse.')
    return np.prod(x.shape) - x.nnz


def sparse_has_implicit_zeros(x):
    """ Check if sparse matrix contains any implicit zeros. """
    if not sp.issparse(x):
        raise TypeError('The matrix provided was not sparse.')
    return np.prod(x.shape) != x.nnz


def sparse_implicit_zero_weights(x, weights):
    """ Extract the weight values of all zeros in a sparse matrix. """
    if not sp.issparse(x):
        raise TypeError('The matrix provided was not sparse.')

    if weights.ndim == 1:
        # Match weights and x axis so `indices` will be set appropriately
        if x.shape[0] == weights.shape[0]:
            x = x.tocsc()
        elif x.shape[1] == weights.shape[0]:
            x = x.tocsr()
        n_items = np.prod(x.shape)
        zero_indices = np.setdiff1d(np.arange(n_items), x.indices, assume_unique=True)
        return weights[zero_indices]
    else:
        # Can easily be implemented using a coo_matrix
        raise NotImplementedError(
            'Computing zero weights on ndimensinal weight matrix is not implemented'
        )


def bincount(x, weights=None, max_val=None, minlength=0):
    """Return counts of values in array X.

    Works kind of like np.bincount(), except that it also supports
    arrays with nans.

    Parameters
    ----------
    x : array_like, 1 dimension, nonnegative ints
        Input array.
    weights : array_like, optional
        Weights, array of the same shape as x.
    max_val : int, optional
        Indicates the maximum value we expect to find in X and sets the result
        array size accordingly. E.g. if we set `max_val=2` yet the largest
        value in X is 1, the result will contain a bin for the value 2, and
        will be set to 0. See examples for usage.
    minlength : int, optional
        A minimum number of bins for the output array. See numpy docs for info.

    Returns
    -------
    Tuple[np.ndarray, int]
        Returns the bincounts and the number of NaN values.

    Examples
    --------
    In case `max_val` is provided, the return shape includes bins for these
    values as well, even if they do not appear in the data. However, this will
    not truncate the bincount if values larger than `max_count` are found.
    >>> bincount([0, 0, 1, 1, 2], max_val=4)
    (array([ 2.,  2.,  1.,  0.,  0.]), 0.0)
    >>> bincount([0, 1, 2, 3, 4], max_val=2)
    (array([ 1.,  1.,  1.,  1.,  1.]), 0.0)

    """
    # Store the original matrix before any manipulation to check for sparse
    x_original = x
    if sp.issparse(x):
        if weights is not None:
            # Match weights and x axis so `indices` will be set appropriately
            if x.shape[0] == weights.shape[0]:
                x = x.tocsc()
            elif x.shape[1] == weights.shape[0]:
                x = x.tocsr()

            zero_weights = sparse_implicit_zero_weights(x, weights).sum()
            weights = weights[x.indices]
        else:
            zero_weights = sparse_count_implicit_zeros(x)

        x = x.data

    x = np.asanyarray(x, dtype=float)
    if bn.anynan(x):
        nonnan = ~np.isnan(x)
        x = x[nonnan]
        if weights is not None:
            nans = (~nonnan * weights).sum(axis=0)
            weights = weights[nonnan]
        else:
            nans = (~nonnan).sum(axis=0)
    else:
        nans = 0. if x.ndim == 1 else np.zeros(x.shape[1], dtype=float)

    if minlength == 0 and max_val is not None:
        minlength = max_val + 1

    bc = np.bincount(
        x.astype(np.int32, copy=False), weights=weights, minlength=minlength
    ).astype(float)
    # Since `csr_matrix.values` only contain non-zero values or explicit
    # zeros, we must count implicit zeros separately and add them to the
    # explicit ones found before
    if sp.issparse(x_original):
        # If x contains only NaNs, then bc will be an empty array
        if zero_weights and bc.size == 0:
            bc = [zero_weights]
        elif zero_weights:
            bc[0] += zero_weights

    return bc, nans


def countnans(x, weights=None, axis=None, dtype=None, keepdims=False):
    """
    Count the undefined elements in an array along given axis.

    Parameters
    ----------
    x : array_like
    weights : array_like, optional
        Weights to weight the nans with, before or after counting (depending
        on the weights shape).
    axis : int, optional
    dtype : dtype, optional
        The data type of the returned array.

    Returns
    -------
    Union[np.ndarray, float]

    """
    if not sp.issparse(x):
        x = np.asanyarray(x)
        is_nan = np.isnan(x)
        if weights is not None and weights.shape == x.shape:
            is_nan = is_nan * weights

        counts = is_nan.sum(axis=axis, dtype=dtype, keepdims=keepdims)
        if weights is not None and weights.shape != x.shape:
            counts = counts * weights
    else:
        assert axis in [None, 0, 1], 'Only axis 0 and 1 are currently supported'
        # To have consistent behaviour with dense matrices, raise error when
        # `axis=1` and the array is 1d (e.g. [[1 2 3]])
        if x.shape[0] == 1 and axis == 1:
            raise ValueError('Axis %d is out of bounds' % axis)

        arr = x if axis == 1 else x.T

        if weights is not None:
            weights = weights if axis == 1 else weights.T

        arr = arr.tocsr()
        counts = _count_nans_per_row_sparse(arr, weights, dtype=dtype)

        # We want a scalar value if `axis=None` or if the sparse matrix is
        # actually a vector (e.g. [[1 2 3]]), but has `ndim=2` due to scipy
        # implementation
        if axis is None or x.shape[0] == 1:
            counts = counts.sum(dtype=dtype)

    return counts


def contingency(X, y, max_X=None, max_y=None, weights=None, mask=None):
    """
    Compute the contingency matrices for each column of X (excluding the masked)
    versus the vector y.

    If the array is 1-dimensional, a 2d contingency matrix is returned. If the
    array is 2d, the function returns a 3d array, with the first dimension
    corresponding to column index (variable in the input array).

    The column of contingency matrix correspond to values of variables, the
    row correspond to values in vector `y`.

    Rows in the input array can be weighted (argument `weights`). A subset of
    columns can be selected by additional argument `mask`.

    The function also returns a count of NaN values per each value of `y`.

    Parameters
    ----------
    X : array_like
        With values in columns.
    y : 1d array
        Vector of true values.
    max_X : int
        The maximal value in the array
    max_y : int
        The maximal value in `y`
    weights : array_like
        Row weights. When not None, contingencies contain weighted counts
    mask : sequence
        Discrete columns of X.

    Returns
    -------
    contingencies: (m × ny × nx) array
        m number of masked (used) columns (all if mask=None), i.e.
        for each column of X;
        ny number of uniques in y,
        nx number of uniques in column of X.
    nans_cols : array_like
        Number of nans in each column of X for each unique value of y.
    nans_rows : array_like
        Number of nans in y for each unique value in columns of X.
    nans : array_like
        Number of nans in column of X and y at the same time.
    """
    was_1d = False
    if X.ndim == 1:
        X = X[..., np.newaxis]
        was_1d = True

    contingencies, nans_cols, nans_rows, nans = [], [], [], []
    ny = np.unique(y).size if max_y is None else max_y + 1
    for i in range(X.shape[1]):
        if mask is not None and not mask[i]:
            contingencies.append(np.zeros((ny, max_X + 1)))
            nans_cols.append(np.zeros(ny))
            nans_rows.append(None)
            nans.append(0)
            continue
        col = X[..., i]
        nx = np.unique(col[~np.isnan(col)]).size if max_X is None else max_X + 1
        if sp.issparse(col):
            col = np.ravel(col.todense())
        contingencies.append(
            bincount(y + ny * col,
                     minlength=ny * nx,
                     weights=weights)[0].reshape(nx, ny).T)

        nan_col_mask = np.isnan(col)
        nan_row_mask = np.isnan(y)
        nan_mask = nan_col_mask & nan_row_mask
        weights_ = np.ones(len(y)) if weights is None else weights

        nans_cols.append(
            bincount(y[nan_col_mask], weights=weights_[nan_col_mask],
                     minlength=ny)[0])
        nans_rows.append(
            bincount(col[nan_row_mask], weights=weights_[nan_row_mask],
                     minlength=nx)[0])
        nans.append(np.sum(nan_mask * weights_))
    if was_1d:
        return contingencies[0], nans_cols[0], nans_rows[0], nans[0]
    return np.array(contingencies), np.array(nans_cols), nans_rows, nans


def stats(X, weights=None, compute_variance=False):
    """
    Compute min, max, #nans, mean and variance.

    Result is a tuple (min, max, mean, variance, #nans, #non-nans) or an
    array of shape (len(X), 6).

    The mean and the number of nans and non-nans are weighted.

    Computation of variance requires an additional pass and is not enabled
    by default. Zeros are filled in instead of variance.

    Parameters
    ----------
    X : array_like, 1 or 2 dimensions
        Input array.
    weights : array_like, optional
        Weights, array of the same length as `x`.
    compute_variance : bool, optional
        If set to True, the function also computes variance.

    Returns
    -------
    out : a 6-element tuple or an array of shape (len(x), 6)
        Computed (min, max, mean, variance or 0, #nans, #non-nans)

    Raises
    ------
    ValueError
        If the length of the weight vector does not match the length of the
        array
    """
    is_numeric = np.issubdtype(X.dtype, np.number)
    is_sparse = sp.issparse(X)

    if X.size and is_numeric:
        if is_sparse:
            X = X.tocsc()
        if compute_variance:
            means, vars = nan_mean_var(X, axis=0, weights=weights)
        else:
            means = nanmean(X, axis=0, weights=weights)
            vars = np.zeros(X.shape[1] if X.ndim == 2 else 1)

    if X.size and is_numeric and not is_sparse:
        nans = np.isnan(X).sum(axis=0)
        return np.column_stack((
            np.nanmin(X, axis=0),
            np.nanmax(X, axis=0),
            means,
            vars,
            nans,
            X.shape[0] - nans))
    elif is_sparse and X.size:
        non_zero = np.bincount(X.nonzero()[1], minlength=X.shape[1])
        return np.column_stack((
            nanmin(X, axis=0),
            nanmax(X, axis=0),
            means,
            vars,
            X.shape[0] - non_zero,
            non_zero))
    else:
        if X.ndim == 1:
            X = X[:, None]
        nans = (pandas.isnull(X).sum(axis=0) + (X == "").sum(axis=0)) \
            if X.size else np.zeros(X.shape[1])
        return np.column_stack((
            np.tile(np.inf, X.shape[1]),
            np.tile(-np.inf, X.shape[1]),
            np.zeros(X.shape[1]),
            np.zeros(X.shape[1]),
            nans,
            X.shape[0] - nans))


def _nan_min_max(x, func, axis=0):
    if not sp.issparse(x):
        return func(x, axis=axis)
    if axis is None:
        extreme = func(x.data, axis=axis) if x.nnz else float('nan')
        if sparse_has_implicit_zeros(x):
            extreme = func([0, extreme])
        return extreme
    if axis == 0:
        x = x.T
    else:
        assert axis == 1

    # TODO check & transform to correct format
    r = []
    for row in x:
        values = row.data
        extreme = func(values) if values.size else float('nan')
        if sparse_has_implicit_zeros(row):
            extreme = func([0, extreme])
        r.append(extreme)
    return np.array(r)


def nanmin(x, axis=None):
    """ Equivalent of np.nammin that supports sparse or dense matrices. """
    return _nan_min_max(x, np.nanmin, axis)


def nanmax(x, axis=None):
    """ Equivalent of np.nammax that supports sparse or dense matrices. """
    return _nan_min_max(x, np.nanmax, axis)


def mean(x):
    """ Equivalent of np.mean that supports sparse or dense matrices. """
    m = (np.sum(x.data) / np.prod(x.shape)
         if sp.issparse(x) else
         np.mean(x))
    if np.isnan(m):
        warnings.warn('mean() resulted in nan. If input can contain nan values,'
                      ' perhaps you meant nanmean?', stacklevel=2)
    return m


def _apply_func(x, dense_func, sparse_func, axis=None):
    """ General wrapper for a function depending on sparse or dense matrices. """
    if not sp.issparse(x):
        return dense_func(x, axis=axis)
    if axis is None:
        return sparse_func(x)
    if axis in [0, 1]:
        arr = x if axis == 1 else x.T
        arr = arr.tocsr()
        return np.fromiter((sparse_func(row) for row in arr),
                           dtype=np.double, count=arr.shape[0])
    else:
        raise NotImplementedError


def nansum(x, axis=None):
    """ Equivalent of np.nansum that supports sparse or dense matrices. """
    def nansum_sparse(x):
        return np.nansum(x.data)

    return _apply_func(x, np.nansum, nansum_sparse, axis=axis)


def nanmean(x, axis=None, weights=None):
    """ Equivalent of np.nanmean that supports sparse or dense matrices. """
    if axis is None and weights is not None:
        raise NotImplementedError("weights are only supported if axis is defined")

    if not sp.issparse(x):
        if weights is None:
            means = bn.nanmean(x, axis=axis)
        else:
            if axis == 0:
                weights = weights.reshape(-1, 1)
            elif axis == 1:
                weights = weights.reshape(1, -1)
            else:
                raise NotImplementedError
            nanw = ~np.isnan(x) * weights  # do not divide by non-used weights
            means = bn.nansum(x * weights, axis=axis) / np.sum(nanw, axis=axis)
    elif axis is None:
        means, _ = mean_variance_axis(x, axis=0)
        means = np.nanmean(means)
    else:
        # mean_variance_axis is picky regarding the input type
        if weights is not None:
            weights = weights.astype(float)
        means, _ = mean_variance_axis(x, axis=axis, weights=weights)

    return means


def nan_mean_var(x, axis=None, weights=None):
    """
    Computes means and variance of dense and sparse matrices.
    Supports weights. Based on mean_variance_axis.
    """
    if axis is None:
        raise NotImplementedError("axis=None is not supported")

    if not sp.issparse(x):
        if weights is None:
            means = bn.nanmean(x, axis=axis)
            variances = bn.nanvar(x, axis=axis)
        else:
            if axis == 0:
                weights = weights.reshape(-1, 1)
            elif axis == 1:
                weights = weights.reshape(1, -1)
            else:
                raise NotImplementedError

            nanw = ~np.isnan(x) * weights  # do not divide by non-used weights
            wsum = np.sum(nanw, axis=axis)
            means = bn.nansum(x * weights, axis=axis) / wsum

            if axis == 0:
                mr = means.reshape(1, -1)
            elif axis == 1:
                mr = means.reshape(-1, 1)

            variances = bn.nansum(((x - mr) ** 2) * weights, axis=axis) / wsum
    else:
        # mean_variance_axis is picky regarding the input type
        if weights is not None:
            weights = weights.astype(float)
        means, variances = mean_variance_axis(x, axis=axis, weights=weights)

    return means, variances


def nanvar(x, axis=None, ddof=0):
    """ Equivalent of np.nanvar that supports sparse or dense matrices. """
    def nanvar_sparse(x):
        n_vals = np.prod(x.shape) - np.sum(np.isnan(x.data))
        n_zeros = np.prod(x.shape) - len(x.data)
        avg = np.nansum(x.data) / n_vals
        return (np.nansum((x.data - avg) ** 2) + avg ** 2 * n_zeros) / (n_vals - ddof)

    return _apply_func(x, bn.nanvar, nanvar_sparse, axis=axis)


def nanstd(x, axis=None, ddof=0):
    """ Equivalent of np.nanstd that supports sparse and dense matrices. """
    return np.sqrt(nanvar(x, axis=axis, ddof=ddof))


def nanmedian(x, axis=None):
    """ Equivalent of np.nanmedian that supports sparse or dense matrices. """
    def nanmedian_sparse(x):
        nz = np.logical_not(np.isnan(x.data))
        n_nan = sum(np.isnan(x.data))
        n_nonzero = sum(x.data[nz] != 0)
        n_zeros = np.prod(x.shape) - n_nonzero - n_nan
        if n_zeros > n_nonzero:
            # Typical case if use of sparse matrices make sense
            return 0
        else:
            # Possibly contains NaNs and
            # more nz values than zeros, so allocating memory should not be too problematic
            return np.nanmedian(x.toarray())

    return _apply_func(x, np.nanmedian, nanmedian_sparse, axis=axis)


def nanmode(x, axis=0):
    """ A temporary replacement for a scipy.stats.mode.

    This function returns mode NaN if all values are NaN (scipy<1.2.0 wrongly
    returns zero). Also, this function returns count NaN if all values are NaN
    (scipy=1.3.0 returns some number)."""
    nans = np.isnan(np.array(x)).sum(axis=axis, keepdims=True) == x.shape[axis]
    res = scipy.stats.mode(x, axis, keepdims=True)
    # type(res) is ModeResult. ModeResult is defined in scipy.stats.stats; this
    # namespace is deprecated, but ModeResult is not exported to scipy.stats
    # Hence we use type(res) to avoid a warning.
    return type(res)(np.where(nans, np.nan, res.mode),
                     np.where(nans, np.nan, res.count))


def unique(x, return_counts=False):
    """ Equivalent of np.unique that supports sparse or dense matrices. """
    if not sp.issparse(x):
        return np.unique(x, return_counts=return_counts)

    implicit_zeros = sparse_count_implicit_zeros(x)
    explicit_zeros = not np.all(x.data)
    r = np.unique(x.data, return_counts=return_counts)
    if not implicit_zeros:
        return r

    if return_counts:
        zero_index = np.searchsorted(r[0], 0)
        if explicit_zeros:
            r[1][r[0] == 0.] += implicit_zeros
            return r
        return np.insert(r[0], zero_index, 0), np.insert(r[1], zero_index, implicit_zeros)
    else:
        if explicit_zeros:
            return r
        zero_index = np.searchsorted(r, 0)
        return np.insert(r, zero_index, 0)


def nanunique(*args, **kwargs):
    """ Return unique values while disregarding missing (np.nan) values.
    Supports sparse or dense matrices. """
    result = unique(*args, **kwargs)

    if isinstance(result, tuple):
        result, counts = result
        non_nan_mask = ~np.isnan(result)
        return result[non_nan_mask], counts[non_nan_mask]

    return result[~np.isnan(result)]


def digitize(x, bins, right=False):
    """Equivalent of np.digitize that supports sparse and dense matrices.

    If a sparse matrix is provided and the '0's belong to the '0'th bin, then
    a sparse matrix is returned.

    Because this can return both sparse and dense matrices, we must keep the
    return shape consistent. Since sparse matrices don't support 1d matrices,
    we reshape any returned 1d numpy array to a 2d matrix, with the first
    dimension shape being 1. This is equivalent to the behaviour of sparse
    matrices.

    Parameters
    ----------
    x : Union[np.ndarry, sp.csr_matrix, sp.csc_matrix]
    bins : np.ndarray
    right : Optional[bool]

    Returns
    -------
    Union[np.ndarray, sp.csr_matrix]

    """
    if not sp.issparse(x):
        # TODO Remove reshaping logic when support for numpy==1.9 is dropped
        original_shape = x.shape
        x = x.flatten()
        result = np.digitize(x, bins, right)
        result = result.reshape(original_shape)
        # In order to keep the return shape consistent, and sparse matrices
        # don't support 1d matrices, make sure to convert 1d to 2d matrices
        if result.ndim == 1:
            result = result.reshape(((1,) + result.shape))
        return result

    # Find the bin where zeros belong, depending on the `right` parameter
    zero_bin = np.searchsorted(bins, 0, side=['right', 'left'][right])

    if zero_bin == 0:
        r = sp.lil_matrix(x.shape, dtype=np.int64)
    else:
        r = zero_bin * np.ones(x.shape, dtype=np.int64)

    for idx, row in enumerate(x.tocsr()):
        # TODO Remove this check when support for numpy==1.9 is dropped
        if row.nnz > 0:
            r[idx, row.indices] = np.digitize(row.data, bins, right)

    # Orange mainly deals with `csr_matrix`, but `lil_matrix` is more efficient
    # for incremental building
    if sp.issparse(r):
        r = r.tocsr()

    return r


def var(x, axis=None, ddof=0):
    """ Equivalent of np.var that supports sparse and dense matrices. """
    if not sp.issparse(x):
        return np.var(x, axis, ddof=ddof)

    result = x.multiply(x).mean(axis) - np.square(x.mean(axis))
    result = np.squeeze(np.asarray(result))

    # Apply correction for degrees of freedom
    n = np.prod(x.shape) if axis is None else x.shape[axis]
    result *= n / (n - ddof)

    return result


def std(x, axis=None, ddof=0):
    """ Equivalent of np.std that supports sparse and dense matrices. """
    return np.sqrt(var(x, axis=axis, ddof=ddof))


def nan_to_num(x, copy=True):
    """ Equivalent of np.nan_to_num that supports sparse and dense matrices. """
    if not sp.issparse(x):
        return np.nan_to_num(x, copy=copy)

    if copy:
        x = x.copy()
    np.nan_to_num(x.data, copy=False)
    _eliminate_zeros(x)
    return x


def isnan(x, out=None):
    """ Equivalent of np.isnan that supports sparse and dense matrices. """
    if not sp.issparse(x):
        return np.isnan(x, out=out)

    if out is None:
        x = x.copy()
    elif out is not x:
        raise ValueError(
            "The `out` parameter can only be set `x` when using sparse matrices"
        )

    np.isnan(x.data, out=x.data)
    _eliminate_zeros(x)
    return x


def any_nan(x, axis=None):
    """ Check if any of the values in a matrix is nan. """
    if not sp.issparse(x):
        return np.isnan(x).any(axis=axis)

    if axis is None:
        return np.isnan(x.data).any()

    if axis == 0:
        x = x.tocsc()
    elif axis == 1:
        x = x.tocsr()

    ax = x.ndim - axis - 1
    result = np.zeros(x.shape[ax], dtype=bool)
    for i in range(x.shape[ax]):
        vals = x.data[x.indptr[i]:x.indptr[i + 1]]
        result[i] = np.isnan(vals).any()

    return result


def all_nan(x, axis=None):
    """
    Check if all of the values in a matrix is nan. Works for sparse matrix too.
    """
    if not sp.issparse(x):
        return np.isnan(x).all(axis=axis)

    if axis is None:
        # when x.nnz < actual shape there are zero values which are not nan
        return np.prod(x.shape) == x.nnz and np.isnan(x.data).all()

    if axis == 0:
        x = x.tocsc()
    elif axis == 1:
        x = x.tocsr()

    ax = x.ndim - axis - 1
    axis_len = x.shape[axis]
    result = np.zeros(x.shape[ax], dtype=bool)
    for i in range(x.shape[ax]):
        vals = x.data[x.indptr[i]:x.indptr[i + 1]]
        result[i] = axis_len == len(vals) and np.isnan(vals).all()

    return result


def FDR(p_values: Iterable, dependent=False, m=None, ordered=False) -> Iterable:
    """ `False Discovery Rate <http://en.wikipedia.org/wiki/False_discovery_rate>`_
        correction on a list of p-values.

    :param p_values: list or np.ndarray of p-values.
    :param dependent: use correction for dependent hypotheses (default False).
    :param m: number of hypotheses tested (default ``len(p_values)``).
    :param ordered: prevent sorting of p-values if they are already sorted
        (default False).
    :return: list or np.ndarray, same as the input
    """
    if p_values is None or len(p_values) == 0 or \
            (m is not None and m <= 0):
        return None

    is_list = isinstance(p_values, list)
    p_values = np.array(p_values)
    if m is None:
        m = len(p_values)
    if not ordered:
        ordered = (np.diff(p_values) >= 0).all()
        if not ordered:
            indices = np.argsort(p_values)
            p_values = p_values[indices]

    if dependent:  # correct q for dependent tests
        m *= sum(1 / np.arange(1, m + 1))

    fdrs = (p_values * m / np.arange(1, len(p_values) + 1))[::-1]
    fdrs = np.array(np.minimum.accumulate(fdrs)[::-1])
    if not ordered:
        fdrs[indices] = fdrs.copy()
    return fdrs if not is_list else list(fdrs)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** Statistics Utility Incorrectly Counts Zeros as NaNs, Leading to Inaccurate Calculations

**Description:**
In the statistical utilities, zeros are being mistakenly counted as NaN (Not a Number) values. This miscount affects the accuracy of statistical measures such as mean, variance, and the count of valid entries.

**Example:**
When processing a sparse identity matrix, zeros should be recognized as valid numerical values, not as NaNs.

```python
import numpy as np
from scipy.sparse import csr_matrix
from Orange.statistics.util import stats

X = csr_matrix(np.identity(5))
result = stats(X)
print(result)
```

**Expected Behavior:**
Zeros should be treated as legitimate numerical entries. The NaN count should accurately reflect only the actual NaN values present in the data.

**Actual Behavior:**
Zeros are incorrectly identified as NaNs, resulting in inflated NaN counts and reduced counts of valid numerical entries. This leads to incorrect statistical outcomes.

[/ISSUE]
{
    "TestUtil.test_FDR": "PASSED",
    "TestUtil.test_FDR_dependent": "PASSED",
    "TestUtil.test_FDR_list": "PASSED",
    "TestUtil.test_FDR_m": "PASSED",
    "TestUtil.test_FDR_no_values": "PASSED",
    "TestUtil.test_contingency": "PASSED",
    "TestUtil.test_mean": "PASSED",
    "TestUtil.test_nanmedian": "PASSED",
    "TestUtil.test_nanmedian_more_nonzeros": "PASSED",
    "TestUtil.test_nanmin_nanmax": "PASSED",
    "TestUtil.test_nanmode": "PASSED",
    "TestUtil.test_nanstd": "PASSED",
    "TestUtil.test_nanstd_with_ddof": "PASSED",
    "TestUtil.test_nansum": "PASSED",
    "TestUtil.test_nanvar": "PASSED",
    "TestUtil.test_nanvar_with_ddof": "PASSED",
    "TestUtil.test_stats": "PASSED",
    "TestUtil.test_stats_empty": "PASSED",
    "TestUtil.test_stats_long_string_mem_use": "PASSED",
    "TestUtil.test_stats_nancounts": "PASSED",
    "TestUtil.test_stats_nans_neutral_weights": "PASSED",
    "TestUtil.test_stats_nans_neutral_weights_sparse": "PASSED",
    "TestUtil.test_stats_non_numeric": "PASSED",
    "TestUtil.test_stats_sparse": "PASSED",
    "TestUtil.test_stats_weights": "PASSED",
    "TestUtil.test_stats_weights_sparse": "PASSED",
    "TestUtil.test_std": "PASSED",
    "TestUtil.test_std_with_ddof": "PASSED",
    "TestUtil.test_var": "PASSED",
    "TestUtil.test_var_with_ddof": "PASSED",
    "TestUtil.test_weighted_contingency": "PASSED",
    "TestNanmean.test_axis_0": "PASSED",
    "TestNanmean.test_axis_1": "PASSED",
    "TestNanmean.test_axis_none": "PASSED",
    "TestNanmean.test_weights_axis_0": "PASSED",
    "TestNanmean.test_weights_axis_1": "PASSED",
    "TestNanmean.test_weights_axis_none": "PASSED",
    "TestNanMeanVar.test_axis_0": "PASSED",
    "TestNanMeanVar.test_axis_1": "PASSED",
    "TestNanMeanVar.test_axis_none": "PASSED",
    "TestDigitize.test_digitize": "PASSED",
    "TestDigitize.test_digitize_1d_array": "PASSED",
    "TestDigitize.test_digitize_right": "PASSED",
    "TestDigitize.test_digitize_sparse_zeroth_bin": "PASSED",
    "TestCountnans.test_1d_array": "PASSED",
    "TestCountnans.test_1d_array_with_axis_0": "PASSED",
    "TestCountnans.test_1d_array_with_axis_1_raises_exception": "PASSED",
    "TestCountnans.test_1d_weights_with_axis_0": "PASSED",
    "TestCountnans.test_1d_weights_with_axis_1": "PASSED",
    "TestCountnans.test_2d_matrix": "PASSED",
    "TestCountnans.test_2d_weights": "PASSED",
    "TestCountnans.test_dtype": "PASSED",
    "TestCountnans.test_on_columns": "PASSED",
    "TestCountnans.test_on_rows": "PASSED",
    "TestCountnans.test_shape_matches_dense_and_sparse": "PASSED",
    "TestCountnans.test_shape_matches_dense_and_sparse_with_axis_0": "PASSED",
    "TestCountnans.test_shape_matches_dense_and_sparse_with_axis_1": "PASSED",
    "TestBincount.test_adds_empty_bins": "PASSED",
    "TestBincount.test_all_nans": "PASSED",
    "TestBincount.test_all_zeros_or_nans": "PASSED",
    "TestBincount.test_count_nans": "PASSED",
    "TestBincount.test_count_nans_objectarray": "PASSED",
    "TestBincount.test_maxval_adds_empty_bins": "PASSED",
    "TestBincount.test_maxval_doesnt_truncate_values_when_too_small": "PASSED",
    "TestBincount.test_minlength_adds_empty_bins": "PASSED",
    "TestBincount.test_weights": "PASSED",
    "TestBincount.test_weights_with_nans": "PASSED",
    "TestBincount.test_weights_with_transposed_x": "PASSED",
    "TestUnique.test_nanunique_ignores_nans_in_counts": "PASSED",
    "TestUnique.test_nanunique_ignores_nans_in_values": "PASSED",
    "TestUnique.test_returns_counts": "PASSED",
    "TestUnique.test_returns_unique_values": "PASSED",
    "TestUnique.test_sparse_explicit_zeros": "PASSED",
    "TestNanToNum.test_converts_invalid_values": "PASSED",
    "TestNanToNum.test_preserves_valid_values": "PASSED",
    "TestIsnan.test_functionality": "PASSED",
    "TestIsnan.test_out": "PASSED",
    "TestAnyNans.test_axis_0_with_nans": "PASSED",
    "TestAnyNans.test_axis_0_without_nans": "PASSED",
    "TestAnyNans.test_axis_1_with_nans": "PASSED",
    "TestAnyNans.test_axis_1_without_nans": "PASSED",
    "TestAnyNans.test_axis_none_with_nans": "PASSED",
    "TestAnyNans.test_axis_none_without_nans": "PASSED",
    "TestAllNans.test_axis_0_with_nans": "PASSED",
    "TestAllNans.test_axis_0_without_nans": "PASSED",
    "TestAllNans.test_axis_1_with_nans": "PASSED",
    "TestAllNans.test_axis_1_without_nans": "PASSED",
    "TestAllNans.test_axis_none_with_nans": "PASSED",
    "TestAllNans.test_axis_none_without_nans": "PASSED"
}
diff --git a/Orange/statistics/util.py b/Orange/statistics/util.py
index c37715e47..0aaf1024e 100644
--- a/Orange/statistics/util.py
+++ b/Orange/statistics/util.py
@@ -344,31 +344,22 @@ def stats(X, weights=None, compute_variance=False):
 
     if X.size and is_numeric:
         if is_sparse:
+            nans = countnans(X, axis=0)
             X = X.tocsc()
+        else:
+            nans = np.isnan(X).sum(axis=0)
         if compute_variance:
             means, vars = nan_mean_var(X, axis=0, weights=weights)
         else:
             means = nanmean(X, axis=0, weights=weights)
             vars = np.zeros(X.shape[1] if X.ndim == 2 else 1)
-
-    if X.size and is_numeric and not is_sparse:
-        nans = np.isnan(X).sum(axis=0)
-        return np.column_stack((
-            np.nanmin(X, axis=0),
-            np.nanmax(X, axis=0),
-            means,
-            vars,
-            nans,
-            X.shape[0] - nans))
-    elif is_sparse and X.size:
-        non_zero = np.bincount(X.nonzero()[1], minlength=X.shape[1])
         return np.column_stack((
             nanmin(X, axis=0),
             nanmax(X, axis=0),
             means,
             vars,
-            X.shape[0] - non_zero,
-            non_zero))
+            nans,
+            X.shape[0] - nans))
     else:
         if X.ndim == 1:
             X = X[:, None]

{"Orange/statistics/util.py": "\"\"\"\nThis module provides alternatives for the few additional functions found in\nand once used from the bottlechest package (fork of bottleneck).\n\nIt also patches bottleneck to contain these functions.\n\"\"\"\nimport warnings\nfrom typing import Iterable\n\nimport bottleneck as bn\nimport numpy as np\nimport pandas\nimport scipy.stats.stats\nfrom scipy import sparse as sp\n\nfrom sklearn.utils.sparsefuncs import mean_variance_axis\n\n\ndef _eliminate_zeros(x):\n    \"\"\"Eliminate zeros from sparse matrix, or raise appropriate warning.\"\"\"\n    if hasattr(x, \"eliminate_zeros\"):\n        x.eliminate_zeros()\n    else:\n        warnings.warn(\n            f\"`{x.__type__}` does not implement `eliminate_zeros`. Some values \"\n            f\"in the sparse matrix may by explicit zeros.\"\n        )\n\n\ndef _count_nans_per_row_sparse(X, weights, dtype=None):\n    \"\"\" Count the number of nans (undefined) values per row. \"\"\"\n    if weights is not None:\n        X = X.tocoo(copy=False)\n        nonzero_mask = np.isnan(X.data)\n        nan_rows, nan_cols = X.row[nonzero_mask], X.col[nonzero_mask]\n\n        if weights.ndim == 1:\n            data_weights = weights[nan_rows]\n        else:\n            data_weights = weights[nan_rows, nan_cols]\n\n        w = sp.coo_matrix((data_weights, (nan_rows, nan_cols)), shape=X.shape)\n        w = w.tocsr()\n        return np.asarray(w.sum(axis=1), dtype=dtype).ravel()\n\n    if isinstance(X, (sp.csr_matrix, sp.csc_matrix)):\n        X = type(X)((np.isnan(X.data), X.indices, X.indptr), X.shape)\n        return np.asarray(X.sum(axis=1), dtype=dtype).ravel()\n    else:  # pragma: no cover\n        raise TypeError(\"unsupported type '{}'\".format(type(X).__name__))\n\n\ndef sparse_count_implicit_zeros(x):\n    \"\"\" Count the number of implicit zeros in a sparse matrix. \"\"\"\n    if not sp.issparse(x):\n        raise TypeError('The matrix provided was not sparse.')\n    return np.prod(x.shape) - x.nnz\n\n\ndef sparse_has_implicit_zeros(x):\n    \"\"\" Check if sparse matrix contains any implicit zeros. \"\"\"\n    if not sp.issparse(x):\n        raise TypeError('The matrix provided was not sparse.')\n    return np.prod(x.shape) != x.nnz\n\n\ndef sparse_implicit_zero_weights(x, weights):\n    \"\"\" Extract the weight values of all zeros in a sparse matrix. \"\"\"\n    if not sp.issparse(x):\n        raise TypeError('The matrix provided was not sparse.')\n\n    if weights.ndim == 1:\n        # Match weights and x axis so `indices` will be set appropriately\n        if x.shape[0] == weights.shape[0]:\n            x = x.tocsc()\n        elif x.shape[1] == weights.shape[0]:\n            x = x.tocsr()\n        n_items = np.prod(x.shape)\n        zero_indices = np.setdiff1d(np.arange(n_items), x.indices, assume_unique=True)\n        return weights[zero_indices]\n    else:\n        # Can easily be implemented using a coo_matrix\n        raise NotImplementedError(\n            'Computing zero weights on ndimensinal weight matrix is not implemented'\n        )\n\n\ndef bincount(x, weights=None, max_val=None, minlength=0):\n    \"\"\"Return counts of values in array X.\n\n    Works kind of like np.bincount(), except that it also supports\n    arrays with nans.\n\n    Parameters\n    ----------\n    x : array_like, 1 dimension, nonnegative ints\n        Input array.\n    weights : array_like, optional\n        Weights, array of the same shape as x.\n    max_val : int, optional\n        Indicates the maximum value we expect to find in X and sets the result\n        array size accordingly. E.g. if we set `max_val=2` yet the largest\n        value in X is 1, the result will contain a bin for the value 2, and\n        will be set to 0. See examples for usage.\n    minlength : int, optional\n        A minimum number of bins for the output array. See numpy docs for info.\n\n    Returns\n    -------\n    Tuple[np.ndarray, int]\n        Returns the bincounts and the number of NaN values.\n\n    Examples\n    --------\n    In case `max_val` is provided, the return shape includes bins for these\n    values as well, even if they do not appear in the data. However, this will\n    not truncate the bincount if values larger than `max_count` are found.\n    >>> bincount([0, 0, 1, 1, 2], max_val=4)\n    (array([ 2.,  2.,  1.,  0.,  0.]), 0.0)\n    >>> bincount([0, 1, 2, 3, 4], max_val=2)\n    (array([ 1.,  1.,  1.,  1.,  1.]), 0.0)\n\n    \"\"\"\n    # Store the original matrix before any manipulation to check for sparse\n    x_original = x\n    if sp.issparse(x):\n        if weights is not None:\n            # Match weights and x axis so `indices` will be set appropriately\n            if x.shape[0] == weights.shape[0]:\n                x = x.tocsc()\n            elif x.shape[1] == weights.shape[0]:\n                x = x.tocsr()\n\n            zero_weights = sparse_implicit_zero_weights(x, weights).sum()\n            weights = weights[x.indices]\n        else:\n            zero_weights = sparse_count_implicit_zeros(x)\n\n        x = x.data\n\n    x = np.asanyarray(x, dtype=float)\n    if bn.anynan(x):\n        nonnan = ~np.isnan(x)\n        x = x[nonnan]\n        if weights is not None:\n            nans = (~nonnan * weights).sum(axis=0)\n            weights = weights[nonnan]\n        else:\n            nans = (~nonnan).sum(axis=0)\n    else:\n        nans = 0. if x.ndim == 1 else np.zeros(x.shape[1], dtype=float)\n\n    if minlength == 0 and max_val is not None:\n        minlength = max_val + 1\n\n    bc = np.bincount(\n        x.astype(np.int32, copy=False), weights=weights, minlength=minlength\n    ).astype(float)\n    # Since `csr_matrix.values` only contain non-zero values or explicit\n    # zeros, we must count implicit zeros separately and add them to the\n    # explicit ones found before\n    if sp.issparse(x_original):\n        # If x contains only NaNs, then bc will be an empty array\n        if zero_weights and bc.size == 0:\n            bc = [zero_weights]\n        elif zero_weights:\n            bc[0] += zero_weights\n\n    return bc, nans\n\n\ndef countnans(x, weights=None, axis=None, dtype=None, keepdims=False):\n    \"\"\"\n    Count the undefined elements in an array along given axis.\n\n    Parameters\n    ----------\n    x : array_like\n    weights : array_like, optional\n        Weights to weight the nans with, before or after counting (depending\n        on the weights shape).\n    axis : int, optional\n    dtype : dtype, optional\n        The data type of the returned array.\n\n    Returns\n    -------\n    Union[np.ndarray, float]\n\n    \"\"\"\n    if not sp.issparse(x):\n        x = np.asanyarray(x)\n        is_nan = np.isnan(x)\n        if weights is not None and weights.shape == x.shape:\n            is_nan = is_nan * weights\n\n        counts = is_nan.sum(axis=axis, dtype=dtype, keepdims=keepdims)\n        if weights is not None and weights.shape != x.shape:\n            counts = counts * weights\n    else:\n        assert axis in [None, 0, 1], 'Only axis 0 and 1 are currently supported'\n        # To have consistent behaviour with dense matrices, raise error when\n        # `axis=1` and the array is 1d (e.g. [[1 2 3]])\n        if x.shape[0] == 1 and axis == 1:\n            raise ValueError('Axis %d is out of bounds' % axis)\n\n        arr = x if axis == 1 else x.T\n\n        if weights is not None:\n            weights = weights if axis == 1 else weights.T\n\n        arr = arr.tocsr()\n        counts = _count_nans_per_row_sparse(arr, weights, dtype=dtype)\n\n        # We want a scalar value if `axis=None` or if the sparse matrix is\n        # actually a vector (e.g. [[1 2 3]]), but has `ndim=2` due to scipy\n        # implementation\n        if axis is None or x.shape[0] == 1:\n            counts = counts.sum(dtype=dtype)\n\n    return counts\n\n\ndef contingency(X, y, max_X=None, max_y=None, weights=None, mask=None):\n    \"\"\"\n    Compute the contingency matrices for each column of X (excluding the masked)\n    versus the vector y.\n\n    If the array is 1-dimensional, a 2d contingency matrix is returned. If the\n    array is 2d, the function returns a 3d array, with the first dimension\n    corresponding to column index (variable in the input array).\n\n    The column of contingency matrix correspond to values of variables, the\n    row correspond to values in vector `y`.\n\n    Rows in the input array can be weighted (argument `weights`). A subset of\n    columns can be selected by additional argument `mask`.\n\n    The function also returns a count of NaN values per each value of `y`.\n\n    Parameters\n    ----------\n    X : array_like\n        With values in columns.\n    y : 1d array\n        Vector of true values.\n    max_X : int\n        The maximal value in the array\n    max_y : int\n        The maximal value in `y`\n    weights : array_like\n        Row weights. When not None, contingencies contain weighted counts\n    mask : sequence\n        Discrete columns of X.\n\n    Returns\n    -------\n    contingencies: (m \u00d7 ny \u00d7 nx) array\n        m number of masked (used) columns (all if mask=None), i.e.\n        for each column of X;\n        ny number of uniques in y,\n        nx number of uniques in column of X.\n    nans_cols : array_like\n        Number of nans in each column of X for each unique value of y.\n    nans_rows : array_like\n        Number of nans in y for each unique value in columns of X.\n    nans : array_like\n        Number of nans in column of X and y at the same time.\n    \"\"\"\n    was_1d = False\n    if X.ndim == 1:\n        X = X[..., np.newaxis]\n        was_1d = True\n\n    contingencies, nans_cols, nans_rows, nans = [], [], [], []\n    ny = np.unique(y).size if max_y is None else max_y + 1\n    for i in range(X.shape[1]):\n        if mask is not None and not mask[i]:\n            contingencies.append(np.zeros((ny, max_X + 1)))\n            nans_cols.append(np.zeros(ny))\n            nans_rows.append(None)\n            nans.append(0)\n            continue\n        col = X[..., i]\n        nx = np.unique(col[~np.isnan(col)]).size if max_X is None else max_X + 1\n        if sp.issparse(col):\n            col = np.ravel(col.todense())\n        contingencies.append(\n            bincount(y + ny * col,\n                     minlength=ny * nx,\n                     weights=weights)[0].reshape(nx, ny).T)\n\n        nan_col_mask = np.isnan(col)\n        nan_row_mask = np.isnan(y)\n        nan_mask = nan_col_mask & nan_row_mask\n        weights_ = np.ones(len(y)) if weights is None else weights\n\n        nans_cols.append(\n            bincount(y[nan_col_mask], weights=weights_[nan_col_mask],\n                     minlength=ny)[0])\n        nans_rows.append(\n            bincount(col[nan_row_mask], weights=weights_[nan_row_mask],\n                     minlength=nx)[0])\n        nans.append(np.sum(nan_mask * weights_))\n    if was_1d:\n        return contingencies[0], nans_cols[0], nans_rows[0], nans[0]\n    return np.array(contingencies), np.array(nans_cols), nans_rows, nans\n\n\ndef stats(X, weights=None, compute_variance=False):\n    \"\"\"\n    Compute min, max, #nans, mean and variance.\n\n    Result is a tuple (min, max, mean, variance, #nans, #non-nans) or an\n    array of shape (len(X), 6).\n\n    The mean and the number of nans and non-nans are weighted.\n\n    Computation of variance requires an additional pass and is not enabled\n    by default. Zeros are filled in instead of variance.\n\n    Parameters\n    ----------\n    X : array_like, 1 or 2 dimensions\n        Input array.\n    weights : array_like, optional\n        Weights, array of the same length as `x`.\n    compute_variance : bool, optional\n        If set to True, the function also computes variance.\n\n    Returns\n    -------\n    out : a 6-element tuple or an array of shape (len(x), 6)\n        Computed (min, max, mean, variance or 0, #nans, #non-nans)\n\n    Raises\n    ------\n    ValueError\n        If the length of the weight vector does not match the length of the\n        array\n    \"\"\"\n    is_numeric = np.issubdtype(X.dtype, np.number)\n    is_sparse = sp.issparse(X)\n\n    if X.size and is_numeric:\n        if is_sparse:\n            X = X.tocsc()\n        if compute_variance:\n            means, vars = nan_mean_var(X, axis=0, weights=weights)\n        else:\n            means = nanmean(X, axis=0, weights=weights)\n            vars = np.zeros(X.shape[1] if X.ndim == 2 else 1)\n\n    if X.size and is_numeric and not is_sparse:\n        nans = np.isnan(X).sum(axis=0)\n        return np.column_stack((\n            np.nanmin(X, axis=0),\n            np.nanmax(X, axis=0),\n            means,\n            vars,\n            nans,\n            X.shape[0] - nans))\n    elif is_sparse and X.size:\n        non_zero = np.bincount(X.nonzero()[1], minlength=X.shape[1])\n        return np.column_stack((\n            nanmin(X, axis=0),\n            nanmax(X, axis=0),\n            means,\n            vars,\n            X.shape[0] - non_zero,\n            non_zero))\n    else:\n        if X.ndim == 1:\n            X = X[:, None]\n        nans = (pandas.isnull(X).sum(axis=0) + (X == \"\").sum(axis=0)) \\\n            if X.size else np.zeros(X.shape[1])\n        return np.column_stack((\n            np.tile(np.inf, X.shape[1]),\n            np.tile(-np.inf, X.shape[1]),\n            np.zeros(X.shape[1]),\n            np.zeros(X.shape[1]),\n            nans,\n            X.shape[0] - nans))\n\n\ndef _nan_min_max(x, func, axis=0):\n    if not sp.issparse(x):\n        return func(x, axis=axis)\n    if axis is None:\n        extreme = func(x.data, axis=axis) if x.nnz else float('nan')\n        if sparse_has_implicit_zeros(x):\n            extreme = func([0, extreme])\n        return extreme\n    if axis == 0:\n        x = x.T\n    else:\n        assert axis == 1\n\n    # TODO check & transform to correct format\n    r = []\n    for row in x:\n        values = row.data\n        extreme = func(values) if values.size else float('nan')\n        if sparse_has_implicit_zeros(row):\n            extreme = func([0, extreme])\n        r.append(extreme)\n    return np.array(r)\n\n\ndef nanmin(x, axis=None):\n    \"\"\" Equivalent of np.nammin that supports sparse or dense matrices. \"\"\"\n    return _nan_min_max(x, np.nanmin, axis)\n\n\ndef nanmax(x, axis=None):\n    \"\"\" Equivalent of np.nammax that supports sparse or dense matrices. \"\"\"\n    return _nan_min_max(x, np.nanmax, axis)\n\n\ndef mean(x):\n    \"\"\" Equivalent of np.mean that supports sparse or dense matrices. \"\"\"\n    m = (np.sum(x.data) / np.prod(x.shape)\n         if sp.issparse(x) else\n         np.mean(x))\n    if np.isnan(m):\n        warnings.warn('mean() resulted in nan. If input can contain nan values,'\n                      ' perhaps you meant nanmean?', stacklevel=2)\n    return m\n\n\ndef _apply_func(x, dense_func, sparse_func, axis=None):\n    \"\"\" General wrapper for a function depending on sparse or dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return dense_func(x, axis=axis)\n    if axis is None:\n        return sparse_func(x)\n    if axis in [0, 1]:\n        arr = x if axis == 1 else x.T\n        arr = arr.tocsr()\n        return np.fromiter((sparse_func(row) for row in arr),\n                           dtype=np.double, count=arr.shape[0])\n    else:\n        raise NotImplementedError\n\n\ndef nansum(x, axis=None):\n    \"\"\" Equivalent of np.nansum that supports sparse or dense matrices. \"\"\"\n    def nansum_sparse(x):\n        return np.nansum(x.data)\n\n    return _apply_func(x, np.nansum, nansum_sparse, axis=axis)\n\n\ndef nanmean(x, axis=None, weights=None):\n    \"\"\" Equivalent of np.nanmean that supports sparse or dense matrices. \"\"\"\n    if axis is None and weights is not None:\n        raise NotImplementedError(\"weights are only supported if axis is defined\")\n\n    if not sp.issparse(x):\n        if weights is None:\n            means = bn.nanmean(x, axis=axis)\n        else:\n            if axis == 0:\n                weights = weights.reshape(-1, 1)\n            elif axis == 1:\n                weights = weights.reshape(1, -1)\n            else:\n                raise NotImplementedError\n            nanw = ~np.isnan(x) * weights  # do not divide by non-used weights\n            means = bn.nansum(x * weights, axis=axis) / np.sum(nanw, axis=axis)\n    elif axis is None:\n        means, _ = mean_variance_axis(x, axis=0)\n        means = np.nanmean(means)\n    else:\n        # mean_variance_axis is picky regarding the input type\n        if weights is not None:\n            weights = weights.astype(float)\n        means, _ = mean_variance_axis(x, axis=axis, weights=weights)\n\n    return means\n\n\ndef nan_mean_var(x, axis=None, weights=None):\n    \"\"\"\n    Computes means and variance of dense and sparse matrices.\n    Supports weights. Based on mean_variance_axis.\n    \"\"\"\n    if axis is None:\n        raise NotImplementedError(\"axis=None is not supported\")\n\n    if not sp.issparse(x):\n        if weights is None:\n            means = bn.nanmean(x, axis=axis)\n            variances = bn.nanvar(x, axis=axis)\n        else:\n            if axis == 0:\n                weights = weights.reshape(-1, 1)\n            elif axis == 1:\n                weights = weights.reshape(1, -1)\n            else:\n                raise NotImplementedError\n\n            nanw = ~np.isnan(x) * weights  # do not divide by non-used weights\n            wsum = np.sum(nanw, axis=axis)\n            means = bn.nansum(x * weights, axis=axis) / wsum\n\n            if axis == 0:\n                mr = means.reshape(1, -1)\n            elif axis == 1:\n                mr = means.reshape(-1, 1)\n\n            variances = bn.nansum(((x - mr) ** 2) * weights, axis=axis) / wsum\n    else:\n        # mean_variance_axis is picky regarding the input type\n        if weights is not None:\n            weights = weights.astype(float)\n        means, variances = mean_variance_axis(x, axis=axis, weights=weights)\n\n    return means, variances\n\n\ndef nanvar(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.nanvar that supports sparse or dense matrices. \"\"\"\n    def nanvar_sparse(x):\n        n_vals = np.prod(x.shape) - np.sum(np.isnan(x.data))\n        n_zeros = np.prod(x.shape) - len(x.data)\n        avg = np.nansum(x.data) / n_vals\n        return (np.nansum((x.data - avg) ** 2) + avg ** 2 * n_zeros) / (n_vals - ddof)\n\n    return _apply_func(x, bn.nanvar, nanvar_sparse, axis=axis)\n\n\ndef nanstd(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.nanstd that supports sparse and dense matrices. \"\"\"\n    return np.sqrt(nanvar(x, axis=axis, ddof=ddof))\n\n\ndef nanmedian(x, axis=None):\n    \"\"\" Equivalent of np.nanmedian that supports sparse or dense matrices. \"\"\"\n    def nanmedian_sparse(x):\n        nz = np.logical_not(np.isnan(x.data))\n        n_nan = sum(np.isnan(x.data))\n        n_nonzero = sum(x.data[nz] != 0)\n        n_zeros = np.prod(x.shape) - n_nonzero - n_nan\n        if n_zeros > n_nonzero:\n            # Typical case if use of sparse matrices make sense\n            return 0\n        else:\n            # Possibly contains NaNs and\n            # more nz values than zeros, so allocating memory should not be too problematic\n            return np.nanmedian(x.toarray())\n\n    return _apply_func(x, np.nanmedian, nanmedian_sparse, axis=axis)\n\n\ndef nanmode(x, axis=0):\n    \"\"\" A temporary replacement for a scipy.stats.mode.\n\n    This function returns mode NaN if all values are NaN (scipy<1.2.0 wrongly\n    returns zero). Also, this function returns count NaN if all values are NaN\n    (scipy=1.3.0 returns some number).\"\"\"\n    nans = np.isnan(np.array(x)).sum(axis=axis, keepdims=True) == x.shape[axis]\n    res = scipy.stats.mode(x, axis, keepdims=True)\n    # type(res) is ModeResult. ModeResult is defined in scipy.stats.stats; this\n    # namespace is deprecated, but ModeResult is not exported to scipy.stats\n    # Hence we use type(res) to avoid a warning.\n    return type(res)(np.where(nans, np.nan, res.mode),\n                     np.where(nans, np.nan, res.count))\n\n\ndef unique(x, return_counts=False):\n    \"\"\" Equivalent of np.unique that supports sparse or dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.unique(x, return_counts=return_counts)\n\n    implicit_zeros = sparse_count_implicit_zeros(x)\n    explicit_zeros = not np.all(x.data)\n    r = np.unique(x.data, return_counts=return_counts)\n    if not implicit_zeros:\n        return r\n\n    if return_counts:\n        zero_index = np.searchsorted(r[0], 0)\n        if explicit_zeros:\n            r[1][r[0] == 0.] += implicit_zeros\n            return r\n        return np.insert(r[0], zero_index, 0), np.insert(r[1], zero_index, implicit_zeros)\n    else:\n        if explicit_zeros:\n            return r\n        zero_index = np.searchsorted(r, 0)\n        return np.insert(r, zero_index, 0)\n\n\ndef nanunique(*args, **kwargs):\n    \"\"\" Return unique values while disregarding missing (np.nan) values.\n    Supports sparse or dense matrices. \"\"\"\n    result = unique(*args, **kwargs)\n\n    if isinstance(result, tuple):\n        result, counts = result\n        non_nan_mask = ~np.isnan(result)\n        return result[non_nan_mask], counts[non_nan_mask]\n\n    return result[~np.isnan(result)]\n\n\ndef digitize(x, bins, right=False):\n    \"\"\"Equivalent of np.digitize that supports sparse and dense matrices.\n\n    If a sparse matrix is provided and the '0's belong to the '0'th bin, then\n    a sparse matrix is returned.\n\n    Because this can return both sparse and dense matrices, we must keep the\n    return shape consistent. Since sparse matrices don't support 1d matrices,\n    we reshape any returned 1d numpy array to a 2d matrix, with the first\n    dimension shape being 1. This is equivalent to the behaviour of sparse\n    matrices.\n\n    Parameters\n    ----------\n    x : Union[np.ndarry, sp.csr_matrix, sp.csc_matrix]\n    bins : np.ndarray\n    right : Optional[bool]\n\n    Returns\n    -------\n    Union[np.ndarray, sp.csr_matrix]\n\n    \"\"\"\n    if not sp.issparse(x):\n        # TODO Remove reshaping logic when support for numpy==1.9 is dropped\n        original_shape = x.shape\n        x = x.flatten()\n        result = np.digitize(x, bins, right)\n        result = result.reshape(original_shape)\n        # In order to keep the return shape consistent, and sparse matrices\n        # don't support 1d matrices, make sure to convert 1d to 2d matrices\n        if result.ndim == 1:\n            result = result.reshape(((1,) + result.shape))\n        return result\n\n    # Find the bin where zeros belong, depending on the `right` parameter\n    zero_bin = np.searchsorted(bins, 0, side=['right', 'left'][right])\n\n    if zero_bin == 0:\n        r = sp.lil_matrix(x.shape, dtype=np.int64)\n    else:\n        r = zero_bin * np.ones(x.shape, dtype=np.int64)\n\n    for idx, row in enumerate(x.tocsr()):\n        # TODO Remove this check when support for numpy==1.9 is dropped\n        if row.nnz > 0:\n            r[idx, row.indices] = np.digitize(row.data, bins, right)\n\n    # Orange mainly deals with `csr_matrix`, but `lil_matrix` is more efficient\n    # for incremental building\n    if sp.issparse(r):\n        r = r.tocsr()\n\n    return r\n\n\ndef var(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.var that supports sparse and dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.var(x, axis, ddof=ddof)\n\n    result = x.multiply(x).mean(axis) - np.square(x.mean(axis))\n    result = np.squeeze(np.asarray(result))\n\n    # Apply correction for degrees of freedom\n    n = np.prod(x.shape) if axis is None else x.shape[axis]\n    result *= n / (n - ddof)\n\n    return result\n\n\ndef std(x, axis=None, ddof=0):\n    \"\"\" Equivalent of np.std that supports sparse and dense matrices. \"\"\"\n    return np.sqrt(var(x, axis=axis, ddof=ddof))\n\n\ndef nan_to_num(x, copy=True):\n    \"\"\" Equivalent of np.nan_to_num that supports sparse and dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.nan_to_num(x, copy=copy)\n\n    if copy:\n        x = x.copy()\n    np.nan_to_num(x.data, copy=False)\n    _eliminate_zeros(x)\n    return x\n\n\ndef isnan(x, out=None):\n    \"\"\" Equivalent of np.isnan that supports sparse and dense matrices. \"\"\"\n    if not sp.issparse(x):\n        return np.isnan(x, out=out)\n\n    if out is None:\n        x = x.copy()\n    elif out is not x:\n        raise ValueError(\n            \"The `out` parameter can only be set `x` when using sparse matrices\"\n        )\n\n    np.isnan(x.data, out=x.data)\n    _eliminate_zeros(x)\n    return x\n\n\ndef any_nan(x, axis=None):\n    \"\"\" Check if any of the values in a matrix is nan. \"\"\"\n    if not sp.issparse(x):\n        return np.isnan(x).any(axis=axis)\n\n    if axis is None:\n        return np.isnan(x.data).any()\n\n    if axis == 0:\n        x = x.tocsc()\n    elif axis == 1:\n        x = x.tocsr()\n\n    ax = x.ndim - axis - 1\n    result = np.zeros(x.shape[ax], dtype=bool)\n    for i in range(x.shape[ax]):\n        vals = x.data[x.indptr[i]:x.indptr[i + 1]]\n        result[i] = np.isnan(vals).any()\n\n    return result\n\n\ndef all_nan(x, axis=None):\n    \"\"\"\n    Check if all of the values in a matrix is nan. Works for sparse matrix too.\n    \"\"\"\n    if not sp.issparse(x):\n        return np.isnan(x).all(axis=axis)\n\n    if axis is None:\n        # when x.nnz < actual shape there are zero values which are not nan\n        return np.prod(x.shape) == x.nnz and np.isnan(x.data).all()\n\n    if axis == 0:\n        x = x.tocsc()\n    elif axis == 1:\n        x = x.tocsr()\n\n    ax = x.ndim - axis - 1\n    axis_len = x.shape[axis]\n    result = np.zeros(x.shape[ax], dtype=bool)\n    for i in range(x.shape[ax]):\n        vals = x.data[x.indptr[i]:x.indptr[i + 1]]\n        result[i] = axis_len == len(vals) and np.isnan(vals).all()\n\n    return result\n\n\ndef FDR(p_values: Iterable, dependent=False, m=None, ordered=False) -> Iterable:\n    \"\"\" `False Discovery Rate <http://en.wikipedia.org/wiki/False_discovery_rate>`_\n        correction on a list of p-values.\n\n    :param p_values: list or np.ndarray of p-values.\n    :param dependent: use correction for dependent hypotheses (default False).\n    :param m: number of hypotheses tested (default ``len(p_values)``).\n    :param ordered: prevent sorting of p-values if they are already sorted\n        (default False).\n    :return: list or np.ndarray, same as the input\n    \"\"\"\n    if p_values is None or len(p_values) == 0 or \\\n            (m is not None and m <= 0):\n        return None\n\n    is_list = isinstance(p_values, list)\n    p_values = np.array(p_values)\n    if m is None:\n        m = len(p_values)\n    if not ordered:\n        ordered = (np.diff(p_values) >= 0).all()\n        if not ordered:\n            indices = np.argsort(p_values)\n            p_values = p_values[indices]\n\n    if dependent:  # correct q for dependent tests\n        m *= sum(1 / np.arange(1, m + 1))\n\n    fdrs = (p_values * m / np.arange(1, len(p_values) + 1))[::-1]\n    fdrs = np.array(np.minimum.accumulate(fdrs)[::-1])\n    if not ordered:\n        fdrs[indices] = fdrs.copy()\n    return fdrs if not is_list else list(fdrs)\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Statistics Utility Incorrectly Counts Zeros as NaNs, Leading to Inaccurate Calculations

**Description:**
In the statistical utilities, zeros are being mistakenly counted as NaN (Not a Number) values. This miscount affects the accuracy of statistical measures such as mean, variance, and the count of valid entries.

**Example:**
When processing a sparse identity matrix, zeros should be recognized as valid numerical values, not as NaNs.

```python
import numpy as np
from scipy.sparse import csr_matrix
from Orange.statistics.util import stats

X = csr_matrix(np.identity(5))
result = stats(X)
print(result)
```

**Expected Behavior:**
Zeros should be treated as legitimate numerical entries. The NaN count should accurately reflect only the actual NaN values present in the data.

**Actual Behavior:**
Zeros are incorrectly identified as NaNs, resulting in inflated NaN counts and reduced counts of valid numerical entries. This leads to incorrect statistical outcomes.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### Orange/statistics/util.py
"""
This module provides alternatives for the few additional functions found in
and once used from the bottlechest package (fork of bottleneck).

It also patches bottleneck to contain these functions.
"""
import warnings
from typing import Iterable

import bottleneck as bn
import numpy as np
import pandas
import scipy.stats.stats
from scipy import sparse as sp

from sklearn.utils.sparsefuncs import mean_variance_axis


def _eliminate_zeros(x):
    """Eliminate zeros from sparse matrix, or raise appropriate warning."""
    if hasattr(x, "eliminate_zeros"):
        x.eliminate_zeros()
    else:
        warnings.warn(
            f"`{x.__type__}` does not implement `eliminate_zeros`. Some values "
            f"in the sparse matrix may by explicit zeros."
        )


def _count_nans_per_row_sparse(X, weights, dtype=None):
    """ Count the number of nans (undefined) values per row. """
    if weights is not None:
        X = X.tocoo(copy=False)
        nonzero_mask = np.isnan(X.data)
        nan_rows, nan_cols = X.row[nonzero_mask], X.col[nonzero_mask]

        if weights.ndim == 1:
            data_weights = weights[nan_rows]
        else:
            data_weights = weights[nan_rows, nan_cols]

        w = sp.coo_matrix((data_weights, (nan_rows, nan_cols)), shape=X.shape)
        w = w.tocsr()
        return np.asarray(w.sum(axis=1), dtype=dtype).ravel()

    if isinstance(X, (sp.csr_matrix, sp.csc_matrix)):
        X = type(X)((np.isnan(X.data), X.indices, X.indptr), X.shape)
        return np.asarray(X.sum(axis=1), dtype=dtype).ravel()
    else:  # pragma: no cover
        raise TypeError("unsupported type '{}'".format(type(X).__name__))


def sparse_count_implicit_zeros(x):
    """ Count the number of implicit zeros in a sparse matrix. """
    if not sp.issparse(x):
        raise TypeError('The matrix provided was not sparse.')
    return np.prod(x.shape) - x.nnz


def sparse_has_implicit_zeros(x):
    """ Check if sparse matrix contains any implicit zeros. """
    if not sp.issparse(x):
        raise TypeError('The matrix provided was not sparse.')
    return np.prod(x.shape) != x.nnz


def sparse_implicit_zero_weights(x, weights):
    """ Extract the weight values of all zeros in a sparse matrix. """
    if not sp.issparse(x):
        raise TypeError('The matrix provided was not sparse.')

    if weights.ndim == 1:
        # Match weights and x axis so `indices` will be set appropriately
        if x.shape[0] == weights.shape[0]:
            x = x.tocsc()
        elif x.shape[1] == weights.shape[0]:
            x = x.tocsr()
        n_items = np.prod(x.shape)
        zero_indices = np.setdiff1d(np.arange(n_items), x.indices, assume_unique=True)
        return weights[zero_indices]
    else:
        # Can easily be implemented using a coo_matrix
        raise NotImplementedError(
            'Computing zero weights on ndimensinal weight matrix is not implemented'
        )


def bincount(x, weights=None, max_val=None, minlength=0):
    """Return counts of values in array X.

    Works kind of like np.bincount(), except that it also supports
    arrays with nans.

    Parameters
    ----------
    x : array_like, 1 dimension, nonnegative ints
        Input array.
    weights : array_like, optional
        Weights, array of the same shape as x.
    max_val : int, optional
        Indicates the maximum value we expect to find in X and sets the result
        array size accordingly. E.g. if we set `max_val=2` yet the largest
        value in X is 1, the result will contain a bin for the value 2, and
        will be set to 0. See examples for usage.
    minlength : int, optional
        A minimum number of bins for the output array. See numpy docs for info.

    Returns
    -------
    Tuple[np.ndarray, int]
        Returns the bincounts and the number of NaN values.

    Examples
    --------
    In case `max_val` is provided, the return shape includes bins for these
    values as well, even if they do not appear in the data. However, this will
    not truncate the bincount if values larger than `max_count` are found.
    >>> bincount([0, 0, 1, 1, 2], max_val=4)
    (array([ 2.,  2.,  1.,  0.,  0.]), 0.0)
    >>> bincount([0, 1, 2, 3, 4], max_val=2)
    (array([ 1.,  1.,  1.,  1.,  1.]), 0.0)

    """
    # Store the original matrix before any manipulation to check for sparse
    x_original = x
    if sp.issparse(x):
        if weights is not None:
            # Match weights and x axis so `indices` will be set appropriately
            if x.shape[0] == weights.shape[0]:
                x = x.tocsc()
            elif x.shape[1] == weights.shape[0]:
                x = x.tocsr()

            zero_weights = sparse_implicit_zero_weights(x, weights).sum()
            weights = weights[x.indices]
        else:
            zero_weights = sparse_count_implicit_zeros(x)

        x = x.data

    x = np.asanyarray(x, dtype=float)
    if bn.anynan(x):
        nonnan = ~np.isnan(x)
        x = x[nonnan]
        if weights is not None:
            nans = (~nonnan * weights).sum(axis=0)
            weights = weights[nonnan]
        else:
            nans = (~nonnan).sum(axis=0)
    else:
        nans = 0. if x.ndim == 1 else np.zeros(x.shape[1], dtype=float)

    if minlength == 0 and max_val is not None:
        minlength = max_val + 1

    bc = np.bincount(
        x.astype(np.int32, copy=False), weights=weights, minlength=minlength
    ).astype(float)
    # Since `csr_matrix.values` only contain non-zero values or explicit
    # zeros, we must count implicit zeros separately and add them to the
    # explicit ones found before
    if sp.issparse(x_original):
        # If x contains only NaNs, then bc will be an empty array
        if zero_weights and bc.size == 0:
            bc = [zero_weights]
        elif zero_weights:
            bc[0] += zero_weights

    return bc, nans


def countnans(x, weights=None, axis=None, dtype=None, keepdims=False):
    """
    Count the undefined elements in an array along given axis.

    Parameters
    ----------
    x : array_like
    weights : array_like, optional
        Weights to weight the nans with, before or after counting (depending
        on the weights shape).
    axis : int, optional
    dtype : dtype, optional
        The data type of the returned array.

    Returns
    -------
    Union[np.ndarray, float]

    """
    if not sp.issparse(x):
        x = np.asanyarray(x)
        is_nan = np.isnan(x)
        if weights is not None and weights.shape == x.shape:
            is_nan = is_nan * weights

        counts = is_nan.sum(axis=axis, dtype=dtype, keepdims=keepdims)
        if weights is not None and weights.shape != x.shape:
            counts = counts * weights
    else:
        assert axis in [None, 0, 1], 'Only axis 0 and 1 are currently supported'
        # To have consistent behaviour with dense matrices, raise error when
        # `axis=1` and the array is 1d (e.g. [[1 2 3]])
        if x.shape[0] == 1 and axis == 1:
            raise ValueError('Axis %d is out of bounds' % axis)

        arr = x if axis == 1 else x.T

        if weights is not None:
            weights = weights if axis == 1 else weights.T

        arr = arr.tocsr()
        counts = _count_nans_per_row_sparse(arr, weights, dtype=dtype)

        # We want a scalar value if `axis=None` or if the sparse matrix is
        # actually a vector (e.g. [[1 2 3]]), but has `ndim=2` due to scipy
        # implementation
        if axis is None or x.shape[0] == 1:
            counts = counts.sum(dtype=dtype)

    return counts


def contingency(X, y, max_X=None, max_y=None, weights=None, mask=None):
    """
    Compute the contingency matrices for each column of X (excluding the masked)
    versus the vector y.

    If the array is 1-dimensional, a 2d contingency matrix is returned. If the
    array is 2d, the function returns a 3d array, with the first dimension
    corresponding to column index (variable in the input array).

    The column of contingency matrix correspond to values of variables, the
    row correspond to values in vector `y`.

    Rows in the input array can be weighted (argument `weights`). A subset of
    columns can be selected by additional argument `mask`.

    The function also returns a count of NaN values per each value of `y`.

    Parameters
    ----------
    X : array_like
        With values in columns.
    y : 1d array
        Vector of true values.
    max_X : int
        The maximal value in the array
    max_y : int
        The maximal value in `y`
    weights : array_like
        Row weights. When not None, contingencies contain weighted counts
    mask : sequence
        Discrete columns of X.

    Returns
    -------
    contingencies: (m × ny × nx) array
        m number of masked (used) columns (all if mask=None), i.e.
        for each column of X;
        ny number of uniques in y,
        nx number of uniques in column of X.
    nans_cols : array_like
        Number of nans in each column of X for each unique value of y.
    nans_rows : array_like
        Number of nans in y for each unique value in columns of X.
    nans : array_like
        Number of nans in column of X and y at the same time.
    """
    was_1d = False
    if X.ndim == 1:
        X = X[..., np.newaxis]
        was_1d = True

    contingencies, nans_cols, nans_rows, nans = [], [], [], []
    ny = np.unique(y).size if max_y is None else max_y + 1
    for i in range(X.shape[1]):
        if mask is not None and not mask[i]:
            contingencies.append(np.zeros((ny, max_X + 1)))
            nans_cols.append(np.zeros(ny))
            nans_rows.append(None)
            nans.append(0)
            continue
        col = X[..., i]
        nx = np.unique(col[~np.isnan(col)]).size if max_X is None else max_X + 1
        if sp.issparse(col):
            col = np.ravel(col.todense())
        contingencies.append(
            bincount(y + ny * col,
                     minlength=ny * nx,
                     weights=weights)[0].reshape(nx, ny).T)

        nan_col_mask = np.isnan(col)
        nan_row_mask = np.isnan(y)
        nan_mask = nan_col_mask & nan_row_mask
        weights_ = np.ones(len(y)) if weights is None else weights

        nans_cols.append(
            bincount(y[nan_col_mask], weights=weights_[nan_col_mask],
                     minlength=ny)[0])
        nans_rows.append(
            bincount(col[nan_row_mask], weights=weights_[nan_row_mask],
                     minlength=nx)[0])
        nans.append(np.sum(nan_mask * weights_))
    if was_1d:
        return contingencies[0], nans_cols[0], nans_rows[0], nans[0]
    return np.array(contingencies), np.array(nans_cols), nans_rows, nans


def stats(X, weights=None, compute_variance=False):
    """
    Compute min, max, #nans, mean and variance.

    Result is a tuple (min, max, mean, variance, #nans, #non-nans) or an
    array of shape (len(X), 6).

    The mean and the number of nans and non-nans are weighted.

    Computation of variance requires an additional pass and is not enabled
    by default. Zeros are filled in instead of variance.

    Parameters
    ----------
    X : array_like, 1 or 2 dimensions
        Input array.
    weights : array_like, optional
        Weights, array of the same length as `x`.
    compute_variance : bool, optional
        If set to True, the function also computes variance.

    Returns
    -------
    out : a 6-element tuple or an array of shape (len(x), 6)
        Computed (min, max, mean, variance or 0, #nans, #non-nans)

    Raises
    ------
    ValueError
        If the length of the weight vector does not match the length of the
        array
    """
    is_numeric = np.issubdtype(X.dtype, np.number)
    is_sparse = sp.issparse(X)

    if X.size and is_numeric:
        if is_sparse:
            X = X.tocsc()
        if compute_variance:
            means, vars = nan_mean_var(X, axis=0, weights=weights)
        else:
            means = nanmean(X, axis=0, weights=weights)
            vars = np.zeros(X.shape[1] if X.ndim == 2 else 1)

    if X.size and is_numeric and not is_sparse:
        nans = np.isnan(X).sum(axis=0)
        return np.column_stack((
            np.nanmin(X, axis=0),
            np.nanmax(X, axis=0),
            means,
            vars,
            nans,
            X.shape[0] - nans))
    elif is_sparse and X.size:
        non_zero = np.bincount(X.nonzero()[1], minlength=X.shape[1])
        return np.column_stack((
            nanmin(X, axis=0),
            nanmax(X, axis=0),
            means,
            vars,
            X.shape[0] - non_zero,
            non_zero))
    else:
        if X.ndim == 1:
            X = X[:, None]
        nans = (pandas.isnull(X).sum(axis=0) + (X == "").sum(axis=0)) \
            if X.size else np.zeros(X.shape[1])
        return np.column_stack((
            np.tile(np.inf, X.shape[1]),
            np.tile(-np.inf, X.shape[1]),
            np.zeros(X.shape[1]),
            np.zeros(X.shape[1]),
            nans,
            X.shape[0] - nans))


def _nan_min_max(x, func, axis=0):
    if not sp.issparse(x):
        return func(x, axis=axis)
    if axis is None:
        extreme = func(x.data, axis=axis) if x.nnz else float('nan')
        if sparse_has_implicit_zeros(x):
            extreme = func([0, extreme])
        return extreme
    if axis == 0:
        x = x.T
    else:
        assert axis == 1

    # TODO check & transform to correct format
    r = []
    for row in x:
        values = row.data
        extreme = func(values) if values.size else float('nan')
        if sparse_has_implicit_zeros(row):
            extreme = func([0, extreme])
        r.append(extreme)
    return np.array(r)


def nanmin(x, axis=None):
    """ Equivalent of np.nammin that supports sparse or dense matrices. """
    return _nan_min_max(x, np.nanmin, axis)


def nanmax(x, axis=None):
    """ Equivalent of np.nammax that supports sparse or dense matrices. """
    return _nan_min_max(x, np.nanmax, axis)


def mean(x):
    """ Equivalent of np.mean that supports sparse or dense matrices. """
    m = (np.sum(x.data) / np.prod(x.shape)
         if sp.issparse(x) else
         np.mean(x))
    if np.isnan(m):
        warnings.warn('mean() resulted in nan. If input can contain nan values,'
                      ' perhaps you meant nanmean?', stacklevel=2)
    return m


def _apply_func(x, dense_func, sparse_func, axis=None):
    """ General wrapper for a function depending on sparse or dense matrices. """
    if not sp.issparse(x):
        return dense_func(x, axis=axis)
    if axis is None:
        return sparse_func(x)
    if axis in [0, 1]:
        arr = x if axis == 1 else x.T
        arr = arr.tocsr()
        return np.fromiter((sparse_func(row) for row in arr),
                           dtype=np.double, count=arr.shape[0])
    else:
        raise NotImplementedError


def nansum(x, axis=None):
    """ Equivalent of np.nansum that supports sparse or dense matrices. """
    def nansum_sparse(x):
        return np.nansum(x.data)

    return _apply_func(x, np.nansum, nansum_sparse, axis=axis)


def nanmean(x, axis=None, weights=None):
    """ Equivalent of np.nanmean that supports sparse or dense matrices. """
    if axis is None and weights is not None:
        raise NotImplementedError("weights are only supported if axis is defined")

    if not sp.issparse(x):
        if weights is None:
            means = bn.nanmean(x, axis=axis)
        else:
            if axis == 0:
                weights = weights.reshape(-1, 1)
            elif axis == 1:
                weights = weights.reshape(1, -1)
            else:
                raise NotImplementedError
            nanw = ~np.isnan(x) * weights  # do not divide by non-used weights
            means = bn.nansum(x * weights, axis=axis) / np.sum(nanw, axis=axis)
    elif axis is None:
        means, _ = mean_variance_axis(x, axis=0)
        means = np.nanmean(means)
    else:
        # mean_variance_axis is picky regarding the input type
        if weights is not None:
            weights = weights.astype(float)
        means, _ = mean_variance_axis(x, axis=axis, weights=weights)

    return means


def nan_mean_var(x, axis=None, weights=None):
    """
    Computes means and variance of dense and sparse matrices.
    Supports weights. Based on mean_variance_axis.
    """
    if axis is None:
        raise NotImplementedError("axis=None is not supported")

    if not sp.issparse(x):
        if weights is None:
            means = bn.nanmean(x, axis=axis)
            variances = bn.nanvar(x, axis=axis)
        else:
            if axis == 0:
                weights = weights.reshape(-1, 1)
            elif axis == 1:
                weights = weights.reshape(1, -1)
            else:
                raise NotImplementedError

            nanw = ~np.isnan(x) * weights  # do not divide by non-used weights
            wsum = np.sum(nanw, axis=axis)
            means = bn.nansum(x * weights, axis=axis) / wsum

            if axis == 0:
                mr = means.reshape(1, -1)
            elif axis == 1:
                mr = means.reshape(-1, 1)

            variances = bn.nansum(((x - mr) ** 2) * weights, axis=axis) / wsum
    else:
        # mean_variance_axis is picky regarding the input type
        if weights is not None:
            weights = weights.astype(float)
        means, variances = mean_variance_axis(x, axis=axis, weights=weights)

    return means, variances


def nanvar(x, axis=None, ddof=0):
    """ Equivalent of np.nanvar that supports sparse or dense matrices. """
    def nanvar_sparse(x):
        n_vals = np.prod(x.shape) - np.sum(np.isnan(x.data))
        n_zeros = np.prod(x.shape) - len(x.data)
        avg = np.nansum(x.data) / n_vals
        return (np.nansum((x.data - avg) ** 2) + avg ** 2 * n_zeros) / (n_vals - ddof)

    return _apply_func(x, bn.nanvar, nanvar_sparse, axis=axis)


def nanstd(x, axis=None, ddof=0):
    """ Equivalent of np.nanstd that supports sparse and dense matrices. """
    return np.sqrt(nanvar(x, axis=axis, ddof=ddof))


def nanmedian(x, axis=None):
    """ Equivalent of np.nanmedian that supports sparse or dense matrices. """
    def nanmedian_sparse(x):
        nz = np.logical_not(np.isnan(x.data))
        n_nan = sum(np.isnan(x.data))
        n_nonzero = sum(x.data[nz] != 0)
        n_zeros = np.prod(x.shape) - n_nonzero - n_nan
        if n_zeros > n_nonzero:
            # Typical case if use of sparse matrices make sense
            return 0
        else:
            # Possibly contains NaNs and
            # more nz values than zeros, so allocating memory should not be too problematic
            return np.nanmedian(x.toarray())

    return _apply_func(x, np.nanmedian, nanmedian_sparse, axis=axis)


def nanmode(x, axis=0):
    """ A temporary replacement for a scipy.stats.mode.

    This function returns mode NaN if all values are NaN (scipy<1.2.0 wrongly
    returns zero). Also, this function returns count NaN if all values are NaN
    (scipy=1.3.0 returns some number)."""
    nans = np.isnan(np.array(x)).sum(axis=axis, keepdims=True) == x.shape[axis]
    res = scipy.stats.mode(x, axis, keepdims=True)
    # type(res) is ModeResult. ModeResult is defined in scipy.stats.stats; this
    # namespace is deprecated, but ModeResult is not exported to scipy.stats
    # Hence we use type(res) to avoid a warning.
    return type(res)(np.where(nans, np.nan, res.mode),
                     np.where(nans, np.nan, res.count))


def unique(x, return_counts=False):
    """ Equivalent of np.unique that supports sparse or dense matrices. """
    if not sp.issparse(x):
        return np.unique(x, return_counts=return_counts)

    implicit_zeros = sparse_count_implicit_zeros(x)
    explicit_zeros = not np.all(x.data)
    r = np.unique(x.data, return_counts=return_counts)
    if not implicit_zeros:
        return r

    if return_counts:
        zero_index = np.searchsorted(r[0], 0)
        if explicit_zeros:
            r[1][r[0] == 0.] += implicit_zeros
            return r
        return np.insert(r[0], zero_index, 0), np.insert(r[1], zero_index, implicit_zeros)
    else:
        if explicit_zeros:
            return r
        zero_index = np.searchsorted(r, 0)
        return np.insert(r, zero_index, 0)


def nanunique(*args, **kwargs):
    """ Return unique values while disregarding missing (np.nan) values.
    Supports sparse or dense matrices. """
    result = unique(*args, **kwargs)

    if isinstance(result, tuple):
        result, counts = result
        non_nan_mask = ~np.isnan(result)
        return result[non_nan_mask], counts[non_nan_mask]

    return result[~np.isnan(result)]


def digitize(x, bins, right=False):
    """Equivalent of np.digitize that supports sparse and dense matrices.

    If a sparse matrix is provided and the '0's belong to the '0'th bin, then
    a sparse matrix is returned.

    Because this can return both sparse and dense matrices, we must keep the
    return shape consistent. Since sparse matrices don't support 1d matrices,
    we reshape any returned 1d numpy array to a 2d matrix, with the first
    dimension shape being 1. This is equivalent to the behaviour of sparse
    matrices.

    Parameters
    ----------
    x : Union[np.ndarry, sp.csr_matrix, sp.csc_matrix]
    bins : np.ndarray
    right : Optional[bool]

    Returns
    -------
    Union[np.ndarray, sp.csr_matrix]

    """
    if not sp.issparse(x):
        # TODO Remove reshaping logic when support for numpy==1.9 is dropped
        original_shape = x.shape
        x = x.flatten()
        result = np.digitize(x, bins, right)
        result = result.reshape(original_shape)
        # In order to keep the return shape consistent, and sparse matrices
        # don't support 1d matrices, make sure to convert 1d to 2d matrices
        if result.ndim == 1:
            result = result.reshape(((1,) + result.shape))
        return result

    # Find the bin where zeros belong, depending on the `right` parameter
    zero_bin = np.searchsorted(bins, 0, side=['right', 'left'][right])

    if zero_bin == 0:
        r = sp.lil_matrix(x.shape, dtype=np.int64)
    else:
        r = zero_bin * np.ones(x.shape, dtype=np.int64)

    for idx, row in enumerate(x.tocsr()):
        # TODO Remove this check when support for numpy==1.9 is dropped
        if row.nnz > 0:
            r[idx, row.indices] = np.digitize(row.data, bins, right)

    # Orange mainly deals with `csr_matrix`, but `lil_matrix` is more efficient
    # for incremental building
    if sp.issparse(r):
        r = r.tocsr()

    return r


def var(x, axis=None, ddof=0):
    """ Equivalent of np.var that supports sparse and dense matrices. """
    if not sp.issparse(x):
        return np.var(x, axis, ddof=ddof)

    result = x.multiply(x).mean(axis) - np.square(x.mean(axis))
    result = np.squeeze(np.asarray(result))

    # Apply correction for degrees of freedom
    n = np.prod(x.shape) if axis is None else x.shape[axis]
    result *= n / (n - ddof)

    return result


def std(x, axis=None, ddof=0):
    """ Equivalent of np.std that supports sparse and dense matrices. """
    return np.sqrt(var(x, axis=axis, ddof=ddof))


def nan_to_num(x, copy=True):
    """ Equivalent of np.nan_to_num that supports sparse and dense matrices. """
    if not sp.issparse(x):
        return np.nan_to_num(x, copy=copy)

    if copy:
        x = x.copy()
    np.nan_to_num(x.data, copy=False)
    _eliminate_zeros(x)
    return x


def isnan(x, out=None):
    """ Equivalent of np.isnan that supports sparse and dense matrices. """
    if not sp.issparse(x):
        return np.isnan(x, out=out)

    if out is None:
        x = x.copy()
    elif out is not x:
        raise ValueError(
            "The `out` parameter can only be set `x` when using sparse matrices"
        )

    np.isnan(x.data, out=x.data)
    _eliminate_zeros(x)
    return x


def any_nan(x, axis=None):
    """ Check if any of the values in a matrix is nan. """
    if not sp.issparse(x):
        return np.isnan(x).any(axis=axis)

    if axis is None:
        return np.isnan(x.data).any()

    if axis == 0:
        x = x.tocsc()
    elif axis == 1:
        x = x.tocsr()

    ax = x.ndim - axis - 1
    result = np.zeros(x.shape[ax], dtype=bool)
    for i in range(x.shape[ax]):
        vals = x.data[x.indptr[i]:x.indptr[i + 1]]
        result[i] = np.isnan(vals).any()

    return result


def all_nan(x, axis=None):
    """
    Check if all of the values in a matrix is nan. Works for sparse matrix too.
    """
    if not sp.issparse(x):
        return np.isnan(x).all(axis=axis)

    if axis is None:
        # when x.nnz < actual shape there are zero values which are not nan
        return np.prod(x.shape) == x.nnz and np.isnan(x.data).all()

    if axis == 0:
        x = x.tocsc()
    elif axis == 1:
        x = x.tocsr()

    ax = x.ndim - axis - 1
    axis_len = x.shape[axis]
    result = np.zeros(x.shape[ax], dtype=bool)
    for i in range(x.shape[ax]):
        vals = x.data[x.indptr[i]:x.indptr[i + 1]]
        result[i] = axis_len == len(vals) and np.isnan(vals).all()

    return result


def FDR(p_values: Iterable, dependent=False, m=None, ordered=False) -> Iterable:
    """ `False Discovery Rate <http://en.wikipedia.org/wiki/False_discovery_rate>`_
        correction on a list of p-values.

    :param p_values: list or np.ndarray of p-values.
    :param dependent: use correction for dependent hypotheses (default False).
    :param m: number of hypotheses tested (default ``len(p_values)``).
    :param ordered: prevent sorting of p-values if they are already sorted
        (default False).
    :return: list or np.ndarray, same as the input
    """
    if p_values is None or len(p_values) == 0 or \
            (m is not None and m <= 0):
        return None

    is_list = isinstance(p_values, list)
    p_values = np.array(p_values)
    if m is None:
        m = len(p_values)
    if not ordered:
        ordered = (np.diff(p_values) >= 0).all()
        if not ordered:
            indices = np.argsort(p_values)
            p_values = p_values[indices]

    if dependent:  # correct q for dependent tests
        m *= sum(1 / np.arange(1, m + 1))

    fdrs = (p_values * m / np.arange(1, len(p_values) + 1))[::-1]
    fdrs = np.array(np.minimum.accumulate(fdrs)[::-1])
    if not ordered:
        fdrs[indices] = fdrs.copy()
    return fdrs if not is_list else list(fdrs)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user