Как я могу применить функцию к каждой строке / столбцу матрицы в MATLAB?
Вы можете применить функцию к каждому элементу в векторе, сказав, например, v + 1
, или вы можете использовать функцию arrayfun
. Как я могу сделать это для каждой строки/столбца матрицы без использования цикла for?
11 ответов:
многие встроенные операции, такие как
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
вы можете захотеть более неясную функцию Matlab bsxfun. Из документации Matlab bsxfun " применяет поэлементную двоичную операцию, заданную функцией handle fun, к массивам A и B с включенным одноэлементным расширением."
@gnovice указано выше, что sum и другие основные функции уже работают на Первом не одноэлементном измерении (т. е. строки, если есть более одной строки, столбцы, если есть только одна строка, или более высокие измерения, если нижняя размеры все Размер==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 примерно в два раза быстрее, если применяемая функция (например, моя функция мощности, выше) проста. Так что вам нужно выбрать, хотите ли вы простота или скорость.
Я не могу прокомментировать, насколько это эффективно, но вот решение:
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, а затем вычесть вектор средних значений в каждом столбце с - среднее(а).
ранее эта функция была доступна через функцию bsxfun. Теперь рекомендуется заменить большинство применений bsxfun на прямые вызовы функций и операторов, поддерживающих неявное расширение. По сравнению с использованием bsxfun, неявный расширение предлагает более быструю скорость, лучшее использование памяти и улучшенная читаемость кода.
в последних версиях 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
для всех видов встроенных функций, и вы можете объявить свои собственные. В документации есть список многих встроенных функций, но в основном вы можете назвать любую функцию, которая принимает два массива (вектор или матрицу) в качестве аргументов и заставить ее работать.
ни один из вышеперечисленных ответов не сработал "из коробки" для меня, однако, работает следующая функция, полученная путем копирования идей других ответов:
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 фактически поддерживает суммирование для данного измерения, т. е. стандартную матрицу с двумя измерениями.
Итак, чтобы вычислить суммы столбцов, сделайте:
colsum = sum(M) % or sum(M, 1)
и для сумм строк, просто сделать
rowsum = sum(M, 2)
моя ставка заключается в том, что это быстрее, чем программирование цикла for и преобразование в ячейки :)
все это можно найти в справке matlab для SUM.