¿Función de mapa en MATLAB?

100

Estoy un poco sorprendido de que MATLAB no tenga una función de mapa, así que yo mismo pirateé una, ya que es algo sin lo que no puedo vivir. ¿Existe una versión mejor? ¿Existe una biblioteca de programación funcional algo estándar para MATLAB que me falta?

function results = map(f,list)
% why doesn't MATLAB have a Map function?
results = zeros(1,length(list));
for k = 1:length(list)
    results(1,k) = f(list(k));
end

end

el uso sería, por ejemplo,

map( @(x)x^2,1:10)
Will Ness
fuente
12
Lección n. ° 1 pasando de otros lenguajes a Matlab: No use bucles for, son unos órdenes de magnitud más lentos que una solución vectorizada.
CookieOfFortune
15
Con la introducción del JIT, los bucles for no sufren la penalización que solían tener.
MatlabDoug
@CookieOfFortune Creo que eso ya no es cierto ...
Ander Biguri
2
@AnderBiguri Creo que han agregado algunas mejoras, pero aún es mucho más lento.
CookieOfFortune
La biblioteca funcional de intercambio de archivos tiene map, foldl(también conocido como reduce), select( también conocido como ) filtery otros beneficios indispensables. Recomendado (si tiene que usar Matlab).
Ahmed Fasih

Respuestas:

133

La respuesta corta: la función incorporada arrayfunhace exactamente lo que hace su mapfunción para matrices numéricas:

>> y = arrayfun(@(x) x^2, 1:10)
y =

     1     4     9    16    25    36    49    64    81   100

Hay otras dos funciones integradas que se comportan de manera similar: cellfun(que opera en elementos de matrices de celdas) y structfun(que opera en cada campo de una estructura).

Sin embargo, estas funciones a menudo no son necesarias si aprovecha la vectorización, específicamente utilizando operadores aritméticos de elementos . Para el ejemplo que dio, una solución vectorizada sería:

>> x = 1:10;
>> y = x.^2
y =

     1     4     9    16    25    36    49    64    81   100

Algunas operaciones operarán automáticamente entre elementos (como agregar un valor escalar a un vector), mientras que otros operadores tienen una sintaxis especial para la operación de elementos (indicada por una .antes del operador). Muchas funciones integradas en MATLAB están diseñadas para operar en argumentos vectoriales y matriciales utilizando operaciones basadas en elementos (a menudo aplicadas a una dimensión determinada, como sumy meanpor ejemplo) y, por lo tanto, no requieren funciones de mapa.

Para resumir, aquí hay algunas formas diferentes de cuadrar cada elemento en una matriz:

x = 1:10;       % Sample array
f = @(x) x.^2;  % Anonymous function that squares each element of its input

% Option #1:
y = x.^2;  % Use the element-wise power operator

% Option #2:
y = f(x);  % Pass a vector to f

% Option #3:
y = arrayfun(f, x);  % Pass each element to f separately

Por supuesto, para una operación tan simple, la opción # 1 es la opción más sensata (y eficiente).

gnovice
fuente
2
Hay que tener en cuenta que la opción 1 no solo es más sencilla, sino también más rápida (en comparación con la opción 3, ¡la 2 debería ser muy similar a la 1)!
Diederick C. Niehorster
10

Además de las operaciones vectoriales y de elementos, también hay cellfunfunciones de mapeo sobre matrices de celdas. Por ejemplo:

cellfun(@upper, {'a', 'b', 'c'}, 'UniformOutput',false)
ans = 
    'A'    'B'    'C'

Si 'UniformOutput' es verdadero (o no se proporciona), intentará concatenar los resultados de acuerdo con las dimensiones de la matriz de celdas, por lo que

cellfun(@upper, {'a', 'b', 'c'})
ans =
ABC
kwatford
fuente
2

Una solución bastante simple, usando la vectorización de Matlab, sería:

a = [ 10 20 30 40 50 ]; % the array with the original values
b = [ 10 8 6 4 2 ]; % the mapping array
c = zeros( 1, 10 ); % your target array

Ahora, escribiendo

c( b ) = a

devoluciones

c = 0    50     0    40     0    30     0    20     0    10

c (b) es una referencia a un vector de tamaño 5 con los elementos de c en los índices dados por b. Ahora, si asigna valores a este vector de referencia, los valores originales en c se sobrescriben, ya que c (b) contiene referencias a los valores en c y no hay copias.

Doc
fuente
1

Parece que la función de matriz incorporada no funciona si el resultado necesario es una matriz de función: por ejemplo: mapa (@ (x) [xx ^ 2 x ^ 3], 1:10)

las modificaciones leves a continuación hacen que esto funcione mejor:

function results = map(f,list)
% why doesn't MATLAB have a Map function?
for k = 1:length(list)
    if (k==1)
        r1=f(list(k));
        results = zeros(length(r1),length(list));
        results(:,k)=r1;
    else
        results(:,k) = f(list(k));

    end;
end;
end
Foo Bara
fuente
5
ARRAYFUN funcionaría para su ejemplo, solo tendría que incluir los argumentos de entrada ..., 'UniformOutput', false);para crear una salida de matriz de celdas que contenga sus matrices, luego formatee y combine como desee en una matriz que no sea de celda.
gnovice
0

Si matlab no tiene una función de mapa incorporada, podría deberse a consideraciones de eficiencia. En su implementación, está utilizando un bucle para iterar sobre los elementos de la lista, que generalmente está mal visto en el mundo de matlab. La mayoría de las funciones integradas de matlab están "vectorizadas", es decir, es más eficiente llamar a una función en una matriz completa, que iterar sobre ella y llamar a la función para cada elemento.

En otras palabras, este


a = 1:10;
a.^2

es mucho más rápido que esto


a = 1:10;
map(@(x)x^2, a)

asumiendo su definición de mapa.

Dima
fuente
2
Creo que su punto no era que quisiera necesariamente que se repitiera, sino simplemente que se especificara como resultado de la matriz de resultados de aplicar la función proporcionada a los elementos correspondientes de la matriz proporcionada. No sé mucho de matlab, pero parece que arrayfun hace el trabajo.
1
La mayoría de las funciones y operadores incorporados de Matlab ya lo hacen: operan en cada elemento de la matriz de entrada y devuelven una matriz correspondiente de resultados.
Dima
0

No es necesario, mapya que una función escalar que se aplica a una lista de valores se aplica a cada uno de los valores y, por lo tanto, funciona de manera similar a map. Sólo inténtalo

l = 1:10
f = @(x) x + 1

f(l)

En tu caso particular, incluso podrías escribir

l.^2
Darío
fuente
9
-1: Eso en realidad no es cierto. Matlab no tiene un sistema de tipos lo suficientemente fuerte para especificar funciones escalares. f se llama con el vector y se realiza una sola suma de vector en su ejemplo. Para verificar esto, perfile tu muestra de código ("perfil activado" antes de ejecutar el código, luego "perfil desactivado informe" después). Verá que hay una única llamada a f.
Mr Fooz
-1

Vectorizar la solución como se describe en las respuestas anteriores es probablemente la mejor solución para la velocidad. La vectorización también es muy Matlaby y se siente bien.

Dicho esto, Matlab ahora tiene una clase de contenedor Map.

Consulte http://www.mathworks.com/help/matlab/map-containers.html

TallBrian
fuente
Op está hablando de la función de orden superior, es decir, cellfunet al., No de tablas hash o pares clave-valor.
Ahmed Fasih