Repository: scipy/scipy
File: scipy/stats/_stats_py.py (Python)

Code before:
        """
        Parameters
        ----------
        confidence_level : float
            The confidence level for the calculation of the population mean
            confidence interval. Default is 0.95.

        Returns
        -------
        ci : namedtuple
            The confidence interval is returned in a ``namedtuple`` with
            fields `low` and `high`.

        """
        low, high = _t_confidence_interval(self.df, self._statistic_np,
                                           confidence_level, self._alternative,
                                           self._dtype, self._xp)
        low = low * self._standard_error + self._estimate
        high = high * self._standard_error + self._estimate
        return ConfidenceInterval(low=low, high=high)


def pack_TtestResult(statistic, pvalue, df, alternative, standard_error,
                     estimate):
    # this could be any number of dimensions (including 0d), but there is
    # at most one unique non-NaN value
    xp = array_namespace(statistic, pvalue)
    alternative = xpx.atleast_nd(xp.asarray(alternative), ndim=1, xp=xp)
    alternative = (_xp_mean(alternative, axis=None, nan_policy='omit', warn=False)
                   if xp_size(alternative) != 0 else xp.nan)
    return TtestResult(statistic, pvalue, df=df, alternative=alternative,
                       standard_error=standard_error, estimate=estimate)


def unpack_TtestResult(res, _):
    return (res.statistic, res.pvalue, res.df, res._alternative,
            res._standard_error, res._estimate)


@xp_capabilities(cpu_only=True, exceptions=["cupy", "jax.numpy"])
@_axis_nan_policy_factory(pack_TtestResult, default_axis=0, n_samples=2,
                          result_to_tuple=unpack_TtestResult, n_outputs=6)
# nan_policy handled by `_axis_nan_policy`, but needs to be left
# in signature to preserve use as a positional argument
def ttest_1samp(a, popmean, axis=0, nan_policy="propagate", alternative="two-sided"):
    """Calculate the T-test for the mean of ONE group of scores.

    This is a test for the null hypothesis that the expected value
    (mean) of a sample of independent observations `a` is equal to the given
    population mean, `popmean`.


Review comment (refactor):
This comment is about the treatment of `alternative`. We do a little work-around for the sake of the `_axis_nan_policy` decorator, which expects all the attributes of the return object to be arrays of the same shape, but the result object needs a single value of the `alternative`.
```suggestion
    # at most one unique non-NaN value.
    # `_xp_mean` omitting NaNs is a JIT-compatible way to extract it.
```


Code after:
        """
        Parameters
        ----------
        confidence_level : float
            The confidence level for the calculation of the population mean
            confidence interval. Default is 0.95.

        Returns
        -------
        ci : namedtuple
            The confidence interval is returned in a ``namedtuple`` with
            fields `low` and `high`.

        """
        low, high = _t_confidence_interval(self.df, self._statistic_np,
                                           confidence_level, self._alternative,
                                           self._dtype, self._xp)
        low = low * self._standard_error + self._estimate
        high = high * self._standard_error + self._estimate
        return ConfidenceInterval(low=low, high=high)


def pack_TtestResult(statistic, pvalue, df, alternative, standard_error,
                     estimate):
    xp = array_namespace(statistic, pvalue)
    # Due to behavior of `_axis_nan_policy` decorator, `alternative` can be any number
    # of dimensions, but there is at most one unique non-NaN value.
    # `_xp_mean` with `nan_policy='omit'` is a JIT-compatible way to extract it.
    alternative = xp.asarray(alternative)
    alternative = (_xp_mean(alternative, axis=None, nan_policy='omit', warn=False)
                   if xp_size(alternative) != 0 else xp.nan)
    return TtestResult(statistic, pvalue, df=df, alternative=alternative,
                       standard_error=standard_error, estimate=estimate)


def unpack_TtestResult(res, _):
    return (res.statistic, res.pvalue, res.df, res._alternative,
            res._standard_error, res._estimate)


@xp_capabilities(cpu_only=True, exceptions=["cupy", "jax.numpy"])
@_axis_nan_policy_factory(pack_TtestResult, default_axis=0, n_samples=2,
                          result_to_tuple=unpack_TtestResult, n_outputs=6)
# nan_policy handled by `_axis_nan_policy`, but needs to be left
# in signature to preserve use as a positional argument
def ttest_1samp(a, popmean, axis=0, nan_policy="propagate", alternative="two-sided"):
    """Calculate the T-test for the mean of ONE group of scores.

    This is a test for the null hypothesis that the expected value
    (mean) of a sample of independent observations `a` is equal to the given
    population mean, `popmean`.