Skip to content

Commit 1946f3e

Browse files
authored
Merge pull request scipy#21822 from mdhaber/gh21820
TST: `stats.fit`: adjust tests for `seed`->`rng` transition
2 parents 05af63f + cef8bba commit 1946f3e

File tree

1 file changed

+66
-17
lines changed

1 file changed

+66
-17
lines changed

scipy/stats/tests/test_fit.py

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -231,31 +231,32 @@ def cases_test_fit_mle():
231231
# These fail default test or hang
232232
skip_basic_fit = {'argus', 'irwinhall', 'foldnorm', 'truncpareto',
233233
'truncweibull_min', 'ksone', 'levy_stable',
234-
'studentized_range', 'kstwo', 'arcsine',
234+
'studentized_range', 'kstwo',
235+
'beta', 'nakagami', 'truncnorm', # don't meet tolerance
235236
'poisson_binom'} # vector-valued shape parameter
236237

237238
# Please keep this list in alphabetical order...
238-
slow_basic_fit = {'alpha', 'betaprime', 'binom', 'bradford', 'burr12',
239+
slow_basic_fit = {'alpha', 'arcsine', 'betaprime', 'binom', 'bradford', 'burr12',
239240
'chi', 'crystalball', 'dweibull', 'erlang', 'exponnorm',
240241
'exponpow', 'f', 'fatiguelife', 'fisk', 'foldcauchy', 'gamma',
241242
'genexpon', 'genextreme', 'gennorm', 'genpareto',
242243
'gompertz', 'halfgennorm', 'invgamma', 'invgauss', 'invweibull',
243244
'jf_skew_t', 'johnsonsb', 'johnsonsu', 'kappa3',
244245
'kstwobign', 'loglaplace', 'lognorm', 'lomax', 'mielke',
245-
'nakagami', 'nbinom', 'norminvgauss',
246+
'nbinom', 'norminvgauss',
246247
'pareto', 'pearson3', 'powerlaw', 'powernorm',
247248
'randint', 'rdist', 'recipinvgauss', 'rice', 'skewnorm',
248249
't', 'uniform', 'weibull_max', 'weibull_min', 'wrapcauchy'}
249250

250251
# Please keep this list in alphabetical order...
251-
xslow_basic_fit = {'beta', 'betabinom', 'betanbinom', 'burr', 'exponweib',
252+
xslow_basic_fit = {'betabinom', 'betanbinom', 'burr', 'exponweib',
252253
'gausshyper', 'gengamma', 'genhalflogistic',
253254
'genhyperbolic', 'geninvgauss',
254255
'hypergeom', 'kappa4', 'loguniform',
255256
'ncf', 'nchypergeom_fisher', 'nchypergeom_wallenius',
256257
'nct', 'ncx2', 'nhypergeom',
257258
'powerlognorm', 'reciprocal', 'rel_breitwigner',
258-
'skellam', 'trapezoid', 'triang', 'truncnorm',
259+
'skellam', 'trapezoid', 'triang',
259260
'tukeylambda', 'vonmises', 'zipfian'}
260261

261262
for dist in dict(distdiscrete + distcont):
@@ -282,12 +283,12 @@ def cases_test_fit_mse():
282283
'gausshyper', 'genhyperbolic', # integration warnings
283284
'tukeylambda', # close, but doesn't meet tolerance
284285
'vonmises', # can have negative CDF; doesn't play nice
285-
'argus', # doesn't meet tolerance; tested separately
286+
'arcsine', 'argus', 'powerlaw', # don't meet tolerance
286287
'poisson_binom', # vector-valued shape parameter
287288
}
288289

289290
# Please keep this list in alphabetical order...
290-
slow_basic_fit = {'alpha', 'anglit', 'arcsine', 'betabinom', 'bradford',
291+
slow_basic_fit = {'alpha', 'anglit', 'betabinom', 'bradford',
291292
'chi', 'chi2', 'crystalball', 'dweibull',
292293
'erlang', 'exponnorm', 'exponpow', 'exponweib',
293294
'fatiguelife', 'fisk', 'foldcauchy', 'foldnorm',
@@ -311,7 +312,7 @@ def cases_test_fit_mse():
311312
'johnsonsb', 'kappa4', 'loguniform', 'mielke',
312313
'nakagami', 'ncf', 'nchypergeom_fisher',
313314
'nchypergeom_wallenius', 'nct', 'ncx2',
314-
'pearson3', 'powerlaw', 'powerlognorm',
315+
'pearson3', 'powerlognorm',
315316
'rdist', 'reciprocal', 'rel_breitwigner', 'rice',
316317
'trapezoid', 'truncnorm', 'truncweibull_min',
317318
'vonmises_line', 'zipfian'}
@@ -375,8 +376,8 @@ class TestFit:
375376
rtol = 1e-2
376377
tols = {'atol': atol, 'rtol': rtol}
377378

378-
def opt(self, *args, **kwds):
379-
return differential_evolution(*args, rng=1, **kwds)
379+
def opt(self, *args, rng=1, **kwds):
380+
return differential_evolution(*args, rng=rng, **kwds)
380381

381382
def test_dist_iv(self):
382383
message = "`dist` must be an instance of..."
@@ -494,7 +495,7 @@ def test_guess_iv(self):
494495
with pytest.warns(RuntimeWarning, match=message):
495496
stats.fit(self.dist, self.data, self.shape_bounds_d, guess=guess)
496497

497-
def basic_fit_test(self, dist_name, method):
498+
def basic_fit_test(self, dist_name, method, rng=1):
498499

499500
N = 5000
500501
dist_data = dict(distcont + distdiscrete)
@@ -530,12 +531,13 @@ def basic_fit_test(self, dist_name, method):
530531

531532
@pytest.mark.parametrize("dist_name", cases_test_fit_mle())
532533
def test_basic_fit_mle(self, dist_name):
533-
self.basic_fit_test(dist_name, "mle")
534+
self.basic_fit_test(dist_name, "mle", rng=5)
534535

535536
@pytest.mark.parametrize("dist_name", cases_test_fit_mse())
536537
def test_basic_fit_mse(self, dist_name):
537-
self.basic_fit_test(dist_name, "mse")
538+
self.basic_fit_test(dist_name, "mse", rng=2)
538539

540+
@pytest.mark.slow
539541
def test_arcsine(self):
540542
# Can't guarantee that all distributions will fit all data with
541543
# arbitrary bounds. This distribution just happens to fail above.
@@ -546,8 +548,9 @@ def test_arcsine(self):
546548
shapes = (1., 2.)
547549
data = dist.rvs(*shapes, size=N, random_state=rng)
548550
shape_bounds = {'loc': (0.1, 10), 'scale': (0.1, 10)}
549-
res = stats.fit(dist, data, shape_bounds, optimizer=self.opt)
550-
assert_nlff_less_or_close(dist, data, res.params, shapes, **self.tols)
551+
res = stats.fit(dist, data, shape_bounds, method='mse', optimizer=self.opt)
552+
assert_nlff_less_or_close(dist, data, res.params, shapes,
553+
nlff_name='_penalized_nlpsf', **self.tols)
551554

552555
@pytest.mark.parametrize("method", ('mle', 'mse'))
553556
def test_argus(self, method):
@@ -561,8 +564,25 @@ def test_argus(self, method):
561564
data = dist.rvs(*shapes, size=N, random_state=rng)
562565
shape_bounds = {'chi': (0.1, 10), 'loc': (0.1, 10), 'scale': (0.1, 10)}
563566
res = stats.fit(dist, data, shape_bounds, optimizer=self.opt, method=method)
567+
nlff_name = {'mle': 'nnlf', 'mse': '_penalized_nlpsf'}[method]
568+
assert_nlff_less_or_close(dist, data, res.params, shapes, **self.tols,
569+
nlff_name=nlff_name)
564570

565-
assert_nlff_less_or_close(dist, data, res.params, shapes, **self.tols)
571+
@pytest.mark.xslow
572+
def test_beta(self):
573+
# Can't guarantee that all distributions will fit all data with
574+
# arbitrary bounds. This distribution just happens to fail above.
575+
# Try something slightly different.
576+
N = 1000
577+
rng = np.random.default_rng(self.seed)
578+
dist = stats.beta
579+
shapes = (2.3098496451481823, 0.62687954300963677, 1., 2.)
580+
data = dist.rvs(*shapes, size=N, random_state=rng)
581+
shape_bounds = {'a': (0.1, 10), 'b':(0.1, 10),
582+
'loc': (0.1, 10), 'scale': (0.1, 10)}
583+
res = stats.fit(dist, data, shape_bounds, method='mle', optimizer=self.opt)
584+
assert_nlff_less_or_close(dist, data, res.params, shapes,
585+
nlff_name='nnlf', **self.tols)
566586

567587
def test_foldnorm(self):
568588
# Can't guarantee that all distributions will fit all data with
@@ -578,6 +598,35 @@ def test_foldnorm(self):
578598

579599
assert_nlff_less_or_close(dist, data, res.params, shapes, **self.tols)
580600

601+
def test_nakagami(self):
602+
# Can't guarantee that all distributions will fit all data with
603+
# arbitrary bounds. This distribution just happens to fail above.
604+
# Try something slightly different.
605+
N = 1000
606+
rng = np.random.default_rng(self.seed)
607+
dist = stats.nakagami
608+
shapes = (4.9673794866666237, 1., 2.)
609+
data = dist.rvs(*shapes, size=N, random_state=rng)
610+
shape_bounds = {'nu':(0.1, 10), 'loc': (0.1, 10), 'scale': (0.1, 10)}
611+
res = stats.fit(dist, data, shape_bounds, method='mle', optimizer=self.opt)
612+
assert_nlff_less_or_close(dist, data, res.params, shapes,
613+
nlff_name='nnlf', **self.tols)
614+
615+
@pytest.mark.slow
616+
def test_powerlaw(self):
617+
# Can't guarantee that all distributions will fit all data with
618+
# arbitrary bounds. This distribution just happens to fail above.
619+
# Try something slightly different.
620+
N = 1000
621+
rng = np.random.default_rng(self.seed)
622+
dist = stats.powerlaw
623+
shapes = (1.6591133289905851, 1., 2.)
624+
data = dist.rvs(*shapes, size=N, random_state=rng)
625+
shape_bounds = {'a': (0.1, 10), 'loc': (0.1, 10), 'scale': (0.1, 10)}
626+
res = stats.fit(dist, data, shape_bounds, method='mse', optimizer=self.opt)
627+
assert_nlff_less_or_close(dist, data, res.params, shapes,
628+
nlff_name='_penalized_nlpsf', **self.tols)
629+
581630
def test_truncpareto(self):
582631
# Can't guarantee that all distributions will fit all data with
583632
# arbitrary bounds. This distribution just happens to fail above.
@@ -592,7 +641,7 @@ def test_truncpareto(self):
592641

593642
assert_nlff_less_or_close(dist, data, res.params, shapes, **self.tols)
594643

595-
@pytest.mark.fail_slow(5)
644+
@pytest.mark.slow
596645
def test_truncweibull_min(self):
597646
# Can't guarantee that all distributions will fit all data with
598647
# arbitrary bounds. This distribution just happens to fail above.

0 commit comments

Comments
 (0)