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

Fur*_*lon 103 matlab function matrix vectorization

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

gno*_*ice 69

许多内置操作类似于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
Run Code Online (Sandbox Code Playgroud)

以下是使用更复杂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
Run Code Online (Sandbox Code Playgroud)

  • 我会针对简单的for循环测试任何特定情况的这种方法的性能,这可能比将矩阵转换为单元阵列更快.使用tic/tac包装进行测试. (17认同)
  • @yuk:我觉得你的意思是"tic/toc".;) (5认同)
  • @gnovice,也许yuk做了一些魔法并指定了tak = toc.在`true = false`是有效语句的语言中,我确信有一种方法可以做到(: (4认同)
  • 哎呀,当然!只是滴答作响...... :) (3认同)
  • @Argyll:确定哪种方法更有效将取决于您想要应用哪种函数、矩阵的大小等。简而言之,这可能取决于问题。事实上,有时一个好的旧 for 循环可能是最快的选择。 (2认同)
  • @gnovice,我建议编辑`sum(M,1)`.初学者可能会认为`sum`可以这种方式用于任意大小的矩阵,然后当矩阵有一天是'1-by-n`时会被难倒. (2认同)

Dan*_*den 24

你可能想要更模糊的Matlab函数bsxfun.从Matlab文档中,bsxfun"将函数句柄fun指定的逐元素二元运算应用于数组A和B,并启用单例扩展."

@gnovice在上面说过,sum和其他基本函数已经在第一个非单一维度上运行(即,如果有多个行,则为行;如果只有一行,则为列;如果较低的维度都具有大小,则为更高的维度== 1 ).但是,bsxfun适用于任何功能,包括(尤其)用户定义的功能.

例如,假设你有一个矩阵A和一个行向量BEg,让我们说:

A = [1 2 3;
     4 5 6;
     7 8 9]
B = [0 1 2]
Run Code Online (Sandbox Code Playgroud)

你想要一个函数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]
Run Code Online (Sandbox Code Playgroud)

C = [1 2 9;
     1 5 36;
     1 8 81]
Run Code Online (Sandbox Code Playgroud)

你可以使用repmat以蛮力的方式做到这一点:

C = A.^repmat(B, size(A, 1), 1)
Run Code Online (Sandbox Code Playgroud)

或者您可以使用bsxfun以优雅的方式执行此操作,bsxfun在内部负责repmat步骤:

C = bsxfun(@(x,y) x.^y, A, B)
Run Code Online (Sandbox Code Playgroud)

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


小智 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)
Run Code Online (Sandbox Code Playgroud)


Wok*_*Wok 11

基于Alex的答案,这是一个更通用的功能:

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));
Run Code Online (Sandbox Code Playgroud)

这是两个函数之间的比较:

>> % 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))'
Run Code Online (Sandbox Code Playgroud)


kam*_*gin 6

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


cra*_*gim 5

除了这个问题答案的不断演变之外,从 r2016b 开始,MATLAB 将隐式扩展单例维度,从而bsxfun在许多情况下不再需要。

\n\n

来自r2016b 发行说明

\n\n
\n

隐式扩展:将按元素运算和函数应用于数组,并自动扩展长度为 1 的维度

\n\n

隐式展开是标量展开的推广。通过标量扩展,标量扩展为与另一个数组相同的大小,以方便按元素操作。通过隐式扩展,只要数组具有兼容的大小,此处列出的按元素运算符和函数就可以隐式地将其输入扩展为相同的大小。如果对于每个维度,输入的维度大小相同或其中之一为 1,则两个数组具有兼容的大小。有关详细信息,请参阅基本运算的兼容数组大小和数组与矩阵运算。

\n\n
Element-wise arithmetic operators \xe2\x80\x94 +, -, .*, .^, ./, .\\\n\nRelational operators \xe2\x80\x94 <, <=, >, >=, ==, ~=\n\nLogical operators \xe2\x80\x94 &, |, xor\n\nBit-wise functions \xe2\x80\x94 bitand, bitor, bitxor\n\nElementary math functions \xe2\x80\x94 max, min, mod, rem, hypot, atan2, atan2d\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

以前,此功能可通过 bsxfun 函数使用。\n 现在建议您将 bsxfun 的大部分使用替换为直接\n 调用支持隐式扩展的函数和运算符。\n 与使用 bsxfun 相比,隐式扩展速度更快速度、\n 更好的内存使用率以及提高的代码可读性。

\n
\n