Możesz zastosować funkcję do każdego elementu w wektorze, mówiąc na przykład v + 1
, lub możesz użyć funkcji arrayfun
. Jak mogę to zrobić dla każdego wiersza / kolumny macierzy bez używania pętli for?
Możesz zastosować funkcję do każdego elementu w wektorze, mówiąc na przykład v + 1
, lub możesz użyć funkcji arrayfun
. Jak mogę to zrobić dla każdego wiersza / kolumny macierzy bez używania pętli for?
Odpowiedzi:
Wiele wbudowanych operacji, takich jak sum
i prod
jest już w stanie działać w wierszach lub kolumnach, więc możesz być w stanie refaktoryzować funkcję, którą stosujesz, aby to wykorzystać.
Jeśli nie jest to wykonalna opcja, jednym ze sposobów jest zebranie wierszy lub kolumn do komórek za pomocą mat2cell
lub num2cell
, a następnie użycie cellfun
operacji na wynikowej tablicy komórek.
Jako przykład, powiedzmy, że chcesz zsumować kolumny macierzy M
. Możesz to zrobić po prostu za pomocą sum
:
M = magic(10); %# A 10-by-10 matrix
columnSums = sum(M, 1); %# A 1-by-10 vector of sums for each column
A oto, jak byś to zrobił, używając bardziej skomplikowanej opcji num2cell
/ cellfun
:
M = magic(10); %# A 10-by-10 matrix
C = num2cell(M, 1); %# Collect the columns into cells
columnSums = cellfun(@sum, C); %# A 1-by-10 vector of sums for each cell
true = false
jest ważne stwierdzenie, jestem pewien, że jest to sposób w jaki można to zrobić (:
sum(M, 1)
. Początkujący mogą pomyśleć, że sum
można go użyć w ten sposób do macierzy o dowolnej wielkości, a potem wpadną w zakłopotanie, gdy macierz pewnego dnia jest 1-by-n
.
Możesz potrzebować bardziej niejasnej funkcji Matlab bsxfun . Z dokumentacji Matlaba, bsxfun „stosuje operację binarną element po elemencie określoną przez funkcję uchwyt fun do tablic A i B, z włączoną ekspansją pojedynczych elementów”.
@gnovice stwierdził powyżej, że suma i inne podstawowe funkcje już działają na pierwszym nie-pojedynczym wymiarze (tj. wiersze, jeśli jest więcej niż jeden wiersz, kolumny, jeśli jest tylko jeden wiersz, lub wyższe wymiary, jeśli wszystkie niższe wymiary mają rozmiar == 1 ). Jednak bsxfun działa dla każdej funkcji, w tym (a zwłaszcza) funkcji zdefiniowanych przez użytkownika.
Na przykład, powiedzmy, że masz macierz A i wektor wierszowy BEg, powiedzmy:
A = [1 2 3;
4 5 6;
7 8 9]
B = [0 1 2]
Potrzebujesz funkcji power_by_col, która zwraca w wektorze C wszystkie elementy w A do potęgi odpowiedniej kolumny B.
Z powyższego przykładu C to macierz 3x3:
C = [1^0 2^1 3^2;
4^0 5^1 6^2;
7^0 8^1 9^2]
to znaczy,
C = [1 2 9;
1 5 36;
1 8 81]
Możesz to zrobić brutalną siłą używając repmat:
C = A.^repmat(B, size(A, 1), 1)
Lub możesz to zrobić w klasyczny sposób za pomocą bsxfun, który wewnętrznie zajmuje się krokiem repmat:
C = bsxfun(@(x,y) x.^y, A, B)
Więc bsxfun oszczędza ci kilku kroków (nie musisz jawnie obliczać wymiarów A). Jednak w niektórych moich nieformalnych testach okazuje się, że repmat jest mniej więcej dwa razy szybszy, jeśli funkcja, która ma zostać zastosowana (jak moja funkcja potęgowa, powyżej) jest prosta. Musisz więc wybrać, czy chcesz prostoty, czy szybkości.
Nie mogę komentować, jak wydajne jest to, ale oto rozwiązanie:
applyToGivenRow = @(func, matrix) @(row) func(matrix(row, :))
applyToRows = @(func, matrix) arrayfun(applyToGivenRow(func, matrix), 1:size(matrix,1))'
% Example
myMx = [1 2 3; 4 5 6; 7 8 9];
myFunc = @sum;
applyToRows(myFunc, myMx)
Opierając się na odpowiedzi Alexa , oto bardziej ogólna funkcja:
applyToGivenRow = @(func, matrix) @(row) func(matrix(row, :));
newApplyToRows = @(func, matrix) arrayfun(applyToGivenRow(func, matrix), 1:size(matrix,1), 'UniformOutput', false)';
takeAll = @(x) reshape([x{:}], size(x{1},2), size(x,1))';
genericApplyToRows = @(func, matrix) takeAll(newApplyToRows(func, matrix));
Oto porównanie między tymi dwiema funkcjami:
>> % Example
myMx = [1 2 3; 4 5 6; 7 8 9];
myFunc = @(x) [mean(x), std(x), sum(x), length(x)];
>> genericApplyToRows(myFunc, myMx)
ans =
2 1 6 3
5 1 15 3
8 1 24 3
>> applyToRows(myFunc, myMx)
??? Error using ==> arrayfun
Non-scalar in Uniform output, at index 1, output 1.
Set 'UniformOutput' to false.
Error in ==> @(func,matrix)arrayfun(applyToGivenRow(func,matrix),1:size(matrix,1))'
Dla kompletności / zainteresowania chciałbym dodać, że Matlab ma funkcję, która pozwala operować na danych na wiersz, a nie na element. Nazywa się rowfun
( http://www.mathworks.se/help/matlab/ref/rowfun.html ), ale jedynym „problemem” jest to, że działa na tabelach ( http://www.mathworks.se/help/ matlab / ref / table.html ) zamiast macierzy .
Dodając do ewoluującego charakteru odpowiedzi na to pytanie, począwszy od r2016b, MATLAB niejawnie rozszerzy pojedyncze wymiary, eliminując potrzebę bsxfun
w wielu przypadkach.
Z informacji o wersji r2016b :
Niejawna ekspansja: zastosuj operacje i funkcje elementarne do tablic z automatycznym rozszerzaniem wymiarów długości 1
Niejawna ekspansja jest uogólnieniem ekspansji skalarnej. Przy rozszerzaniu skalarnym skalar rozwija się do tego samego rozmiaru co inna tablica, aby ułatwić operacje na elementach. W przypadku niejawnego rozwinięcia wymienione tutaj operatory i funkcje elementarne mogą niejawnie rozszerzyć swoje dane wejściowe, aby miały ten sam rozmiar, o ile tablice mają zgodne rozmiary. Dwie tablice mają zgodne rozmiary, jeśli dla każdego wymiaru rozmiary wymiarów wejściowych są takie same lub jeden z nich wynosi 1. Aby uzyskać więcej informacji, zobacz Zgodne rozmiary tablic dla operacji podstawowych i Operacje na macierzach i macierzach.
Element-wise arithmetic operators — +, -, .*, .^, ./, .\ Relational operators — <, <=, >, >=, ==, ~= Logical operators — &, |, xor Bit-wise functions — bitand, bitor, bitxor Elementary math functions — max, min, mod, rem, hypot, atan2, atan2d
Na przykład możesz obliczyć średnią z każdej kolumny w macierzy A, a następnie odjąć wektor średnich wartości z każdej kolumny za pomocą A - średnia (A).
Wcześniej ta funkcjonalność była dostępna za pośrednictwem funkcji bsxfun. Obecnie zaleca się zastąpienie większości zastosowań bsxfun bezpośrednimi wywołaniami funkcji i operatorów obsługujących niejawne rozwinięcie. W porównaniu z używaniem bsxfun, niejawna ekspansja zapewnia większą prędkość, lepsze wykorzystanie pamięci i lepszą czytelność kodu.
Żadna z powyższych odpowiedzi nie zadziałała dla mnie „po wyjęciu z pudełka”, jednak następująca funkcja, uzyskana poprzez skopiowanie pomysłów z innych odpowiedzi, działa:
apply_func_2_cols = @(f,M) cell2mat(cellfun(f,num2cell(M,1), 'UniformOutput',0));
Pobiera funkcję f
i stosuje ją do każdej kolumny macierzyM
.
Na przykład:
f = @(v) [0 1;1 0]*v + [0 0.1]';
apply_func_2_cols(f,[0 0 1 1;0 1 0 1])
ans =
0.00000 1.00000 0.00000 1.00000
0.10000 0.10000 1.10000 1.10000
Dzięki najnowszym wersjom Matlab możesz wykorzystać strukturę danych tabeli na swoją korzyść. Jest nawet operacja typu `` rowfun '', ale okazało się, że łatwiej jest to zrobić:
a = magic(6);
incrementRow = cell2mat(cellfun(@(x) x+1,table2cell(table(a)),'UniformOutput',0))
lub tutaj jest starszy, który miałem, który nie wymaga tabel, dla starszych wersji Matlab.
dataBinner = cell2mat(arrayfun(@(x) Binner(a(x,:),2)',1:size(a,1),'UniformOutput',0)')
Zaakceptowaną odpowiedzią wydaje się być najpierw konwersja na komórki, a następnie użycie cellfun
do operacji na wszystkich komórkach. Nie znam konkretnej aplikacji, ale generalnie myślę, że użycie bsxfun
do operowania na matrycy byłoby bardziej wydajne. Zasadniczo bsxfun
stosuje operację element po elemencie w dwóch tablicach. Więc jeśli chcesz pomnożyć każdy element w n x 1
wektorze przez każdy element w m x 1
wektorze, aby uzyskać n x m
tablicę, możesz użyć:
vec1 = [ stuff ]; % n x 1 vector
vec2 = [ stuff ]; % m x 1 vector
result = bsxfun('times', vec1.', vec2);
To da ci macierz o nazwie, w result
której pozycja (i, j) będzie i-tym elementem vec1
pomnożonej przez j-ty element funkcjivec2
.
Możesz używać bsxfun
do wszelkiego rodzaju wbudowanych funkcji i możesz zadeklarować własne. Dokumentacja zawiera listę wielu wbudowanych funkcji, ale w zasadzie możesz nazwać dowolną funkcję, która przyjmuje dwie tablice (wektor lub macierz) jako argumenty i uruchomić ją.
Natknąłem się na to pytanie / odpowiedź, szukając sposobu obliczenia sum wierszy macierzy.
Chciałbym tylko dodać, że funkcja SUMA Matlaba faktycznie obsługuje sumowanie dla danego wymiaru, czyli standardowej macierzy z dwoma wymiarami.
Aby obliczyć sumy kolumn, wykonaj:
colsum = sum(M) % or sum(M, 1)
a dla sum wierszy po prostu zrób
rowsum = sum(M, 2)
Założę się, że jest to szybsze niż programowanie pętli for i konwersja do komórek :)
Wszystko to można znaleźć w pomocy Matlab dla programu SUM.
jeśli znasz długość swoich rzędów, możesz zrobić coś takiego:
a=rand(9,3);
b=rand(9,3);
arrayfun(@(x1,x2,y1,y2,z1,z2) line([x1,x2],[y1,y2],[z1,z2]) , a(:,1),b(:,1),a(:,2),b(:,2),a(:,3),b(:,3) )