Как я могу применить функцию к каждой строке/столбцу матрицы в MATLAB?

Вы можете применить функцию к каждому элементу в векторе, произнеся, например, v + 1, или вы можете использовать функцию arrayfun. Как это сделать для каждой строки/столбца матрицы без использования цикла for?

Ответ 1

Многие встроенные операции, такие как 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

Ответ 2

Вам может понадобиться более неясная функция Matlab bsxfun. Из документации Matlab bsxfun "применяет двоичную операцию" элемент за элементом ", указанную функциональным дескриптором fun для массивов A и B, с включенным расширением Singleton".

@gnovice заявил выше, что сумма и другие базовые функции уже действуют на первый размер не одиночного элемента (т.е. строки, если имеется более одной строки, столбцы, если есть только одна строка или более высокие размеры, если все размеры меньшего размера имеют размер == 1). Однако bsxfun работает для любой функции, включая (и особенно) пользовательские функции.

Например, предположим, что у вас есть матрица A и вектор-строка B. Например, скажем:

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]

Вы можете сделать это методом грубой силы, используя repmat:

C = A.^repmat(B, size(A, 1), 1)

Или вы могли бы сделать это классным способом, используя bsxfun, который внутренне заботится о шаге repmat:

C = bsxfun(@(x,y) x.^y, A, B)

Итак, bsxfun сэкономит вам несколько шагов (вам не нужно явно вычислять размеры A). Однако в некоторых неофициальных моих тестах получается, что repmat примерно в два раза быстрее, если функция, которая будет применяться (например, моя функция мощности выше) проста. Поэтому вам нужно будет выбрать, хотите ли вы простоту или скорость.

Ответ 3

Я не могу прокомментировать, насколько это эффективно, но вот решение:

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)

Ответ 4

Основываясь на Alex answer, вот более общая функция:

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))'

Ответ 5

Для полноты/интереса я хотел бы добавить, что у matlab есть функция, которая позволяет вам работать с данными в строке, а не за элементом. Он называется rowfun (http://www.mathworks.se/help/matlab/ref/rowfun.html), но единственной "проблемой" является то, что он работает с таблицами (http://www.mathworks.se/help/matlab/ref/table.html), а не матрицы.

Ответ 6

Добавляя к эволюционирующему характеру ответа на этот вопрос, начиная с r2016b, MATLAB будет неявно расширять размеры Singleton, устраняя необходимость во bsxfun во многих случаях.

Из примечания к выпуску r2016b:

Неявное расширение: применяйте элементарные операции и функции к массивам с автоматическим расширением размеров длины 1

Неявное расширение является обобщением скалярного разложения. С скалярное расширение, скаляр расширяется до того же размера, что и другой массив для облегчения действий по элементам. При неявном расширении, элементарные операторы и функции, перечисленные здесь, могут неявно расширяйте свои входы до того же размера, если массивы имеют совместимые размеры. Два массива имеют совместимые размеры, если для каждого размерность размеров входов либо одинакова, либо один из них - 1. См. раздел Совместимые размеры массивов для основных операций и Array vs. Matrix Operations для получения дополнительной информации.

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, а затем вычесть вектор средних значений из каждого столбца с А - означают (А).

Ранее эта функция была доступна через функцию bsxfun. В настоящее время рекомендуется заменить большинство применений bsxfun на прямые вызывает функции и операторы, которые поддерживают неявное расширение. По сравнению с использованием bsxfun неявное расширение предлагает более быструю скорость, улучшенное использование памяти и улучшенная читаемость кода.

Ответ 7

Кажется, что принятым ответом является сначала преобразование в ячейки, а затем использование cellfun для работы со всеми ячейками. Я не знаю конкретного приложения, но в целом я думаю, что использование bsxfun для работы с матрицей будет более эффективным. В основном bsxfun применяет операцию поэлементно к двум массивам. Поэтому, если вы хотите умножить каждый элемент в векторе nx 1 на каждый элемент в векторе mx 1 чтобы получить массив nxm, вы можете использовать:

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 для всех видов встроенных функций, и вы можете объявить свои собственные. В документации есть список многих встроенных функций, но в основном вы можете назвать любую функцию, которая принимает два массива (вектор или матрицу) в качестве аргументов, и заставить ее работать.

Ответ 8

В последних версиях 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)')

Ответ 9

Ни один из вышеперечисленных ответов не работал "из коробки" для меня, однако, работает следующая функция, полученная путем копирования идей других ответов:

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

Ответ 10

Наткнулся на этот вопрос/ответ, пытаясь вычислить суммы строк матрицы.

Я хотел бы добавить, что функция Matlab SUM фактически поддерживает подведение для данного измерения, т.е. стандартную матрицу с двумя измерениями.

Итак, чтобы вычислить суммы столбцов do:

colsum = sum(M) % or sum(M, 1)

и для сумм строк просто do

rowsum = sum(M, 2)

Моя ставка заключается в том, что это быстрее, чем программирование цикла for и преобразование в ячейки:)

Все это можно найти в справке matlab для SUM.

Ответ 11

если вы знаете длину своих строк, вы можете сделать что-то вроде этого:

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) )