Cómo crear una matriz ortonormal aleatoria en python numpy

¿Hay algún método al que pueda llamar para crear una matriz ortonormal aleatoria en python? Posiblemente utilizando numpy? ¿O hay una manera de crear una matriz ortonormal usando múltiples métodos de números? Gracias.

Este es el método rvs extraído de https://github.com/scipy/scipy/pull/5622/files , con un cambio mínimo, lo suficiente como para ejecutarse como una función numpy independiente.

 import numpy as np def rvs(dim=3): random_state = np.random H = np.eye(dim) D = np.ones((dim,)) for n in range(1, dim): x = random_state.normal(size=(dim-n+1,)) D[n-1] = np.sign(x[0]) x[0] -= D[n-1]*np.sqrt((x*x).sum()) # Householder transformation Hx = (np.eye(dim-n+1) - 2.*np.outer(x, x)/(x*x).sum()) mat = np.eye(dim) mat[n-1:, n-1:] = Hx H = np.dot(H, mat) # Fix the last sign such that the determinant is 1 D[-1] = (-1)**(1-(dim % 2))*D.prod() # Equivalent to np.dot(np.diag(D), H) but faster, apparently H = (D*HT).T return H 

Coincide con la prueba de Warren, https://stackoverflow.com/a/38426572/901925

La versión 0.18 de scipy tiene scipy.stats.ortho_group y scipy.stats.special_ortho_group . La solicitud de extracción donde se agregó es https://github.com/scipy/scipy/pull/5622

Por ejemplo,

 In [24]: from scipy.stats import ortho_group # Requires version 0.18 of scipy In [25]: m = ortho_group.rvs(dim=3) In [26]: m Out[26]: array([[-0.23939017, 0.58743526, -0.77305379], [ 0.81921268, -0.30515101, -0.48556508], [-0.52113619, -0.74953498, -0.40818426]]) In [27]: np.set_printoptions(suppress=True) In [28]: m.dot(mT) Out[28]: array([[ 1., 0., -0.], [ 0., 1., 0.], [-0., 0., 1.]]) 

Puede obtener una matriz ortogonal Q aleatoria nxn (distribuida uniformemente sobre la variedad de matrices ortogonales nxn ) realizando una factorización QR de una matriz nxn con elementos iid Gaussian variables aleatorias de media 0 y varianza 1 . Aquí hay un ejemplo:

 import numpy as np from scipy.linalg import qr n = 3 H = np.random.randn(n, n) Q, R = qr(H) print (Q.dot(QT)) 
 [[ 1.00000000e+00 -2.77555756e-17 2.49800181e-16] [ -2.77555756e-17 1.00000000e+00 -1.38777878e-17] [ 2.49800181e-16 -1.38777878e-17 1.00000000e+00]] 

Si no desea una Matriz Cuadrada con vectores de columna ortonormales, puede crear una cuadrada con cualquiera de los métodos mencionados y eliminar algunas columnas.

 from scipy.stats import special_ortho_group num_dim=3 x = special_ortho_group.rvs(num_dim) 

Documentación

Una forma fácil de crear cualquier matriz ortogonal de forma ( nxm ):

 import numpy as np n, m = 3, 5 H = np.random.rand(n, m) u, s, vh = np.linalg.svd(H, full_matrices=False) mat = u @ vh print(mat @ mat.T) # -> eye(n) 

Tenga en cuenta que si n > m , obtendría mat.T @ mat = eye(m) .