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)
Will Ness
źródło
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.

gnovice
źródło
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
kwatford
źródło
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.

doc
źródło
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
Foo Bara
źródło
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.

Dima
źródło
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
Dario
źródło
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

TallBrian
źródło
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