Solución:
Hay tres razones por las que uso bsxfun
(documentación, enlace de blog)
-
bsxfun
es más rápido querepmat
(vea abajo) -
bsxfun
requiere menos mecanografía - Utilizando
bsxfun
, como usaraccumarray
, me hace sentir bien acerca de mi comprensión de Matlab.
bsxfun
replicará las matrices de entrada a lo largo de sus “dimensiones singleton”, es decir, las dimensiones a lo largo de las cuales el tamaño de la matriz es 1, de modo que coincidan con el tamaño de la dimensión correspondiente de la otra matriz. Esto es lo que se llama “expansión singleton”. Como acotación al margen, las dimensiones singleton son las que se eliminarán si llama squeeze
.
Es posible que para problemas muy pequeños, el repmat
El enfoque es más rápido, pero con ese tamaño de matriz, ambas operaciones son tan rápidas que probablemente no supongan ninguna diferencia en términos de rendimiento general. Hay dos razones importantes bsxfun
es más rápido: (1) el cálculo ocurre en código compilado, lo que significa que la replicación real de la matriz nunca ocurre, y (2) bsxfun
es una de las funciones de Matlab multiproceso.
He realizado una comparación de velocidad entre repmat
y bsxfun
con R2012b en mi portátil decentemente rápido.
Para mi, bsxfun
es aproximadamente 3 veces más rápido que repmat
. La diferencia se vuelve más pronunciada si las matrices se hacen más grandes
El salto en tiempo de ejecución de repmat
ocurre alrededor de un tamaño de matriz de 1 Mb, lo que podría tener algo que ver con el tamaño de la caché de mi procesador – bsxfun
no es un salto tan malo, porque solo necesita asignar la matriz de salida.
A continuación, encontrará el código que utilicé para cronometrar:
n = 300;
k=1; %# k=100 for the second graph
a = ones(10,1);
rr = zeros(n,1);
bb=zeros(n,1);
ntt=100;
tt=zeros(ntt,1);
for i=1:n;
r = rand(1,i*k);
for it=1:ntt;
tic,
x=bsxfun(@plus,a,r);
tt(it)=toc;
end;
bb(i)=median(tt);
for it=1:ntt;
tic,
y=repmat(a,1,i*k)+repmat(r,10,1);
tt(it)=toc;
end;
rr(i)=median(tt);
end
En mi caso, uso bsxfun
porque me evita pensar en los problemas de columnas o filas.
Para escribir tu ejemplo:
A = A - (ones(size(A, 1), 1) * mean(A));
Tengo que solucionar varios problemas:
1) size(A,1)
o size(A,2)
2) ones(sizes(A,1),1)
o ones(1,sizes(A,1))
3) ones(size(A, 1), 1) * mean(A)
o mean(A)*ones(size(A, 1), 1)
4) mean(A)
o mean(A,2)
Cuando uso bsxfun
, Solo tengo que resolver el último:
a) mean(A)
o mean(A,2)
Podrías pensar que es perezoso o algo así, pero cuando uso bsxfun
, Yo tengo menos errores y yo programa más rápido.
Además, es más corto, lo que mejora digitando rapido y legibilidad.
¡Pregunta muy interesante! Recientemente me encontré con exactamente esa situación al responder a esta pregunta. Considere el siguiente código que calcula índices de una ventana deslizante de tamaño 3 a través de un vector a
:
a = rand(1e7,1);
tic;
idx = bsxfun(@plus, [0:2]', 1:numel(a)-2);
toc
% equivalent code from im2col function in MATLAB
tic;
idx0 = repmat([0:2]', 1, numel(a)-2);
idx1 = repmat(1:numel(a)-2, 3, 1);
idx2 = idx0+idx1;
toc;
isequal(idx, idx2)
Elapsed time is 0.297987 seconds.
Elapsed time is 0.501047 seconds.
ans =
1
En este caso bsxfun
¡es casi dos veces más rápido! Es útil y rápido porque evita la asignación explícita de memoria para matrices idx0
y idx1
, guardándolos en la memoria y luego leyéndolos nuevamente solo para agregarlos. Dado que el ancho de banda de la memoria es un activo valioso y, a menudo, el cuello de botella en las arquitecturas actuales, desea usarlo con prudencia y disminuir los requisitos de memoria de su código para mejorar el rendimiento.
bsxfun
le permite hacer precisamente eso: crear una matriz basada en aplicar un operador arbitrario a todos los pares de elementos de dos vectores, en lugar de operar explícitamente en dos matrices obtenidas al replicar los vectores. Es decir expansión singleton. También puede pensar en ello como el producto exterior de BLAS:
v1=[0:2]';
v2 = 1:numel(a)-2;
tic;
vout = v1*v2;
toc
Elapsed time is 0.309763 seconds.
Multiplica dos vectores para obtener una matriz. Solo que el producto externo solo realiza multiplicaciones, y bsxfun
Puede aplicar operadores arbitrarios. Como nota al margen, es muy interesante ver que bsxfun
es tan rápido como el producto exterior BLAS. Y generalmente se considera que BLAS ofrece los rendimiento..
Editar Gracias al comentario de Dan, aquí hay un gran artículo de Loren discutiendo exactamente eso.