Генерирование случайных векторов евклидовой нормы <= 1 в Python?

Более конкретно, учитывая естественное число d, как я могу генерировать случайные векторы в R ^ d такие, что каждый вектор x имеет евклидову норму &lt = 1?

Генерация случайных векторов с помощью numpy.random.rand(1, d) не проблема, но вероятность такого случайного вектора, имеющего норму &lt = 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) необходим как второй коэффициент масштабирования, потому что в противном случае все векторы будут иметь эвклидовую норму, равную единице.