首页 文章

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

提问于
浏览
94

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

11 回答

  • 11

    许多内置操作(如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
    
  • 23

    你可能想要更模糊的Matlab函数bsxfun . 从Matlab文档中,bsxfun "applies the element-by-element binary operation specified by the function handle fun to arrays A and B, with singleton expansion enabled."

    @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的速度大约是其两倍 . 因此,您需要选择是否需要简单性或速度 .

  • 5

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

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

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

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

  • 3

    从r2016b开始,MATLAB将隐式地扩展单个维度,在许多情况下不需要 bsxfun ,从而增加了这个问题答案的演变性质 .

    来自r2016b release notes

    隐式扩展:将元素操作和函数应用于数组,并自动扩展长度为1的维数 . 隐式扩展是标量扩展的推广 . 通过标量扩展,标量扩展为与另一个阵列相同的大小,以便于元素操作 . 通过隐式扩展,只要数组具有兼容的大小,此处列出的元素操作符和函数就可以隐式地将其输入扩展为相同的大小 . 如果对于每个维度,输入的维度大小相同或者其中一个是1,则两个阵列具有兼容的大小 . 有关详细信息,请参阅基本操作和阵列与矩阵操作的兼容阵列大小 . 元素算术运算符 - , - , . *, . ^, . /, . \

    关系运算符 - <,<=,>,> =,==,〜=

    逻辑运算符 - &,|,xor

    逐位函数 - bitand,bitor,bitxor

    基本数学函数 - max,min,mod,rem,hypot,atan2,atan2d
    例如,您可以计算矩阵A中每列的平均值,然后用A - 均值(A)减去每列的平均值向量 . 以前,此功能可通过bsxfun函数获得 . 现在建议您使用直接调用支持隐式扩展的函数和运算符来替换bsxfun的大多数用法 . 与使用bsxfun相比,隐式扩展提供更快的速度,更好的内存使用和更高的代码可读性 .

  • 0

    使用最新版本的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)')
    
  • -1

    接受的答案似乎是首先转换为单元格然后使用 cellfun 来操作所有单元格 . 我不知道具体的应用,但总的来说我认为使用bsxfun来操作矩阵会更有效率 . 基本上 bsxfun 跨两个数组逐个元素地应用操作 . 因此,如果您想将 m 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 用于各种内置函数,并且可以声明自己的函数 . 该文档有许多内置函数的列表,但基本上你可以命名任何接受两个数组(向量或矩阵)作为参数的函数,并让它工作 .

  • 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
    
  • 1

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

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

    所以要计算列总和:

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

    对于行和,简单地做

    rowsum = sum(M, 2)
    

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

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

  • 67

    如果你知道你的行的长度,你可以做这样的事情:

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

相关问题