【问题标题】:What's the best way to iterate through columns of a matrix?遍历矩阵列的最佳方法是什么?
【发布时间】:2008-10-19 12:10:41
【问题描述】:

我想使用 MATLAB 将函数应用于矩阵中的所有列。例如,我希望能够在矩阵的每一列上调用 smooth,而不是让 smooth 将矩阵视为向量(如果您调用 smooth(matrix),这是默认行为)。

我确定一定有更惯用的方法来做到这一点,但我找不到,所以我定义了一个map_column 函数:

function result = map_column(m, func)
    result = m;
    for col = 1:size(m,2)
        result(:,col) = func(m(:,col));
    end
end

我可以打电话给:

smoothed = map_column(input, @(c) (smooth(c, 9)));

这段代码有什么问题吗?我该如何改进它?

【问题讨论】:

    标签: matlab matrix enumeration


    【解决方案1】:

    MATLAB“for”语句实际上循环遍历所提供的任何列 - 通常,这只会产生一系列标量,因为传递给 for 的向量(如上面的示例)是一个行向量。这意味着你可以像这样重写上面的代码:

    function result = map_column(m, func)
        result = [];
        for m_col = m
          result = horzcat(result, func(m_col));
        end
    

    如果 func 不返回列向量,那么您可以添加类似

    f = func(m_col);
    result = horzcat(result, f(:));
    

    强制它进入一个列。

    【讨论】:

    • OP 的代码预先分配了result 矩阵,此代码没有。相反,它每次迭代都会增长矩阵,这会产生很大的损失。应该始终尝试在 MATLAB 中使用 pre-allocate 数组。
    【解决方案2】:

    你的解决方案很好。

    请注意,horizcat 会对大型矩阵造成很大的性能损失。它使代码为 O(N^2) 而不是 O(N)。对于 100x10,000 矩阵,您的实现在我的机器上需要 2.6 秒,而 horizcat 需要 64.5 秒。对于 100x5000 矩阵,horizcat 实现需要 15.7s。

    如果您愿意,您可以稍微概括一下您的函数,使其能够迭代最终维度甚至任意维度(不仅仅是列)。

    【讨论】:

      【解决方案3】:

      也许您总是可以使用 ' 运算符转换矩阵,然后将结果转换回来。

      smoothed = smooth(input', 9)';
      

      这至少适用于 fft 函数。

      【讨论】:

      • 这不适用于平滑功能。如果您通过平滑矩阵,它会将其视为一个大向量。不过,这种方法对于其他一些功能会很方便。
      • ' 是复共轭转置。如果目标是交换矩阵的两个维度,请使用.'
      【解决方案4】:

      在矩阵的列之间产生隐式循环的一种方法是使用 cellfun。也就是说,您必须首先将矩阵转换为单元格数组,每个单元格将容纳一​​列。然后打电话给cellfun。例如:

      A = randn(10,5);
      

      看到这里我计算了每列的标准差。

      cellfun(@std,mat2cell(A,size(A,1),ones(1,size(A,2))))
      
      ans =
            0.78681       1.1473      0.89789      0.66635       1.3482
      

      当然,MATLAB 中的许多函数已经设置为在用户指定的数组的行或列上工作。当然,std 也是如此,但这是测试 cellfun 是否成功运行的便捷方法。

      std(A,[],1)
      
      ans =
            0.78681       1.1473      0.89789      0.66635       1.3482
      

      【讨论】:

      • 这个解决方案没问题,只是需要一些额外的内存。为了匹配 OP 的使用,将'UniformOutput',false 添加到cellfun 调用中,然后使用horzcat(result{:}) 或等效的cat(2,result{:}) 将生成的所有(希望的)列向量连接回一个矩阵。此解决方案的效率与 OP 中的代码大致相同,因为 cellfun 是使用循环以非常相似的方式实现的。
      【解决方案5】:

      如果您正在处理大型矩阵,请不要忘记预先分配结果矩阵。否则,每次添加新行/列时,您的 CPU 将花费大量周期重复重新分配矩阵。

      【讨论】:

        【解决方案6】:

        如果这是您的函数的常见用例,如果输入不是向量,最好让函数自动遍历列。

        这并不能完全解决您的问题,但会简化函数的使用。在这种情况下,输出也应该是一个矩阵。

        您还可以使用m(:,:) = m(:) 将矩阵转换为一长列。但是,这是否有意义取决于您的功能。

        【讨论】:

          猜你喜欢
          • 2012-07-16
          • 2011-04-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-28
          • 2019-11-20
          • 1970-01-01
          • 2015-10-20
          相关资源
          最近更新 更多