2010-02-21 3 views
89

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

ответ

66

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

Я бы проверить эффективность такого подхода для каждого конкретного случая с простым для цикла, что может быть быстрее, чем преобразование матрицы в ячейку массива. Используйте tic/tac wrap для тестирования. – yuk

+5

@yuk: Я думаю, вы имели в виду «тик/ток». ;) – gnovice

+2

Упс, конечно! Просто что-то тикает ... :) – yuk

-1

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

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

Таким образом, чтобы вычислить суммы столбцов сделать:

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

и для строчных сумм, просто сделать

rowsum = sum(M, 2) 

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

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

+7

Возможность применения SUM по заданному измерению была упомянута в первом предложении исходного ответа на этот вопрос. Затем в ответ был рассмотрен случай, когда возможность выбора измерения еще не встроена в функцию. Вы правы, однако, что использование встроенных параметров выбора размеров - когда они доступны - почти всегда быстрее, чем цикл for или преобразование в ячейки. – cjh

+0

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

18

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

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

Дается более общий ответ [здесь] (http://stackoverflow.com/a/15971182/376454). – Wok

9

Опираясь на Alex's 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))' 
22

Возможно, вам понадобится более неясная функция Matlab bsxfun. В документации Matlab bsxfun «применяет двоичную операцию« по одному элементу », указанную функцией fun fun в массивах A и B, с включенным расширением singleton».

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

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

A = [1 2 3; 
    4 5 6; 
    7 8 9] 
B = [0 1 2] 

Вы хотите функцию power_by_col, которая возвращает в вектор C все элементы А к власти соответствующий столбец B.

из приведенного выше примера, с представляет собой матрицу 3х3:

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 примерно в два раза быстрее, если функция, которая будет применяться (например, моя функция мощности выше) проста. Поэтому вам нужно будет выбрать, хотите ли вы простоты или скорости.

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

-1

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

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

Тем, кто видит этот ответ: Это не способ сделать это! Это не способ сделать что-либо в MATLAB! –

5

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

1

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

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

r2016b release notes С:

Неявного Расширение: Применение поэлементны операциями и функций в массивах с автоматическим расширением размеров длиной 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 

Например, можно вычислить среднее значение каждого столбца в матрице А, , а затем вычесть вектор средних значений из каждой колонки с А - среднего (А).

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

0

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

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