Skip to content

Commit 6acf136

Browse files
authored
Merge pull request scipy#21881 from mdhaber/stats_spec7
2 parents fcc1423 + 3bcf31d commit 6acf136

File tree

6 files changed

+100
-81
lines changed

6 files changed

+100
-81
lines changed

scipy/stats/_fit.py

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from collections import namedtuple
33
import numpy as np
44
from scipy import optimize, stats
5-
from scipy._lib._util import check_random_state
5+
from scipy._lib._util import check_random_state, _transition_to_rng
66

77

88
def _combine_bounds(name, user_bounds, shape_domain, integral):
@@ -738,9 +738,10 @@ def nlpsf(free_params, data=data): # bind data NOW
738738
'null_distribution'))
739739

740740

741+
@_transition_to_rng('random_state')
741742
def goodness_of_fit(dist, data, *, known_params=None, fit_params=None,
742743
guessed_params=None, statistic='ad', n_mc_samples=9999,
743-
random_state=None):
744+
rng=None):
744745
r"""
745746
Perform a goodness of fit test comparing data to a distribution family.
746747
@@ -797,18 +798,11 @@ def goodness_of_fit(dist, data, *, known_params=None, fit_params=None,
797798
The number of Monte Carlo samples drawn from the null hypothesized
798799
distribution to form the null distribution of the statistic. The
799800
sample size of each is the same as the given `data`.
800-
random_state : {None, int, `numpy.random.Generator`,
801-
`numpy.random.RandomState`}, optional
802-
803-
Pseudorandom number generator state used to generate the Monte Carlo
804-
samples.
805-
806-
If `random_state` is ``None`` (default), the
807-
`numpy.random.RandomState` singleton is used.
808-
If `random_state` is an int, a new ``RandomState`` instance is used,
809-
seeded with `random_state`.
810-
If `random_state` is already a ``Generator`` or ``RandomState``
811-
instance, then the provided instance is used.
801+
rng : `numpy.random.Generator`, optional
802+
Pseudorandom number generator state. When `rng` is None, a new
803+
`numpy.random.Generator` is created using entropy from the
804+
operating system. Types other than `numpy.random.Generator` are
805+
passed to `numpy.random.default_rng` to instantiate a ``Generator``.
812806
813807
Returns
814808
-------
@@ -996,7 +990,7 @@ def goodness_of_fit(dist, data, *, known_params=None, fit_params=None,
996990
997991
>>> known_params = {'loc': loc, 'scale': scale}
998992
>>> res = stats.goodness_of_fit(stats.norm, x, known_params=known_params,
999-
... statistic='ks', random_state=rng)
993+
... statistic='ks', rng=rng)
1000994
>>> res.statistic, res.pvalue
1001995
(0.1119257570456813, 0.2788)
1002996
@@ -1030,7 +1024,7 @@ def goodness_of_fit(dist, data, *, known_params=None, fit_params=None,
10301024
as described above. This is where `goodness_of_fit` excels.
10311025
10321026
>>> res = stats.goodness_of_fit(stats.norm, x, statistic='ks',
1033-
... random_state=rng)
1027+
... rng=rng)
10341028
>>> res.statistic, res.pvalue
10351029
(0.1119257570456813, 0.0196)
10361030
@@ -1062,7 +1056,7 @@ def goodness_of_fit(dist, data, *, known_params=None, fit_params=None,
10621056
estimate it directly.
10631057
10641058
>>> res = stats.goodness_of_fit(stats.norm, x, statistic='ad',
1065-
... random_state=rng)
1059+
... rng=rng)
10661060
>>> res.statistic, res.pvalue
10671061
(1.2139573337497467, 0.0034)
10681062
@@ -1078,7 +1072,7 @@ def goodness_of_fit(dist, data, *, known_params=None, fit_params=None,
10781072
>>> rng = np.random.default_rng()
10791073
>>> x = stats.chi(df=2.2, loc=0, scale=2).rvs(size=1000, random_state=rng)
10801074
>>> res = stats.goodness_of_fit(stats.rayleigh, x, statistic='cvm',
1081-
... known_params={'loc': 0}, random_state=rng)
1075+
... known_params={'loc': 0}, rng=rng)
10821076
10831077
This executes fairly quickly, but to check the reliability of the ``fit``
10841078
method, we should inspect the fit result.
@@ -1118,9 +1112,9 @@ def goodness_of_fit(dist, data, *, known_params=None, fit_params=None,
11181112
11191113
"""
11201114
args = _gof_iv(dist, data, known_params, fit_params, guessed_params,
1121-
statistic, n_mc_samples, random_state)
1115+
statistic, n_mc_samples, rng)
11221116
(dist, data, fixed_nhd_params, fixed_rfd_params, guessed_nhd_params,
1123-
guessed_rfd_params, statistic, n_mc_samples_int, random_state) = args
1117+
guessed_rfd_params, statistic, n_mc_samples_int, rng) = args
11241118

11251119
# Fit null hypothesis distribution to data
11261120
nhd_fit_fun = _get_fit_fun(dist, data, guessed_nhd_params,
@@ -1129,7 +1123,7 @@ def goodness_of_fit(dist, data, *, known_params=None, fit_params=None,
11291123
nhd_dist = dist(*nhd_vals)
11301124

11311125
def rvs(size):
1132-
return nhd_dist.rvs(size=size, random_state=random_state)
1126+
return nhd_dist.rvs(size=size, random_state=rng)
11331127

11341128
# Define statistic
11351129
fit_fun = _get_fit_fun(dist, data, guessed_rfd_params, fixed_rfd_params)
@@ -1299,7 +1293,7 @@ def _cramer_von_mises(dist, data, axis):
12991293

13001294

13011295
def _gof_iv(dist, data, known_params, fit_params, guessed_params, statistic,
1302-
n_mc_samples, random_state):
1296+
n_mc_samples, rng):
13031297

13041298
if not isinstance(dist, stats.rv_continuous):
13051299
message = ("`dist` must be a (non-frozen) instance of "
@@ -1349,7 +1343,7 @@ def _gof_iv(dist, data, known_params, fit_params, guessed_params, statistic,
13491343
message = "`n_mc_samples` must be an integer."
13501344
raise TypeError(message)
13511345

1352-
random_state = check_random_state(random_state)
1346+
rng = check_random_state(rng)
13531347

13541348
return (dist, data, fixed_nhd_params, fixed_rfd_params, guessed_nhd_params,
1355-
guessed_rfd_params, statistic, n_mc_samples_int, random_state)
1349+
guessed_rfd_params, statistic, n_mc_samples_int, rng)

scipy/stats/_multicomp.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from scipy.stats._common import ConfidenceInterval
1212
from scipy.stats._qmc import check_random_state
1313
from scipy.stats._stats_py import _var
14+
from scipy._lib._util import _transition_to_rng
15+
1416

1517
if TYPE_CHECKING:
1618
import numpy.typing as npt
@@ -180,11 +182,12 @@ def confidence_interval(
180182
return self._ci
181183

182184

185+
@_transition_to_rng('random_state', replace_doc=False)
183186
def dunnett(
184187
*samples: npt.ArrayLike, # noqa: D417
185188
control: npt.ArrayLike,
186189
alternative: Literal['two-sided', 'less', 'greater'] = "two-sided",
187-
random_state: SeedType = None
190+
rng: SeedType = None
188191
) -> DunnettResult:
189192
"""Dunnett's test: multiple comparisons of means against a control group.
190193
@@ -211,14 +214,21 @@ def dunnett(
211214
* 'greater': the means of the distributions underlying the
212215
samples are greater than the mean of the distribution underlying
213216
the control.
214-
random_state : {None, int, `numpy.random.Generator`}, optional
215-
If `random_state` is an int or None, a new `numpy.random.Generator` is
216-
created using ``np.random.default_rng(random_state)``.
217-
If `random_state` is already a ``Generator`` instance, then the
218-
provided instance is used.
219-
220-
The random number generator is used to control the randomized
221-
Quasi-Monte Carlo integration of the multivariate-t distribution.
217+
rng : `numpy.random.Generator`, optional
218+
Pseudorandom number generator state. When `rng` is None, a new
219+
`numpy.random.Generator` is created using entropy from the
220+
operating system. Types other than `numpy.random.Generator` are
221+
passed to `numpy.random.default_rng` to instantiate a ``Generator``.
222+
223+
.. versionchanged:: 1.15.0
224+
225+
As part of the `SPEC-007 <https://scientific-python.org/specs/spec-0007/>`_
226+
transition from use of `numpy.random.RandomState` to
227+
`numpy.random.Generator`, this keyword was changed from `random_state` to
228+
`rng`. For an interim period, both keywords will continue to work, although
229+
only one may be specified at a time. After the interim period, function
230+
calls using the `random_state` keyword will emit warnings. Following a
231+
deprecation period, the `random_state` keyword will be removed.
222232
223233
Returns
224234
-------
@@ -311,7 +321,7 @@ def dunnett(
311321
"""
312322
samples_, control_, rng = _iv_dunnett(
313323
samples=samples, control=control,
314-
alternative=alternative, random_state=random_state
324+
alternative=alternative, rng=rng
315325
)
316326

317327
rho, df, n_group, n_samples, n_control = _params_dunnett(
@@ -342,10 +352,10 @@ def _iv_dunnett(
342352
samples: Sequence[npt.ArrayLike],
343353
control: npt.ArrayLike,
344354
alternative: Literal['two-sided', 'less', 'greater'],
345-
random_state: SeedType
355+
rng: SeedType
346356
) -> tuple[list[np.ndarray], np.ndarray, SeedType]:
347357
"""Input validation for Dunnett's test."""
348-
rng = check_random_state(random_state)
358+
rng = check_random_state(rng)
349359

350360
if alternative not in {'two-sided', 'less', 'greater'}:
351361
raise ValueError(

scipy/stats/_sensitivity_analysis.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from scipy.stats._qmc import check_random_state
1414
from scipy.stats._resampling import BootstrapResult
1515
from scipy.stats import qmc, bootstrap
16+
from scipy._lib._util import _transition_to_rng
1617

1718

1819
if TYPE_CHECKING:
@@ -61,7 +62,7 @@ def f_ishigami(x: npt.ArrayLike) -> np.ndarray:
6162
def sample_A_B(
6263
n: IntNumber,
6364
dists: list[PPFDist],
64-
random_state: SeedType = None
65+
rng: SeedType = None
6566
) -> np.ndarray:
6667
"""Sample two matrices A and B.
6768
@@ -80,7 +81,7 @@ def sample_A_B(
8081
:doi:`10.1016/j.cpc.2009.09.018`, 2010.
8182
"""
8283
d = len(dists)
83-
A_B = qmc.Sobol(d=2*d, seed=random_state, bits=64).random(n).T
84+
A_B = qmc.Sobol(d=2*d, seed=rng, bits=64).random(n).T
8485
A_B = A_B.reshape(2, d, -1)
8586
try:
8687
for d_, dist in enumerate(dists):
@@ -246,14 +247,15 @@ def ppf(self) -> Callable[..., float]:
246247
...
247248

248249

250+
@_transition_to_rng('random_state', replace_doc=False)
249251
def sobol_indices(
250252
*,
251253
func: Callable[[np.ndarray], npt.ArrayLike] |
252254
dict[Literal['f_A', 'f_B', 'f_AB'], np.ndarray],
253255
n: IntNumber,
254256
dists: list[PPFDist] | None = None,
255257
method: Callable | Literal['saltelli_2010'] = 'saltelli_2010',
256-
random_state: SeedType = None
258+
rng: SeedType = None
257259
) -> SobolResult:
258260
r"""Global sensitivity indices of Sobol'.
259261
@@ -309,11 +311,21 @@ def sobol_indices(
309311
The output is a tuple of the first and total indices with
310312
shape ``(s, d)``.
311313
This is an advanced feature and misuse can lead to wrong analysis.
312-
random_state : {None, int, `numpy.random.Generator`}, optional
313-
If `random_state` is an int or None, a new `numpy.random.Generator` is
314-
created using ``np.random.default_rng(random_state)``.
315-
If `random_state` is already a ``Generator`` instance, then the
316-
provided instance is used.
314+
rng : `numpy.random.Generator`, optional
315+
Pseudorandom number generator state. When `rng` is None, a new
316+
`numpy.random.Generator` is created using entropy from the
317+
operating system. Types other than `numpy.random.Generator` are
318+
passed to `numpy.random.default_rng` to instantiate a ``Generator``.
319+
320+
.. versionchanged:: 1.15.0
321+
322+
As part of the `SPEC-007 <https://scientific-python.org/specs/spec-0007/>`_
323+
transition from use of `numpy.random.RandomState` to
324+
`numpy.random.Generator`, this keyword was changed from `random_state` to
325+
`rng`. For an interim period, both keywords will continue to work, although
326+
only one may be specified at a time. After the interim period, function
327+
calls using the `random_state` keyword will emit warnings. Following a
328+
deprecation period, the `random_state` keyword will be removed.
317329
318330
Returns
319331
-------
@@ -466,7 +478,7 @@ def sobol_indices(
466478
... uniform(loc=-np.pi, scale=2*np.pi),
467479
... uniform(loc=-np.pi, scale=2*np.pi)
468480
... ],
469-
... random_state=rng
481+
... rng=rng
470482
... )
471483
>>> indices.first_order
472484
array([0.31637954, 0.43781162, 0.00318825])
@@ -587,7 +599,7 @@ def sobol_indices(
587599
conclude on high-order terms. Hence the benefit of using Sobol' indices.
588600
589601
"""
590-
random_state = check_random_state(random_state)
602+
rng = check_random_state(rng)
591603

592604
n_ = int(n)
593605
if not (n_ & (n_ - 1) == 0) or n != n_:
@@ -637,7 +649,7 @@ def indices_method(f_A, f_B, f_AB):
637649
def wrapped_func(x):
638650
return np.atleast_2d(func(x))
639651

640-
A, B = sample_A_B(n=n, dists=dists, random_state=random_state)
652+
A, B = sample_A_B(n=n, dists=dists, rng=rng)
641653
AB = sample_AB(A=A, B=B)
642654

643655
f_A = wrapped_func(A)

0 commit comments

Comments
 (0)