Взвешенное евклидово расстояние в R

Я хотел бы создать матрицу расстояний со взвешенными евклидовыми расстояниями из фрейма данных. Веса будут определены в векторе. Вот пример:

library("cluster")

a <- c(1,2,3,4,5)
b <- c(5,4,3,2,1)
c <- c(5,4,1,2,3)
df <- data.frame(a,b,c)

weighting <- c(1, 2, 3)

dm <- as.matrix(daisy(df, metric = "euclidean", weights = weighting))

Я искал повсюду и не могу найти пакет или решение для этого в R.Функция 'daisy' в пакете 'cluster' утверждает, что поддерживает взвешивание, но веса, похоже, не применяются, и она просто выплевывает обычный евклид. расстояния.

Любые идеи Stack Overflow?


person Gary866    schedule 30.08.2016    source источник
comment
stat.ethz.ch/R-manual/ R-devel / library / cluster / html / daisy.html На самом деле я мог ошибаться. В документе, кажется, говорится, что взвешивание работает только с расстоянием Гауэра. Тем не менее, мой вопрос все еще остается в силе: есть ли пакет, поддерживающий взвешенные евклидовы расстояния?   -  person Gary866    schedule 30.08.2016
comment
Думаю, вам нужно показать формулу взвешенного расстояния.   -  person IRTFM    schedule 31.08.2016
comment
images.slideplayer.com/16/5203007/slides/slide_49.jpg Итак, в примере (который я исправил), если нам нужно расстояние между строками 1 и 2, оно будет рассчитано как: distance = 1 * (1-2) ^ 2 + 2 * (5-4) ^ 2 + 3 * (5-4) ^ 2 Расчет расстояния должен применяться к большому набору данных, где количество переменных и весов будет отличаться для каждого прогона. Так что не так просто (или, по крайней мере, выше моего уровня навыков) просто написать свою функцию, поэтому я ищу пакет.   -  person Gary866    schedule 31.08.2016
comment
Похоже, что другие написали свою функцию. Вы, наверное, можете попробовать воссоздать.   -  person Pierre L    schedule 31.08.2016
comment
Вы можете масштабировать векторы квадратным корнем из весов (умножая каждое измерение на его собственный масштабный коэффициент, а не обычную векторную операцию), а затем продолжать с евклидовыми расстояниями. Однако понятия не имею, как это сделать в R.   -  person Walter Tross    schedule 31.08.2016
comment
@PierreLafortune Я подозревал, что это может быть так просто, как в R!   -  person Walter Tross    schedule 31.08.2016
comment
На самом деле это больше похоже на sweep(df, 1, weighting, function(x, y) x*sqrt(y))   -  person Pierre L    schedule 31.08.2016
comment
Хорошо, @PierreLafortune, пора написать свой ответ (тем не менее, оптимизируя этот sqrt () вне цикла) ...   -  person Walter Tross    schedule 31.08.2016
comment
@WalterTross Можете ли вы показать пример использования квадратного корня из веса для умножения на набор данных для масштабирования?   -  person Pierre L    schedule 31.08.2016
comment
Я знаю, как это кодировать, я имею в виду статистическое обоснование.   -  person Pierre L    schedule 31.08.2016
comment
@PierreLafortune Никаких статистических рассуждений, только геометрия, но вы правы, см. Мой комментарий к вашему ответу.   -  person Walter Tross    schedule 31.08.2016


Ответы (1)


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

newdf <- sweep(df, 2, weighting, function(x,y) x * sqrt(y))
as.matrix(daisy(newdf, metric="euclidean"))

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

xpand <- function(d) do.call("expand.grid", rep(list(1:nrow(d)), 2))
euc_norm <- function(x) sqrt(sum(x^2))
euc_dist <- function(mat, weights=1) {
  iter <- xpand(mat)
  vec <- mapply(function(i,j) euc_norm(weights*(mat[i,] - mat[j,])), 
                iter[,1], iter[,2])
  matrix(vec,nrow(mat), nrow(mat))
}

Мы можем проверить результат, проверив функцию daisy:

#test1
as.matrix(daisy(df, metric="euclidean"))
#          1        2        3        4        5
# 1 0.000000 1.732051 4.898979 5.196152 6.000000
# 2 1.732051 0.000000 3.316625 3.464102 4.358899
# 3 4.898979 3.316625 0.000000 1.732051 3.464102
# 4 5.196152 3.464102 1.732051 0.000000 1.732051
# 5 6.000000 4.358899 3.464102 1.732051 0.000000

euc_dist(df)
#          [,1]     [,2]     [,3]     [,4]     [,5]
# [1,] 0.000000 1.732051 4.898979 5.196152 6.000000
# [2,] 1.732051 0.000000 3.316625 3.464102 4.358899
# [3,] 4.898979 3.316625 0.000000 1.732051 3.464102
# [4,] 5.196152 3.464102 1.732051 0.000000 1.732051
# [5,] 6.000000 4.358899 3.464102 1.732051 0.000000

Причина, по которой я сомневаюсь в методе Уолтера, заключается в том, что, во-первых, я никогда не видел, чтобы веса применялись по их квадратному корню, обычно это 1/w. Во-вторых, когда я применяю ваши веса к моей функции, я получаю другой результат.

euc_dist(df, weights=weighting) 
person Pierre L    schedule 31.08.2016
comment
Существует несколько способов взвешивания. Я бы масштабировал каждую ось на w, чтобы увеличить вес в w. Для манхэттенского противостояния это явно дает желаемый эффект. Евклидово принимает квадрат, но кто сказал, что он не работает (w*(x_i-y_i))^2? Мне эта схема взвешивания кажется наименее неожиданной. - person Has QUIT--Anony-Mousse; 31.08.2016
comment
@ Anony-Mousse, вы правы, я бы также масштабировал каждую ось по ее весу, а не по квадратному корню. Евклидово расстояние - это квадратный корень из суммы квадратных дельт, поэтому на самом деле ОП в своем комментарии к своему вопросу использует неправильное определение расстояния. Я придерживался этого правила, что заставило меня ввести квадратные корни из весов, но это плохая идея. - person Walter Tross; 31.08.2016
comment
Квадрат евклидова расстояния (сумма квадратов дельт), конечно, полезен, если необходимы только сравнения, потому что он экономит вычислительно тяжелый этап извлечения квадратного корня, но веса должны оставаться определенными в стандартной евклидовой метрике. Кстати, евклидово расстояние и манхэттенское расстояние равны, когда дельты во всех измерениях, кроме одного, равны нулю. - person Walter Tross; 31.08.2016
comment
@ Anony-Mousse В своем описании я не разъяснил, что выбрал другую методику взвешивания. - person Pierre L; 31.08.2016
comment
Отличный пост, спасибо. Метод масштабирования сработал, и я когда-нибудь поэкспериментирую с другими методами. - person Gary866; 01.09.2016