如何在MATLAB中将函数应用于矩阵的每一行/列?

时间:2010-02-21 19:58:27

标签: matlab function matrix vectorization

您可以通过例如v + 1来说明向量中的每个项目应用函数,或者您可以使用函数arrayfun。如何在不使用for循环的情况下对矩阵的每一行/列进行此操作?

11 个答案:

答案 0 :(得分:68)

许多内置操作(如sumprod)已经能够跨行或列操作,因此您可以重构您正在应用的功能以利用此功能。

如果这不是一个可行的选项,一种方法是使用mat2cellnum2cell将行或列收集到单元格中,然后使用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

答案 1 :(得分:24)

您可能想要更加模糊的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以优雅的方式执行此操作,bsxfun在内部处理repmat步骤:

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

因此bsxfun会为您节省一些步骤(您不需要明确计算A的尺寸)。然而,在我的一些非正式测试中,事实证明,如果要应用的函数(如上面的幂函数)很简单,repmat的速度大约是其两倍。因此,您需要选择是否需要简单性或速度。

答案 2 :(得分:19)

我无法评论这是多么有效,但这是一个解决方案:

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)

答案 3 :(得分:11)

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

答案 4 :(得分:6)

为了完整性/兴趣,我想补充一点,matlab确实有一个函数,允许你对每行数据而不是每个元素进行操作。它被称为rowfunhttp://www.mathworks.se/help/matlab/ref/rowfun.html),但唯一的“问题”是它在表格http://www.mathworks.se/help/matlab/ref/table.html)上运行而不是矩阵

答案 5 :(得分: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
     

例如,您可以计算矩阵A中每列的平均值,   然后用A - 从每列中减去平均值的向量 -   意味着(A)。

     

以前,此功能可通过bsxfun函数获得。   现在建议您使用direct直接替换bsxfun的大多数用法   调用支持隐式扩展的函数和运算符。   与使用bsxfun相比,隐式扩展提供更快的速度,   更好的内存使用率和更高的代码可读性。

答案 6 :(得分:1)

接受的答案似乎是首先转换为单元格然后使用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)条目将是vec1的第i个元素乘以vec2的第j个元素。

您可以将bsxfun用于各种内置函数,并且可以声明自己的函数。该文档有许多内置函数的列表,但基本上你可以命名任何接受两个数组(向量或矩阵)作为参数的函数,并让它工作。

答案 7 :(得分: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)')

答案 8 :(得分:1)

上述答案都没有奏效,开箱即用#34;但是,对我来说,通过复制其他答案的想法获得的以下功能有效:

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

答案 9 :(得分:-1)

在寻求如何计算矩阵的行和时,偶然发现了这个问题/答案。

我想补充一点,Matlab的SUM函数实际上支持给定维度的求和,即具有二维的标准矩阵。

所以要计算列总和:

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

并且对于行总和,只需执行

rowsum = sum(M, 2)

我敢打赌,这比编程for循环和转换为单元格更快:)

所有这些都可以在SUM的matlab帮助中找到。

答案 10 :(得分:-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) )