Hàm ánh xạ trong MATLAB?


100

Tôi hơi ngạc nhiên khi MATLAB không có chức năng Bản đồ, vì vậy tôi đã tự hack một cái với nhau vì đó là thứ mà tôi không thể sống thiếu. Có phiên bản tốt hơn ngoài đó không? Có thư viện lập trình chức năng tiêu chuẩn nào đó cho MATLAB mà tôi đang thiếu không?

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

sử dụng sẽ là ví dụ

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

12
Bài học số 1 chuyển từ các ngôn ngữ khác sang Matlab: Không sử dụng vòng lặp for, chúng chậm hơn một vài bậc về độ lớn so với một giải pháp vector hóa.
CookieOfFortune

15
Với sự ra đời của JIT, các vòng lặp for không bị phạt như trước đây.
MatlabDoug

@CookieOfFortune Tôi nghĩ điều đó không còn đúng nữa ...
Ander Biguri

2
@AnderBiguri Tôi nghĩ rằng họ đã thêm một số cải tiến nhưng nó vẫn chậm hơn nhiều.
CookieOfFortune

Các thư viện chức năng vào File Exchange đã map, foldl(còn gọi là reduce), select(aka filter), và các tính năng không thể thiếu khác. Được đề xuất (nếu bạn phải sử dụng Matlab).
Ahmed Fasih

Câu trả lời:


133

Câu trả lời ngắn gọn: hàm tích hợp sẵn arrayfunthực hiện chính xác những gì maphàm của bạn thực hiện đối với mảng số:

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

     1     4     9    16    25    36    49    64    81   100

Có hai hàm tích hợp khác hoạt động tương tự: cellfun(hoạt động trên các phần tử của mảng ô) vàstructfun (hoạt động trên mỗi trường của cấu trúc).

Tuy nhiên, những chức năng này thường không cần thiết nếu bạn tận dụng lợi thế của vectơ hóa, cụ thể là sử dụng các toán tử số học khôn ngoan nguyên tố . Đối với ví dụ bạn đã đưa ra, một giải pháp được vector hóa sẽ là:

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

     1     4     9    16    25    36    49    64    81   100

Một số phép toán sẽ tự động hoạt động trên các phần tử (như thêm một giá trị vô hướng vào một vectơ) trong khi các toán tử khác có cú pháp đặc biệt cho phép toán thông minh phần tử (được ký hiệu bằng một .trước toán tử). Nhiều hàm tích hợp trong MATLAB được thiết kế để hoạt động trên các đối số vectơ và ma trận bằng cách sử dụng các phép toán khôn ngoan (thường được áp dụng cho một thứ nguyên nhất định, chẳng hạn như summean chẳng hạn) và do đó không yêu cầu các hàm bản đồ.

Tóm lại, đây là một số cách khác nhau để bình phương mỗi phần tử trong một mảng:

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

Tất nhiên, đối với một hoạt động đơn giản như vậy, tùy chọn số 1 là lựa chọn hợp lý nhất (và hiệu quả).


2
Cần lưu ý rằng tùy chọn 1 không chỉ đơn giản hơn mà còn nhanh hơn (so với tùy chọn 3, 2 phải rất giống với 1)!
Diederick C. Niehorster

10

Ngoài các phép toán vector và phần tử, còn có cellfuncác hàm ánh xạ qua các mảng ô. Ví dụ:

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

Nếu 'UniformOutput' là true (hoặc không được cung cấp), nó sẽ cố gắng nối các kết quả theo các kích thước của mảng ô, vì vậy

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

2

Một giải pháp khá đơn giản, sử dụng vectơ hóa của Matlab sẽ là:

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

Bây giờ, đang gõ

c( b ) = a

trả lại

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

c (b) là một tham chiếu đến một vectơ có kích thước 5 với các phần tử của c tại các chỉ số cho bởi b. Bây giờ nếu bạn gán giá trị cho vectơ tham chiếu này, các giá trị gốc trong c sẽ bị ghi đè, vì c (b) chứa các tham chiếu đến các giá trị trong c và không có bản sao.


1

Có vẻ như arrayfun tích hợp không hoạt động nếu kết quả cần là một mảng hàm: ví dụ: map (@ (x) [xx ^ 2 x ^ 3], 1: 10)

các mod nhỏ bên dưới giúp việc này hoạt động tốt hơn:

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 sẽ hoạt động cho ví dụ của bạn, bạn chỉ cần bao gồm các đối số đầu vào ..., 'UniformOutput', false);để tạo đầu ra mảng ô chứa các mảng của bạn, sau đó định dạng và kết hợp chúng theo cách bạn muốn thành một mảng không phải ô.
gnovice

0

Nếu matlab không có chức năng bản đồ tích hợp, đó có thể là do cân nhắc về hiệu quả. Trong quá trình triển khai của mình, bạn đang sử dụng một vòng lặp để lặp qua các phần tử của danh sách, điều này thường không được chú ý trong thế giới matlab. Hầu hết các hàm matlab tích hợp sẵn đều được "vectơ hóa", tức là sẽ hiệu quả hơn khi gọi một hàm trên toàn bộ mảng, hơn là tự mình lặp lại nó và gọi hàm cho từng phần tử.

Nói cách khác, điều này


a = 1:10;
a.^2

nhanh hơn nhiều


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

giả định định nghĩa của bạn về bản đồ.


2
Tôi nghĩ quan điểm của anh ấy không phải là anh ấy muốn nó nhất thiết phải lặp lại, mà chỉ đơn giản là được chỉ định là có một mảng kết quả của việc áp dụng hàm được cung cấp cho các phần tử tương ứng của mảng được cung cấp. Tôi không biết nhiều về matlab, nhưng có vẻ như arrayfun làm được việc.

1
Hầu hết các hàm và toán tử Matlab cài sẵn đã làm được điều đó: chúng hoạt động trên từng phần tử của mảng đầu vào và chúng trả về một mảng kết quả tương ứng.
Dima

0

Bạn không cần mapvì một hàm vô hướng được áp dụng cho danh sách các giá trị sẽ được áp dụng cho từng giá trị và do đó hoạt động tương tự như map. Cứ thử đi

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

f(l)

Trong trường hợp cụ thể của bạn, bạn thậm chí có thể viết

l.^2

9
-1: Điều đó thực sự không đúng. Matlab không có hệ thống kiểu đủ mạnh để chỉ định các hàm vô hướng. f được gọi với vectơ và một phép cộng vectơ đơn được thực hiện trong ví dụ của bạn. Để xác minh điều này, hãy lập hồ sơ mẫu mã của bạn ("hồ sơ trên" trước khi chạy mã, sau đó "hồ sơ tắt báo cáo" sau đó). Bạn sẽ thấy có một cuộc gọi duy nhất tới f.
Mr Fooz

-1

Vectơ hóa giải pháp như được mô tả trong các câu trả lời trước có lẽ là giải pháp tốt nhất cho tốc độ. Vectorizing cũng rất Matlaby và cảm thấy tốt.

Với điều đó, Matlab hiện có một lớp Map container.

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


Op đang nói về hàm bậc cao hơn, tức là, cellfunvà các cộng sự, không phải bảng băm hoặc các cặp khóa-giá trị.
Ahmed Fasih
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.