2012-01-06 11 views
6

Dada p vectores x1,x2,...,xp cada uno de dimensión d, ¿cuál es la mejor manera de calcular su tensor producto/Kruskal exterior/(la p X -array con entradas X[i1,i2,..ip] = x1[i1]x2[i2]...xp[ip])? Bucle es trivial, pero estúpida. Uso repetido llama a outer funciona bien, pero no parece ser la solución óptima (y obtendrá más lento a medida p aumenta, obviamente) ¿hay una mejor maneraproducto/tensor exterior en R

Editar:.?

Mi actual mejor es

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

los cuales al menos "se siente mejor" ...

Edición 2: En respuesta a @Dwin, aquí hay un ejemplo completa

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

Esto podría responder a su pregunta - http://stackoverflow.com/questions/6192848/how-to-generalize-outer-to-n-dimensions/6193836#6193836 –

+0

La respuesta aceptada es bastante lento; parece ser más lento que las llamadas repetidas al exterior (lo que no sorprende dado lo general que es). Pero creo que quizás el segundo se puede adaptar ... – MMM

+0

Me sorprendería mucho si la solución 'expand.grid' fuera más rápida que la solución' externa'. –

Respuesta

5

será difícil de superar el rendimiento de outer. Esto termina haciendo una multiplicación de matriz que es realizada por la biblioteca BLAS. Llamar a outer repetidamente tampoco importa, ya que la última llamada dominará tanto la velocidad como la memoria. Por ejemplo, para vectores de longitud 100, la última llamada es al menos 100 veces más lenta que la anterior ...

Su mejor apuesta para obtener el mejor rendimiento aquí es obtener la mejor biblioteca BLAS para R. La predeterminada no es muy bueno En Linux, puede configurar bastante fácilmente R para usar ATLAS BLAS. En Windows es más difícil, pero posible. Ver 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) 

I sustituirá mi de Windows Rblas.dll con la versión DYNAMIC_ARCH de GOTO BLAS en this place que mejoró el tiempo de 0,5 a 0,35 segundos como se ve arriba.

+0

tiene sentido. Me preguntaba sobre todo si había algo en la base que me faltaba, pero creo que realmente es una especie de cosa especializada. Gracias. – MMM

+0

En lugar de crear 'mouter' puede usar' Reducir': 'Reducir ("% o% ", list (x1, x2, x3))'. Sin embargo, no creo que el rendimiento cambie mucho. – James

+0

'/ ref:' Las estimaciones de la aceleración de un BLAS optimizado pueden ser un orden de magnitud mayor: http://blog.felixriedel.com/2012/10/speed-up-r-by-using-a-different- blas-implementation / – isomorphismes

1

Puede utilizar tensor paquete.

Y también %o% función

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

Bueno, '% o%' es exactamente 'externo (x, y, '*')' por lo que no ayudará al problema de velocidad. Como siempre, :-) Tengo que preguntar, "¿qué es? el problema que estás tratando de resolver? "Es posible que haya una manera diferente a través de tus datos. –

+0

Sé cómo tomar el producto externo de dos matrices (o dos vectores); eso no es lo que necesito. Mirando el paquete tensorial no me queda claro de inmediato cómo sería de ayuda. – MMM

+0

@Carl Witthoft La matriz resultante es (casi) la pmf conjunta de una variable discreta multivariante. Necesito este pmf aproximado, o una forma de devolver todas sus entradas mayores que algunas valor, y también la suma de las entradas. – MMM

1

me pregunto si el producto kronecker es lo que quiere. No puedo decir desde la descripción de su problema exactamente lo que desea, pero los elementos de esto en un pequeño conjunto de argumentos son los mismos (aunque en una disposición diferente a los producidos por la solución de Chalasani que criticaron como lento:

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" 

Si quieres productos, sustituya o bien prod o "*". en cualquier caso, ofreciendo un conjunto de muestras de los vectores y la salida deseada es una mejor práctica en cuestiones que presentan.

+0

Lo siento, pensé que estaba claro desde la pregunta de que la salida debería ser una matriz, no una matriz. He agregado un ejemplo para aclarar. Todas mis entradas son vectores, por lo que kronecker y outer son equivalentes. Reemplazar la función kronecker en su respuesta con otra llamada a outer fue la solución que tenía originalmente, que devuelve una matriz. – MMM

+0

Sí, fue la razón por la que mencioné el arreglo diferente. Su caso de uso no fue descrito, así que pensé que podría satisfacer. –

Cuestiones relacionadas