Ви можете застосувати функцію до кожного елемента у векторі, сказавши, наприклад v + 1
, або ви можете використовувати функцію arrayfun
. Як я можу це зробити для кожного рядка / стовпця матриці, не використовуючи цикл for?
Ви можете застосувати функцію до кожного елемента у векторі, сказавши, наприклад v + 1
, або ви можете використовувати функцію arrayfun
. Як я можу це зробити для кожного рядка / стовпця матриці, не використовуючи цикл for?
Відповіді:
Багатьом вбудованим операціям подобається sum
та prod
вже є можливість працювати через рядки чи стовпці, тож ви можете скористатися функцією, яку ви застосовуєте, щоб скористатися цією можливістю.
Якщо це не є життєздатним варіантом, один із способів зробити це - збирати рядки або стовпці в комірки за допомогою mat2cell
або num2cell
, а потім використовувати cellfun
для роботи над отриманим масивом комірок.
Наприклад, скажімо, що ви хочете підсумувати стовпці матриці M
. Зробити це можна просто за допомогою sum
:
M = magic(10); %# A 10-by-10 matrix
columnSums = sum(M, 1); %# A 1-by-10 vector of sums for each column
А ось як би ви це зробили, використовуючи складніший 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
є дійсне твердження, я впевнений, що ви можете це зробити (:
sum(M, 1)
. Початківці можуть подумати, що sum
їх можна використовувати таким чином для матриць довільного розміру, а потім застрягти, коли матриця одного дня 1-by-n
.
Можливо, ви хочете більш незрозумілу функцію Matlab bsxfun . З документації на Matlab, bsxfun "застосовує бінарні операції по елементам, визначені функцією обробки функції весело до масивів A і B, з включеним однотонним розширенням."
@gnovice зазначено вище, що сума та інші основні функції вже функціонують на першому не-однотонному вимірі (тобто рядки, якщо є більше одного рядка, стовпці, якщо є лише один рядок, або більш високі розміри, якщо всі нижчі розміри мають розмір == 1 ). Однак bsxfun працює для будь-якої функції, включаючи (і особливо) визначені користувачем функції.
Наприклад, скажімо, у вас є матриця A і векторний рядок BEg, скажімо:
A = [1 2 3;
4 5 6;
7 8 9]
B = [0 1 2]
Ви хочете функцію power_by_col, яка повертає у векторі C всі елементи в A на потужність відповідного стовпця B.
З наведеного вище прикладу, C - матриця 3x3:
C = [1^0 2^1 3^2;
4^0 5^1 6^2;
7^0 8^1 9^2]
тобто
C = [1 2 9;
1 5 36;
1 8 81]
Ви можете зробити це брутальним шляхом, використовуючи репмат:
C = A.^repmat(B, size(A, 1), 1)
Або ви могли зробити це класним способом, використовуючи bsxfun, який внутрішньо піклується про крок репмати:
C = bsxfun(@(x,y) x.^y, A, B)
Таким чином, bsxfun економить кілька кроків (не потрібно чітко обчислювати розміри A). Однак у деяких неформальних тестах виявляється, що репмат приблизно вдвічі швидший, якщо функція, яка застосовується (як і моя функція живлення, вище), проста. Тож вам потрібно буде вибрати, чи хочете ви простоти чи швидкості.
Я не можу коментувати, наскільки це ефективно, але ось таке рішення:
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)
Спираючись на відповідь Алекса , тут є більш загальна функція:
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));
Ось порівняння між двома функціями:
>> % 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))'
Для повноти / зацікавленості я хотів би додати, що у matlab є функція, яка дозволяє вам працювати з даними на рядок, а не з елементами. Він називається rowfun
( http://www.mathworks.se/help/matlab/ref/rowfun.html ), але єдиною "проблемою" є те, що він працює над таблицями ( http://www.mathworks.se/help/ matlab / ref / table.html ), а не матриці .
Додаючи відповідь на це запитання, що змінюється, починаючи з r2016b, MATLAB неявно розширить однотонні розміри, усуваючи потребу bsxfun
в багатьох випадках.
З приміток до випуску r2016b :
Неявне розширення: Застосовуйте елементарні операції та функції до масивів з автоматичним розширенням розмірів довжини 1
Неявне розширення - це узагальнення скалярного розширення. При скалярному розширенні скаляр розширюється на той же розмір, що й інший масив для полегшення стихійних операцій. При неявному розширенні перераховані тут елементарні оператори та функції можуть неявно розширювати свої входи такого ж розміру, поки масиви мають сумісні розміри. Два масиви мають сумісні розміри, якщо для кожного виміру розміри розмірів входів є однаковими або один з них є 1. Для отримання додаткової інформації див. Сумісні розміри масивів для основних операцій та операцій з масивом проти матриці.
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
Наприклад, ви можете обчислити середнє значення кожного стовпця в матриці A, а потім відняти вектор середніх значень з кожного стовпця з A - середнім (A).
Раніше ця функція була доступна через функцію bsxfun. Тепер рекомендується замінити більшість застосувань bsxfun прямими дзвінками до функцій та операторів, які підтримують неявне розширення. У порівнянні з використанням bsxfun, неявне розширення пропонує більш високу швидкість, краще використання пам’яті та покращену читабельність коду.
Жодна з перерахованих вище відповідей для мене не працювала "поза коробкою", проте працює наступна функція, отримана при копіюванні ідей інших відповідей:
apply_func_2_cols = @(f,M) cell2mat(cellfun(f,num2cell(M,1), 'UniformOutput',0));
Він бере функцію f
і застосовує її до кожного стовпця матриці M
.
Так, наприклад:
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
З останніми версіями Matlab ви можете використовувати структуру даних таблиці на вашу користь. Існує навіть операція "rowfun", але мені було легше зробити це:
a = magic(6);
incrementRow = cell2mat(cellfun(@(x) x+1,table2cell(table(a)),'UniformOutput',0))
або ось старіший у мене, який не потребує таблиць, для старих версій Matlab.
dataBinner = cell2mat(arrayfun(@(x) Binner(a(x,:),2)',1:size(a,1),'UniformOutput',0)')
Здається, прийнята відповідь полягає в тому, щоб спочатку перетворити на клітини, а потім використовувати cellfun
для роботи над усіма клітинками. Я не знаю конкретної програми, але в цілому, я думаю, що використання bsxfun
для роботи над матрицею було б більш ефективним. В основному bsxfun
застосовується операція по елементам через два масиви. Отже, якщо ви хочете помножити кожен елемент у n x 1
векторному на кожен елемент у m x 1
векторі, щоб отримати n x m
масив, ви можете використовувати:
vec1 = [ stuff ]; % n x 1 vector
vec2 = [ stuff ]; % m x 1 vector
result = bsxfun('times', vec1.', vec2);
Це дасть вам матрицю під назвою, result
де запис (i, j) буде i-м елементом, vec1
помноженим на j-й елемент vec2
.
Ви можете використовувати bsxfun
для всіляких вбудованих функцій, а ви можете заявити про власну. У документації є перелік багатьох вбудованих функцій, але в основному ви можете назвати будь-яку функцію, яка приймає два масиви (вектор або матрицю) як аргументи, і змушує її працювати.
Натрапили на це питання / відповідь, шукаючи, як обчислити рядкові суми матриці.
Я хотів би лише додати, що функція SUM Matlab насправді підтримує підсумовування заданого виміру, тобто стандартну матрицю з двома вимірами.
Отже, для обчислення сум стовпців виконайте:
colsum = sum(M) % or sum(M, 1)
а для рядкових сум просто зробити
rowsum = sum(M, 2)
Моя обставина, це швидше, ніж програмування циклу для циклу та перетворення на комірки :)
Все це можна знайти у довідці з matlab для SUM.
якщо ви знаєте довжину своїх рядів, ви можете зробити щось подібне:
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) )