Конечные метрические вложения: хороший алгоритм?

Я имею конечное метрическое пространство, заданное как (симметричное) k на k матрицу расстояния. Я бы хотел, чтобы алгоритм (приблизительно) изометрически вставлял это в евклидово пространство R ^ (k-1). Хотя это не всегда удается сделать точно, решая систему уравнений, заданную расстояниями, я ищу решение, которое внедряется с некоторой (очень малой) управляемой ошибкой.

В настоящее время я использую многомерное масштабирование (MDS) с выходным размером, установленным в (k-1). Мне приходит в голову, что в целом MDS может быть оптимизирован для ситуации, когда вы пытаетесь уменьшить размер встроенного внедрения до чего-то менее (k-1) (обычно 2 или 3) и что может быть лучший алгоритм для моего ограниченного случай.

Вопрос: что такое хороший/быстрый алгоритм реализации метрического пространства размера k в R ^ {k-1} с использованием евклидова расстояния?

Некоторые параметры и указатели:

(1) Мои k относительно малы. Скажем, 3 < k < 25

(2) На самом деле меня не волнует, если я вставляю в R ^ {k-1}. Если это упрощает вещи/делает вещи быстрее, любой R ^ N также будет прекрасен, пока он изометричен. Я рад, если есть более быстрый алгоритм или один с меньшей ошибкой, если я увеличусь до R ^ k или R ^ (2k + 1).

(3) Если вы можете указать на реализацию python, я буду еще счастливее.

(4) Все, что лучше, чем MDS будет работать.

Ответы

Ответ 1

Почему бы не попробовать LLE, вы также можете найти там код.

Ответ 2

Хорошо, как обещалось здесь простое решение:

Обозначение: пусть d_{i,j}=d_{j,i} обозначает расстояние квадрата между точками i и j. Пусть N - число точек. Обозначим через p_i точку i и p_{i,k} k -й координаты точки.

Надеюсь, теперь я получу алгоритм. После этого будут некоторые объяснения, поэтому вы можете проверить вывод (я ненавижу, когда появляются многие индексы).

Алгоритм использует динамическое программирование для достижения правильного решения

Initialization:
p_{i,k} := 0 for all i and k

Calculation:
for i = 2 to N do
   sum = 0
   for j = 2 to i - 1 do
     accu = d_{i,j} - d_{i,1} - p_{j,j-1}^2
     for k = 1 to j-1 do
       accu = accu + 2 p_{i,k}*p_{j,k} - p_{j,k}^2
     done
     p_{i,j} = accu / ( 2 p_{j,j-1} )
     sum = sum + p_{i,j}^2
   done
   p_{i,i-1} = sqrt( d_{i,0} - sum )
done

Если я не совершил серьезных ошибок индекса (обычно я это делаю), это должно сделать трюк.

Идея этого:

Мы устанавливаем первую точку в начале координат, чтобы облегчить нашу жизнь. Не то, что для точки p_i мы никогда не устанавливаем координату k, когда k > i-1. То есть для второй точки мы устанавливаем только первую координату, для третьей точки устанавливаем только первую и вторую координаты и т.д.

Теперь предположим, что мы имеем координаты для всех точек p_ {k '}, где k'<i, и мы хотим вычислить координаты для p_{i}, чтобы выполнялись все d_{i,k'} (нам все равно не нужно никаких ограничений для точек с k>k'). Если записать систему уравнений, то

d_{i,j} = \sum_{k=1}^N (p_{i,k} - p_{j,k} )^2

Поскольку оба p_{i,k} и p_{j,k} равны нулю для k>k', мы можем уменьшить это:

d_{i,j} = \sum_{k=1}^k' (p_{i,k} - p_{j,k} )^2

Также обратите внимание, что при инварианте цикла все p_{j,k} будут равны нулю при k>j-1. Итак, мы разделим это уравнение:

d_{i,j} = \sum_{k=1}^{j-1} (p_{i,k} - p_{j,k} )^2 + \sum_{k=j}^{k'} p_{i,j}^2

Для первого уравнения получим:

d_{i,1} = \sum_{k=1}^{j-1} (p_{i,k} - p_{j,k} )^2 + \sum_{k=j}^{k'} p_i{i,1}^2

Это будет нуждаться в специальном лечении позже.

Теперь, если мы решим все биномы в нормальном уравнении, получим:

d_{i,j} = \sum_{k=1}^{j-1} p_{i,k}^2 - 2 p_{i,k} p_{j,k} + p_{j,k}^2 + \sum_{k=j}^{k'} p_{i,j}^2

вычтите из этого первое уравнение, и вы останетесь с:

d_{i,j} - d_{i,1} = \sum_{k=1}^{j-1} p_{j,k}^2 - 2 p_{i,k} p_{j,k}

для всех j > 1.

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

Надеюсь, вы сможете следовать моим рассуждениям. Это немного поздно, и моя голова немного откручивается от этих индексов.

EDIT: Да, были ошибки индексации. Исправлена. Я попытаюсь реализовать это в python, когда у меня есть время, чтобы проверить его.