Estou trabalhando com o Matlab.
Eu tenho uma matriz quadrada binária. Para cada linha, há uma ou mais entradas de 1. Quero passar por cada linha dessa matriz e retornar o índice desses 1s e armazená-los na entrada de uma célula.
Eu queria saber se existe uma maneira de fazer isso sem fazer loop em todas as linhas desta matriz, pois o loop for é realmente lento no Matlab.
Por exemplo, minha matriz
M = 0 1 0
1 0 1
1 1 1
Então, eventualmente, eu quero algo como
A = [2]
[1,3]
[1,2,3]
Então A
é uma célula.
Existe uma maneira de atingir esse objetivo sem usar o loop for, com o objetivo de calcular o resultado mais rapidamente?
matlab
vectorization
ftxx
fonte
fonte
for
loops? Para esse problema, nas versões modernas do MATLAB, suspeito fortemente que umfor
loop seja a solução mais rápida. Se você tiver um problema de desempenho, suspeito que esteja procurando o local errado, com base em conselhos desatualizados.cellfun
.1
s em uma fileira típica? Eu não esperaria que umfind
loop levasse algo próximo dos 30s para algo pequeno o suficiente para caber na memória física.Respostas:
Na parte inferior desta resposta está um código de benchmarking, pois você esclareceu que está interessado em desempenho, em vez de evitar arbitrariamente
for
loops.Na verdade, acho que os
for
loops são provavelmente a opção de melhor desempenho aqui. Desde que o "novo" (2015b) mecanismo JIT foi introduzido ( fonte ), osfor
loops não são inerentemente lentos - na verdade, eles são otimizados internamente.Você pode ver no benchmark que a
mat2cell
opção oferecida por ThomasIsCoding aqui é muito lenta ...Se nos livrarmos dessa linha para tornar a escala mais clara, meu
splitapply
método é bastante lento, a opção accumarray do obchardon é um pouco melhor, mas as opções mais rápidas (e comparáveis) estão usandoarrayfun
(como também sugerido por Thomas) ou umfor
loop. Observe quearrayfun
é basicamente umfor
loop disfarçado para a maioria dos casos de uso, portanto, este não é um empate surpreendente!Eu recomendo que você use umfor
loop para aumentar a legibilidade do código e o melhor desempenho.Editar :
Se assumirmos que o loop é a abordagem mais rápida, podemos fazer algumas otimizações em torno do
find
comando.Especificamente
Faça
M
lógica. Como mostra o gráfico abaixo, isso pode ser mais rápido para relativamente pequenoM
, mas mais lento com a troca de conversão de tipo para grandeM
.Use um lógico
M
para indexar uma matriz em1:size(M,2)
vez de usarfind
. Isso evita a parte mais lenta do loop (ofind
comando) e supera a sobrecarga de conversão de tipo, tornando-a a opção mais rápida.Aqui está a minha recomendação para o melhor desempenho:
Adicionei isso à referência abaixo, eis a comparação de abordagens no estilo de loop:
Código de benchmarking:
fonte
M
. Se, por exemplo, apenas 5% dos elementos forem preenchidosM = randi([0,20],N) == 20;
, ofor
loop será de longe o mais lento e o seuarrayfun
método vencerá.accumarray
semind2sub
, mas é mais lenta que ofor
loopVocê pode tentar
arrayfun
como abaixo, que varre as linhas deM
ou (uma abordagem mais lenta por
mat2cell
)fonte
arrayfun
seja basicamente um disfarce, isso pode falhar nas duas frentes de 1) evitar loops e 2) ser rápido, conforme esperado pelo OPEdit : Eu adicionei uma referência, os resultados mostram que um loop for é mais eficiente do que
accumarray
.Você pode usar
find
eaccumarray
:A matriz é transposta (
A'
) porquefind
agrupa por coluna.Exemplo:
Resultado:
Referência:
Resultado:
Um loop for é mais eficiente que
accumarray
...fonte
Usando accumarray :
fonte
MM{I} = find(M(I, :))
.ind2sub
:[ii, jj] = find(M); accumarray(ii, jj, [], @(x){x})
Você pode usar strfind :
fonte
string
tipos reais do que caracteres? Existem muitas otimizações para as strings, daí a razão pela qual elas existem ...