Генерирование случайных векторов евклидовой нормы <= 1 в Python?
Более конкретно, учитывая естественное число d, как я могу генерировать случайные векторы в R ^ d такие, что каждый вектор x имеет евклидову норму < = 1?
Генерация случайных векторов с помощью numpy.random.rand(1, d) не проблема, но вероятность такого случайного вектора, имеющего норму < = 1, предсказуемо плохо для даже не малого d. Например, даже при d = 10 примерно 0,2% таких случайных векторов имеют соответственно малую норму. Так что это кажется глупым решением.
EDIT: Re: Вальтер, да, я ищу равномерное распределение по векторам единичного шара в R ^ d.
Ответы
Ответ 1
Основываясь на статье Wolfram Mathworld о выборе точки гиперсферы и Ответ Nate Eldredge к аналогичному вопросу на math.stackexchange.com, вы можете сгенерировать такой вектор, создав вектор d
независимых гауссовских случайных величин и случайное число U
, равномерно распределенное по замкнутому интервалу [0, 1]
, затем нормализуя вектор к норме U^(1/d)
.
Ответ 2
Основываясь на ответе user2357112, вам нужно что-то вроде этого:
import numpy as np
...
inv_d = 1.0 / d
for ...:
gauss = np.random.normal(size=d)
length = np.linalg.norm(gauss)
if length == 0.0:
x = gauss
else:
r = np.random.rand() ** inv_d
x = np.multiply(gauss, r / length)
# conceptually: / length followed by * r
# do something with x
(это моя вторая программа на Python, поэтому не стреляйте в меня...)
Трюки заключаются в том, что
- комбинация d независимых гауссовских переменных с тем же σ является гауссовским распределением по d измерениям, что, замечательно, имеет сферическую симметрию,
- гауссовское распределение по d измерениям можно проецировать на единичную сферу путем деления на норму, а
- равномерное распределение в d-мерной единичной сфере имеет кумулятивное радиальное распределение r d (это то, что вам нужно инвертировать)
Ответ 3
это код Python/Numpy, который я использую. Поскольку он не использует циклы, выполняется намного быстрее:
n_vectors=1000
d=2
rnd_vec=np.random.uniform(-1, 1, size=(n_vectors, d)) # the initial random vectors
unif=np.random.uniform(size=n_vectors) # a second array random numbers
scale_f=np.expand_dims(np.linalg.norm(rnd_vec, axis=1)/unif, axis=1) # the scaling factors
rnd_vec=rnd_vec/scale_f # the random vectors in R^d
Второй массив случайных чисел (unif) необходим как второй коэффициент масштабирования, потому что в противном случае все векторы будут иметь эвклидовую норму, равную единице.