Funkcja mapowania w MATLAB?


100

Jestem trochę zaskoczony, że MATLAB nie ma funkcji Map, więc zhakowałem jeden razem, ponieważ jest to coś, bez czego nie mogę żyć. Czy jest tam lepsza wersja? Czy jest jakaś standardowa funkcjonalna biblioteka programistyczna dla MATLAB, której brakuje?

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

użycie byłoby np

map( @(x)x^2,1:10)

12
Lekcja 1 - przejście z innych języków do Matlab: nie używaj pętli, są one o kilka rzędów wielkości wolniejsze niż rozwiązania wektoryzowane.
CookieOfFortune

15
Wraz z wprowadzeniem JIT pętle for nie ponoszą takiej kary jak kiedyś.
MatlabDoug

@CookieOfFortune Myślę, że to już nieprawda ...
Ander Biguri

2
@AnderBiguri Myślę, że dodali kilka ulepszeń, ale nadal jest znacznie wolniejszy.
CookieOfFortune

Biblioteka funkcjonalna na pliku wymiany ma map, foldl(znany również jako reduce), select(aka filter) oraz inne niezbędne gadżety. Zalecane (jeśli musisz używać Matlab).
Ahmed Fasih

Odpowiedzi:


133

Krótka odpowiedź: funkcja wbudowana arrayfunrobi dokładnie to samo, co twoja mapfunkcja dla tablic numerycznych:

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

     1     4     9    16    25    36    49    64    81   100

Istnieją dwie inne wbudowane funkcje, które zachowują się podobnie: cellfun(które działają na elementach tablic komórek) i structfun(które działają na każdym polu struktury).

Jednak te funkcje często nie są konieczne, jeśli korzystasz z wektoryzacji, w szczególności przy użyciu operatorów arytmetycznych opartych na elementach . Na przykład, który podałeś, wektoryzowanym rozwiązaniem byłoby:

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

     1     4     9    16    25    36    49    64    81   100

Niektóre operacje będą automatycznie działać na elementach (np. Dodawanie wartości skalarnej do wektora), podczas gdy inne operatory mają specjalną składnię dla operacji elementarnych (oznaczoną a .przed operatorem). Wiele funkcji wbudowanych w MATLAB-ie jest zaprojektowanych do działania na argumentach wektorowych i macierzowych za pomocą operacji elementarnych (często stosowanych do danego wymiaru, takiego jak sumi meanna przykład), a zatem nie wymaga funkcji mapowania.

Podsumowując, oto kilka różnych sposobów prostowania każdego elementu w tablicy:

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

Oczywiście dla tak prostej operacji opcja nr 1 jest najbardziej rozsądnym (i wydajnym) wyborem.


2
Należy zauważyć, że opcja 1 jest nie tylko prostsza, ale także szybsza (w porównaniu do opcji 3, 2 powinna być bardzo podobna do 1)!
Diederick C. Niehorster,

10

Oprócz operacji opartych na wektorach i elementach istnieje również cellfunfunkcja mapowania funkcji na tablicach komórek. Na przykład:

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

Jeśli parametr „UniformOutput” ma wartość true (lub nie został podany), spróbuje połączyć wyniki zgodnie z wymiarami tablicy komórek, więc

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

2

Dość prostym rozwiązaniem, wykorzystującym wektoryzację Matlaba, byłoby:

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

Teraz piszę

c( b ) = a

zwroty

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

c (b) jest odniesieniem do wektora o rozmiarze 5 z elementami c przy indeksach podanych przez b. Teraz, jeśli przypiszesz wartości do tego wektora odniesienia, oryginalne wartości w c zostaną nadpisane, ponieważ c (b) zawiera odniesienia do wartości c i żadnych kopii.


1

Wygląda na to, że wbudowana funkcja arrayfun nie działa, jeśli wynikiem jest tablica funkcji: np .: map (@ (x) [xx ^ 2 x ^ 3], 1: 10)

niewielkie modyfikacje poniżej sprawiają, że działa to lepiej:

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

5
ARRAYFUN zadziałałoby w twoim przykładzie, wystarczyłoby dołączyć argumenty wejściowe, ..., 'UniformOutput', false);aby utworzyć wynikową tablicę komórek zawierającą twoje tablice, a następnie sformatować i połączyć je w dowolny sposób w tablicę inną niż komórkowa.
gnovice

0

Jeśli Matlab nie ma wbudowanej funkcji mapy, może to być spowodowane względami wydajności. W swojej implementacji używasz pętli do iteracji po elementach listy, co jest generalnie źle widziane w świecie Matlab. Większość wbudowanych funkcji Matlab jest „wektoryzowana”, co oznacza, że ​​bardziej wydajne jest wywołanie funkcji na całej tablicy niż samodzielne iterowanie po niej i wywoływanie funkcji dla każdego elementu.

Innymi słowy, to


a = 1:10;
a.^2

jest znacznie szybszy niż to


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

zakładając twoją definicję mapy.


2
Myślę, że nie chodziło mu o to, że chciał, aby to koniecznie zapętliło się, ale po prostu aby zostało określone jako mające w rezultacie tablicę wyników zastosowania dostarczonej funkcji do odpowiednich elementów dostarczonej tablicy. Nie znam wiele Matlab, ale wygląda na to, że arrayfun wykonuje swoją pracę.

1
Większość wbudowanych funkcji i operatorów Matlaba już to robi: działają na każdym elemencie tablicy wejściowej i zwracają odpowiednią tablicę wyników.
Dima

0

Nie potrzebujesz, mapponieważ funkcja skalarna, która jest stosowana do listy wartości, jest stosowana do każdej z wartości i dlatego działa podobnie do map. Spróbuj

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

f(l)

W twoim konkretnym przypadku możesz nawet pisać

l.^2

9
-1: To właściwie nieprawda. Matlab nie ma wystarczająco silnego systemu typów, aby określać funkcje skalarne. f jest wywoływana wraz z wektorem, aw naszym przykładzie wykonywane jest dodawanie pojedynczego wektora. Aby to sprawdzić, profiluj przykładowy kod („włącz profil” przed uruchomieniem kodu, a po nim „wyłącz profil”). Zobaczysz, że jest jedno wezwanie do f.
Pan Fooz,

-1

Wektoryzacja rozwiązania opisanego w poprzednich odpowiedziach jest prawdopodobnie najlepszym rozwiązaniem dla szybkości. Wektoryzacja jest również bardzo matowa i dobrze się czuje.

Powiedziawszy to, Matlab ma teraz klasę kontenera Map.

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


Op mówi o funkcji wyższego rzędu, tj. cellfunEt al., A nie o tabelach skrótów ani parach klucz-wartość.
Ahmed Fasih
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.