Minha pergunta: notei que muitas respostas boas para as questões do Matlab no SO usam frequentemente a função bsxfun
. Por quê?
Motivação: Na documentação do Matlab para bsxfun
, é fornecido o seguinte exemplo:
A = magic(5);
A = bsxfun(@minus, A, mean(A))
Claro que poderíamos fazer a mesma operação usando:
A = A - (ones(size(A, 1), 1) * mean(A));
De fato, um simples teste de velocidade demonstra que o segundo método é cerca de 20% mais rápido. Então, por que usar o primeiro método? Suponho que há algumas circunstâncias em que o uso bsxfun
será muito mais rápido que a abordagem "manual". Eu estaria realmente interessado em ver um exemplo dessa situação e uma explicação de por que é mais rápido.
Além disso, um elemento final para essa pergunta, novamente da documentação do Matlab para bsxfun
: "C = bsxfun (fun, A, B) aplica a operação binária elemento a elemento especificada pela função handle fun nas matrizes A e B, com singleton expansão ativada. " O que significa a frase "com expansão singleton ativada"?
tic...toc
contornar as linhas, a velocidade do código dependerá da necessidade de ler as funções na memória.timeit
função no link que você / angainor / Dan fornece.Respostas:
Existem três razões pelas quais eu uso
bsxfun
( documentação , link do blog )bsxfun
é mais rápido querepmat
(veja abaixo)bsxfun
requer menos digitaçãobsxfun
, como usaraccumarray
, me faz sentir bem com minha compreensão do Matlab.bsxfun
replicará as matrizes de entrada ao longo de suas "dimensões singleton", ou seja, as dimensões ao longo das quais o tamanho da matriz é 1, para que correspondam ao tamanho da dimensão correspondente da outra matriz. Isto é o que se chama "expasão singleton". Como um aparte, as dimensões singleton são as que serão eliminadas se você ligarsqueeze
.É possível que, para problemas muito pequenos, a
repmat
abordagem seja mais rápida - mas nesse tamanho de matriz, as duas operações são tão rápidas que provavelmente não farão diferença em termos de desempenho geral. Há duas razões importantes para quebsxfun
seja mais rápido: (1) o cálculo ocorre no código compilado, o que significa que a replicação real da matriz nunca acontece e (2)bsxfun
é uma das funções do Matlab multithread.Fiz uma comparação de velocidade entre
repmat
ebsxfun
com o R2012b no meu laptop decentemente rápido.Para mim,
bsxfun
é cerca de 3 vezes mais rápido querepmat
. A diferença se torna mais acentuada se as matrizes ficarem maioresO salto no tempo de execução
repmat
ocorre em torno de um tamanho de matriz de 1Mb, que pode ter algo a ver com o tamanho do cache do meu processador -bsxfun
não fica tão ruim quanto um salto, porque ele só precisa alocar a matriz de saída.Abaixo, você encontra o código que usei para cronometrar:
fonte
No meu caso, uso
bsxfun
porque me evita pensar nos problemas de coluna ou linha.Para escrever seu exemplo:
Eu tenho que resolver vários problemas:
1)
size(A,1)
ousize(A,2)
2)
ones(sizes(A,1),1)
ouones(1,sizes(A,1))
3)
ones(size(A, 1), 1) * mean(A)
oumean(A)*ones(size(A, 1), 1)
4)
mean(A)
oumean(A,2)
Quando uso
bsxfun
, só tenho que resolver o último:a)
mean(A)
oumean(A,2)
Você pode pensar que é preguiçoso ou algo assim, mas quando uso
bsxfun
, tenho menos bugs e programa mais rapidamente .Além disso, é mais curto, o que melhora a velocidade e a legibilidade da digitação .
fonte
Pergunta muito interessante! Recentemente, deparei-me exatamente com essa situação ao responder a essa pergunta. Considere o seguinte código que calcula índices de uma janela deslizante de tamanho 3 por meio de um vetor
a
:Nesse caso,
bsxfun
é quase duas vezes mais rápido! É útil e rápido, pois evita a alocação explícita de memória para matrizesidx0
eidx1
, salvando-as na memória e, em seguida, lendo-as novamente apenas para adicioná-las. Como a largura de banda da memória é um ativo valioso e, muitas vezes, o gargalo nas arquiteturas atuais, você deseja usá-la com sabedoria e diminuir os requisitos de memória do seu código para melhorar o desempenho.bsxfun
permite fazer exatamente isso: crie uma matriz com base na aplicação de um operador arbitrário a todos os pares de elementos de dois vetores, em vez de operar explicitamente em duas matrizes obtidas pela replicação dos vetores. Essa é a expansão singleton . Você também pode pensar nisso como o produto externo da BLAS:Você multiplica dois vetores para obter uma matriz. Só que o produto externo executa apenas a multiplicação e
bsxfun
pode aplicar operadores arbitrários. Como uma observação lateral, é muito interessante ver quebsxfun
é tão rápido quanto o produto externo BLAS. E o BLAS é geralmente considerado como o melhor desempenho.Editar Graças ao comentário de Dan, aqui está um ótimo artigo de Loren discutindo exatamente isso.
fonte
bsxfun
um bom exemplo.A partir do R2016b, o Matlab suporta expansão implícita para uma ampla variedade de operadores, portanto, na maioria dos casos, não é mais necessário usar
bsxfun
:Há uma discussão detalhada de Expansão implícita e seu desempenho no blog de Loren. Para citar Steve Eddins do MathWorks:
fonte
As coisas nem sempre são consistentes com os três métodos comuns:
repmat
despesa pela indexação ebsxfun
. Fica bem mais interessante quando você aumenta ainda mais o tamanho do vetor. Veja o enredo:bsxfun
na verdade se torna um pouco mais lento que os outros dois em algum momento, mas o que me surpreendeu é que se você aumentar ainda mais o tamanho do vetor (> 13E6 elementos de saída), o bsxfun de repente se torna mais rápido novamente em cerca de 3x. Suas velocidades parecem saltar em passos e a ordem nem sempre é consistente. Meu palpite é que também pode ser dependente do tamanho do processador / memória, mas geralmente acho que continuariabsxfun
sempre que possível.fonte