Skip to content

Commit

Permalink
ENH: stats: Implement frozen random_correlation (scipy#15681)
Browse files Browse the repository at this point in the history
* ENH: Implement frozen random_correlation

Co-authored-by: Matt Haberland <[email protected]>
  • Loading branch information
NamamiShanker and mdhaber authored Mar 2, 2022
1 parent d2a6ca5 commit ad44afa
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 0 deletions.
85 changes: 85 additions & 0 deletions scipy/stats/_multivariate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3603,6 +3603,37 @@ class random_correlation_gen(multi_rv_generic):
rvs(eigs=None, random_state=None)
Draw random correlation matrices, all with eigenvalues eigs.
Parameters
----------
eigs : 1d ndarray
Eigenvalues of correlation matrix
seed : {None, int, `numpy.random.Generator`,
`numpy.random.RandomState`}, optional
If `seed` is None (or `np.random`), the `numpy.random.RandomState`
singleton is used.
If `seed` is an int, a new ``RandomState`` instance is used,
seeded with `seed`.
If `seed` is already a ``Generator`` or ``RandomState`` instance
then that instance is used.
tol : float, optional
Tolerance for input parameter checks
diag_tol : float, optional
Tolerance for deviation of the diagonal of the resulting
matrix. Default: 1e-7
Raises
------
RuntimeError
Floating point error prevented generating a valid correlation
matrix.
Returns
-------
rvs : ndarray or scalar
Random size N-dimensional matrices, dimension (size, dim, dim),
each having eigenvalues eigs.
Notes
-----
Expand Down Expand Up @@ -3640,6 +3671,14 @@ def __init__(self, seed=None):
super().__init__(seed)
self.__doc__ = doccer.docformat(self.__doc__)

def __call__(self, eigs, seed=None, tol=1e-13, diag_tol=1e-7):
"""Create a frozen random correlation matrix.
See `random_correlation_frozen` for more information.
"""
return random_correlation_frozen(eigs, seed=seed, tol=tol,
diag_tol=diag_tol)

def _process_parameters(self, eigs, tol):
eigs = np.asarray(eigs, dtype=float)
dim = eigs.size
Expand Down Expand Up @@ -3775,6 +3814,52 @@ def rvs(self, eigs, random_state=None, tol=1e-13, diag_tol=1e-7):
random_correlation = random_correlation_gen()


class random_correlation_frozen(multi_rv_frozen):
def __init__(self, eigs, seed=None, tol=1e-13, diag_tol=1e-7):
"""Create a frozen random correlation matrix distribution.
Parameters
----------
eigs : 1d ndarray
Eigenvalues of correlation matrix
seed : {None, int, `numpy.random.Generator`,
`numpy.random.RandomState`}, optional
If `seed` is None (or `np.random`), the `numpy.random.RandomState`
singleton is used.
If `seed` is an int, a new ``RandomState`` instance is used,
seeded with `seed`.
If `seed` is already a ``Generator`` or ``RandomState`` instance
then that instance is used.
tol : float, optional
Tolerance for input parameter checks
diag_tol : float, optional
Tolerance for deviation of the diagonal of the resulting
matrix. Default: 1e-7
Raises
------
RuntimeError
Floating point error prevented generating a valid correlation
matrix.
Returns
-------
rvs : ndarray or scalar
Random size N-dimensional matrices, dimension (size, dim, dim),
each having eigenvalues eigs.
"""

self._dist = random_correlation_gen(seed)
self.tol = tol
self.diag_tol = diag_tol
_, self.eigs = self._dist._process_parameters(eigs, tol=self.tol)

def rvs(self, random_state=None):
return self._dist.rvs(self.eigs, random_state=random_state,
tol=self.tol, diag_tol=self.diag_tol)


class unitary_group_gen(multi_rv_generic):
r"""A matrix-valued U(N) random variable.
Expand Down
12 changes: 12 additions & 0 deletions scipy/stats/tests/test_multivariate.py
Original file line number Diff line number Diff line change
Expand Up @@ -1538,6 +1538,18 @@ def test_invalid_eigs(self):
assert_raises(ValueError, random_correlation.rvs, [2.5, -.5])
assert_raises(ValueError, random_correlation.rvs, [1, 2, .1])

def test_frozen_matrix(self):
eigs = (.5, .8, 1.2, 1.5)
frozen = random_correlation(eigs)
frozen_seed = random_correlation(eigs, seed=514)

rvs1 = random_correlation.rvs(eigs, random_state=514)
rvs2 = frozen.rvs(random_state=514)
rvs3 = frozen_seed.rvs()

assert_equal(rvs1, rvs2)
assert_equal(rvs1, rvs3)

def test_definition(self):
# Test the definition of a correlation matrix in several dimensions:
#
Expand Down

0 comments on commit ad44afa

Please sign in to comment.