Вы можете применить функцию к каждому элементу в векторе, например, сказав 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 «применяет бинарную операцию поэлементно, заданную дескриптором функции fun, к массивам 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]
Вы можете сделать это методом грубой силы, используя repmat:
C = A.^repmat(B, size(A, 1), 1)
Или вы можете сделать это классным способом, используя bsxfun, который внутренне заботится о шаге repmat:
C = bsxfun(@(x,y) x.^y, A, B)
Таким образом, bsxfun сэкономит вам несколько шагов (вам не нужно явно рассчитывать размеры A). Однако в некоторых моих неофициальных тестах оказалось, что repmat примерно в два раза быстрее, если функция, которую нужно применить (например, моя функция мощности, выше), проста. Поэтому вам нужно выбрать, хотите ли вы простоты или скорости.
Я не могу прокомментировать, насколько это эффективно, но вот решение:
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 - mean (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 вы можете использовать структуру данных Table в своих интересах. Есть даже операция 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)
Держу пари, что это быстрее, чем программирование цикла for и преобразование в ячейки :)
Все это можно найти в справке по 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) )