Estoy trabajando con Matlab.
Tengo una matriz cuadrada binaria. Para cada fila, hay una o más entradas de 1. Quiero pasar por cada fila de esta matriz y devolver el índice de esos 1s y almacenarlos en la entrada de una celda.
Me preguntaba si hay una manera de hacer esto sin recorrer todas las filas de esta matriz, ya que el ciclo es realmente lento en Matlab.
Por ejemplo, mi matriz
M = 0 1 0
1 0 1
1 1 1
Luego, eventualmente, quiero algo como
A = [2]
[1,3]
[1,2,3]
Entonces A
es una célula.
¿Hay alguna manera de lograr este objetivo sin usar for loop, con el objetivo de calcular el resultado más rápidamente?
matlab
vectorization
ftxx
fuente
fuente
for
bucles? Para este problema, con las versiones modernas de MATLAB, sospecho que unfor
bucle es la solución más rápida. Si tiene un problema de rendimiento, sospecho que está buscando la solución en el lugar equivocado en base a consejos desactualizados.cellfun
.1
s en una fila típica? No esperaría que unfind
ciclo tome algo cercano a 30 años para algo lo suficientemente pequeño como para caber en la memoria física.Respuestas:
Al final de esta respuesta hay un código de evaluación comparativa, ya que usted aclaró que está interesado en el rendimiento en lugar de evitar arbitrariamente los
for
bucles.De hecho, creo que los
for
bucles son probablemente la opción más eficaz aquí. Desde que se introdujo el "nuevo" (2015b) motor JIT ( fuente ), losfor
bucles no son inherentemente lentos, de hecho, están optimizados internamente.Puede ver desde el punto de referencia que la
mat2cell
opción ofrecida por ThomasIsCoding aquí es muy lenta ...Si nos deshacemos de esa línea para
splitapply
aclarar la escala, entonces mi método es bastante lento, la opción accumarray de obchardon es un poco mejor, pero las opciones más rápidas (y comparables) están usandoarrayfun
(como también lo sugiere Thomas) o unfor
bucle. Tenga en cuenta quearrayfun
es básicamente unfor
bucle disfrazado para la mayoría de los casos de uso, ¡así que no es un lazo sorprendente!Le recomendaría que use unfor
bucle para aumentar la legibilidad del código y el mejor rendimiento.Editar :
Si suponemos que el bucle es el enfoque más rápido, podemos hacer algunas optimizaciones en torno al
find
comando.Específicamente
Hacer
M
lógico Como se muestra en el gráfico a continuación, esto puede ser más rápido para relativamente pequeñoM
, pero más lento con el intercambio de conversión de tipo para grandeM
.Use un lógico
M
para indexar una matriz en1:size(M,2)
lugar de usarfind
. Esto evita la parte más lenta del bucle (elfind
comando) y supera la sobrecarga de conversión de tipo, por lo que es la opción más rápida.Aquí está mi recomendación para el mejor rendimiento:
He agregado esto al punto de referencia a continuación, aquí está la comparación de los enfoques de estilo de bucle:
Código de evaluación comparativa:
fuente
M
. Si, por ejemplo, solo se llenaM = randi([0,20],N) == 20;
el 5% de los elementos, entonces elfor
ciclo es, con mucho, el más lento y suarrayfun
método gana.accumarray
sinind2sub
, pero es más lento que elfor
cicloPuede intentar
arrayfun
como a continuación, que barre filas deM
o (un enfoque más lento por
mat2cell
)fuente
arrayfun
es básicamente un disfraz de bucle, por lo que esto puede fallar en ambos frentes de 1) evitar bucles y 2) ser rápido, como esperaba el OPEditar : agregué un punto de referencia, los resultados muestran que un bucle for es más eficiente que
accumarray
.Puedes usar
find
yaccumarray
:La matriz se transpone (
A'
) porque sefind
agrupa por columna.Ejemplo:
Salida:
Punto de referencia:
Resultado:
Un bucle for es más eficiente que
accumarray
...fuente
Usando accumarray :
fuente
MM{I} = find(M(I, :))
.ind2sub
:[ii, jj] = find(M); accumarray(ii, jj, [], @(x){x})
Puedes usar strfind :
fuente
string
tipos reales , en lugar de caracteres? Hay muchas optimizaciones para las cadenas, de ahí por qué existen ...