Случайный единичный вектор в многомерном пространстве

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

Если я выбираю случайное число для каждого из n измерений из [-1,1], а затем нормализует вектор до длины 1, я получу равномерное распределение по всем возможным направлениям?

Я говорю только теоретически здесь, так как случайные числа, генерируемые компьютером, на самом деле не являются случайными.

Ответы

Ответ 1

Один простой трюк - выбрать каждое измерение из гауссовского дистрибутива, а затем нормализовать:

from random import gauss

def make_rand_vector(dims):
    vec = [gauss(0, 1) for i in range(dims)]
    mag = sum(x**2 for x in vec) ** .5
    return [x/mag for x in vec]

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

Если ваше число измерений велико, то это имеет сильное преимущество: всегда работать немедленно, генерируя случайные векторы, пока не найдете тот, который имеет величину меньше единицы, что заставит ваш компьютер просто висеть на более чем дюжине измерений или так, потому что вероятность того, что любой из них квалифицируется, становится исчезающе малой.

Ответ 2

Вы не получите равномерно распределенный ансамбль углов с описанным вами алгоритмом. Углы будут смещены в сторону углов вашего n-мерного гиперкуба.

Это можно устранить, исключив любые точки с расстоянием больше 1 от начала координат. Затем вы имеете дело со сферическим, а не с кубическим (n-мерным) объемом, и тогда ваш набор углов должен быть равномерно распределен по пространству образца.

псевдокод:

Пусть n - число измерений, K - искомое число векторов:

vec_count=0
while vec_count < K
   generate n uniformly distributed values a[0..n-1] over [-1, 1]
   r_squared = sum over i=0,n-1 of a[i]^2
   if 0 < r_squared <= 1.0
      b[i] = a[i]/sqrt(r_squared)  ; normalize to length of 1
      add vector b[0..n-1] to output list
      vec_count = vec_count + 1
   else
      reject this sample
end while

Ответ 3

Существует ускоренная реализация алгоритма, который производит выборку из нормальных распределений: random:: uniform_on_sphere

Ответ 4

У меня был тот же самый вопрос, когда также разрабатывался алгоритм ML.
Я пришел к такому же выводу, что и Джим Льюис после рисования образцов для 2-го случая и построения результирующего распределения угла.

Кроме того, если вы попытаетесь получить распределение плотности для направления в 2d, когда вы произвольно рисуете от [-1,1] для оси x и y, вы увидите, что:

f_X(x) = 1/(4*cos²(x)), если 0 < x < 45⁰
и
f_X(x) = 1/(4*sin²(x)), если x > 45⁰

где x - угол, а f_X - распределение плотности вероятности.

Я написал об этом здесь: https://aerodatablog.wordpress.com/2018/01/14/random-hyperplanes/

Ответ 5

#define SCL1 (M_SQRT2/2)
#define SCL2 (M_SQRT2*2)

// unitrand in [-1,1].
double u = SCL1 * unitrand();
double v = SCL1 * unitrand();
double w = SCL2 * sqrt(1.0 - u*u - v*v);

double x = w * u;
double y = w * v;
double z = 1.0 - 2.0 * (u*u + v*v);