2012-01-06 2 views
6

Учитывая p векторов x1,x2,...,xp каждый размерностей d, что это лучший способ, чтобы вычислить их тензорный/внешнее произведение/Kruskal (в p -array X с элементами X[i1,i2,..ip] = x1[i1]x2[i2]...xp[ip])? Looping тривиально, но глупо. Использование повторено звонки outer работает нормально, но не кажется оптимальным решением (и будет работать медленнее, как с ростом р, очевидно) есть ли лучший способOuter/тензорное произведение в R

Edit:.?

Мой текущий лучшее

array(apply(expand.grid(x1, x2, x3), 1, prod), dim=rep(d, 3)) 

, которые по крайней мере, "чувствует себя лучше" ...

Edit 2: В ответ на @Dwin, вот полный пример

d=3 
x1 = 1:d 
x2 = 1:d+3 
x3 = 1:d+6 
array(apply(expand.grid(x1, x2, x3), 1, prod), dim=rep(d, 3)) 

, , 1 

    [,1] [,2] [,3] 
[1,] 28 35 42 
[2,] 56 70 84 
[3,] 84 105 126 

, , 2 

    [,1] [,2] [,3] 
[1,] 32 40 48 
[2,] 64 80 96 
[3,] 96 120 144 

, , 3 

    [,1] [,2] [,3] 
[1,] 36 45 54 
[2,] 72 90 108 
[3,] 108 135 162 
+0

Это может ответить на ваш вопрос - http://stackoverflow.com/questions/6192848/how-to-generalize-outer-to-n-dimensions/6193836#6193836 –

+0

Принятый ответ довольно медленный; он кажется медленнее, чем повторные призывы к внешним (неудивительно, учитывая, насколько это вообще). Но я думаю, может быть, второй может быть адаптирован ... – MMM

+0

Я был бы очень удивлен, если бы решение 'expand.grid' было быстрее, чем' external'. –

ответ

5

это будет трудно превзойти производительность outer.Это заканчивается тем, что выполняется умножение матрицы, которое выполняется библиотекой BLAS. Повторное обращение outer тоже не имеет значения, поскольку последний вызов будет доминировать как в скорости, так и в памяти. Например, для векторов длиной 100 последний звонок по меньшей мере на 100 раз медленнее предыдущего ...

Лучше всего получить наилучшую производительность здесь, чтобы получить лучшую библиотеку BLAS для R. По умолчанию не очень хорошо. В Linux вы можете довольно легко настроить R для использования ATLAS BLAS. В Windows это сложнее, но возможно. См. R for Windows FAQ.

# multiple outer 
mouter <- function(x1, ...) { 
    r <- x1 
    for(vi in list(...)) r <- outer(r, vi) 
    r 
} 

# Your example 
d=3 
x1 = 1:d 
x2 = 1:d+3 
x3 = 1:d+6 
mouter(x1,x2,x3) 

# Performance test 
x <- runif(1e2) 
system.time(mouter(x,x,x)) # 0 secs (less than 10 ms) 
system.time(mouter(x,x,x,x)) # 0.5 secs/0.35 secs (better BLAS) 

Я заменил мой Windows, Rblas.dll с версией DYNAMIC_ARCH из GOTO BLAS в this place которая улучшила время от 0,5 до 0,35 секунды, как показано выше.

+0

Делает смысл. Мне в основном было интересно, есть ли что-то в базе, которую я отсутствовал, но я думаю, что это действительно какая-то специализированная вещь. Благодарю. – MMM

+0

Вместо создания 'mouter' вы можете использовать' Reduce': 'Reduce ("% o% ", list (x1, x2, x3))'. Не думайте, что производительность сильно изменится. – James

+0

'/ ref:' Оценки ускорения от оптимизированного BLAS могут быть на порядок выше: http://blog.felixriedel.com/2012/10/speed-up-r-by-using-a-different- Блас-реализация / – isomorphismes

1

Вы можете использовать tensor пакет.

А также %o% функция

A <- matrix(1:6, 2, 3) 
D <- A %o% A 
+0

Ну, '% o%' - это точно 'external (x, y, '*')', так что это не поможет решить проблему скорости. Как всегда, :-) Я должен спросить: «что проблема, которую вы пытаетесь решить? »Возможно, у вас есть другой способ: –

+0

Я знаю, как взять внешний продукт двух матриц (или двух векторов), это не то, что мне нужно. Глядя на пакет тензоров мне не сразу понятно, как это могло бы помочь. – MMM

+0

@Carl Witthoft Результирующий массив (почти) совместный pmf многомерной дискретной переменной. Мне нужен этот приблизительный pmf или способ вернуть все его записи больше, чем некоторые значение, а также сумма записей. – MMM

1

Я задаюсь вопросом, если kronecker продукт, что вы хотите. Я не могу сказать из вашего описания проблемы то, что вам нужно, но элементы из этого в небольшом наборе аргументов одинаковы (хотя и в другом варианте, как в выпуске решения Chalasani, вы критиковали как медленное:

kronecker(outer(LETTERS[1:2], c(3, 4, 5),FUN=paste), letters[6:8] ,FUN=paste) 
    [,1] [,2] [,3] 
[1,] "A 3 f" "A 4 f" "A 5 f" 
[2,] "A 3 g" "A 4 g" "A 5 g" 
[3,] "A 3 h" "A 4 h" "A 5 h" 
[4,] "B 3 f" "B 4 f" "B 5 f" 
[5,] "B 3 g" "B 4 g" "B 5 g" 
[6,] "B 3 h" "B 4 h" "B 5 h" 

Если вы хотите продукты, то заменить либо prod или «*». в любом случае, предлагая набор образцов векторов и желаемый результат является лучшей практики в постановке вопросов.

+0

Извините, я думал, что это ясно из вопрос, что вывод должен быть массивом, а не матрицей. Я добавил пример для уточнения. Все мои входы - векторы, поэтому кронекеры и внешние эквиваленты. Замена функции kronecker в вашем ответе с помощью другого вызова внешнего - это решение, которое я изначально имел, которое возвращает массив. – MMM

+0

Да, это была причина, по которой я упомянул о разных договоренностях. Ваш случай использования не был описан, поэтому я подумал, что это может удовлетворить. –

Смежные вопросы