Есть ли эффективный способ генерации симметричной случайной матрицы? - PullRequest
2 голосов
/ 15 июня 2019

Есть ли эффективный способ (с использованием numpy) генерировать симметричную случайную матрицу с элементами, равномерно распределенными в [0,1)?

Ответы [ 2 ]

4 голосов
/ 15 июня 2019

Пусть U - квадратная матрица равномерно распределенных случайных чисел.Затем можно добавить нижнюю треугольную часть U с транспонированием (включая диагональ только один раз), чтобы получить симметричную матрицу со случайными числами из того же распределения, что и U.

import numpy as np 

U = np.random.uniform(low=0, high=1.0, size=(1000, 1000))
S = np.tril(U) + np.tril(U, -1).T

print(np.histogram(S.flatten()))
print(np.histogram(S[0,:]))
print(np.histogram(S[:,0]))

Матрица в целом кака также любая строка или столбец будут равномерно распределены в [0,1) в документации для np.random.uniform

По скорости я получаю

%timeit U = np.random.uniform(low=0, high=1.0, size=(1000, 1000))
10.6 ms ± 46.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit S = np.tril(U) + np.tril(U, -1).T
5.76 ms ± 75.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Как отметили другие люди, вы также можете сделать

S = (U + U.T) / 2

, чтобы получить симметрию, но это даст вам треугольные распределенные случайные числа в недиагональной форме, так как вы суммируете две равномерные случайные величины.

2 голосов
/ 15 июня 2019

Вот метод, использующий scipy.spatial.distance.squareform:

squareform переключается между полной и «сжатой» формами симметричной матрицы:

>>> full = squareform(np.arange(1,11))
>>> full
array([[ 0,  1,  2,  3,  4],
       [ 1,  0,  5,  6,  7],
       [ 2,  5,  0,  8,  9],
       [ 3,  6,  8,  0, 10],
       [ 4,  7,  9, 10,  0]])
>>> squareform(full)
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])

Так как он был разработан с учетом матрицы расстояний, он оставляет диагональ на нуле, поэтому мы должны заполнить ее вручную. Для этого мы используем einsum, который использовался так, как мы возвращаем записываемое представление диагонали,

>>> from scipy.spatial.distance import squareform
>>> 
>>> N = 5
>>> a = squareform(np.random.random(N*(N-1)//2))
>>> np.einsum('ii->i', a)[:] = np.random.random(N)
>>> a
array([[0.29946651, 0.3636706 , 0.00708741, 0.87536594, 0.62197293],
       [0.3636706 , 0.31774527, 0.05597852, 0.10800514, 0.99871399],
       [0.00708741, 0.05597852, 0.83912235, 0.86241008, 0.01806965],
       [0.87536594, 0.10800514, 0.86241008, 0.11039534, 0.64213608],
       [0.62197293, 0.99871399, 0.01806965, 0.64213608, 0.84755054]])
...