我想用MATLAB将函数应用于矩阵中的所有列。例如,我希望能够在矩阵的每一列上调用平滑,而不是将矩阵平滑地视为向量(如果您调用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)));
这段代码有什么问题吗?我怎么能改进它?
答案 0 :(得分:9)
MATLAB“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(:));
强制它进入一列。
答案 1 :(得分:3)
你的解决方案很好。
请注意,对于大型矩阵,horizcat会严重影响性能。它使代码为O(N ^ 2)而不是O(N)。对于100x10,000矩阵,我的机器上的实现需要2.6秒,而horizcat需要64.5秒。对于100x5000矩阵,horizcat实现需要15.7秒。
如果您愿意,可以稍微概括一下您的函数,使其能够迭代最终维度甚至任意维度(不仅仅是列)。
答案 2 :(得分:2)
也许您总是可以使用'运算符转换矩阵,然后将结果转换回来。
smoothed = smooth(input', 9)';
至少适用于fft功能。
答案 3 :(得分:2)
在矩阵的列中引入隐式循环的方法是使用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
答案 4 :(得分:1)
如果处理大型矩阵,请不要忘记预先分配结果矩阵。否则,每次添加新行/列时,CPU将花费大量周期重复分配矩阵。
答案 5 :(得分:0)
如果这是函数的常见用例,那么如果输入不是向量,则使函数自动遍历列可能是个好主意。
这并不能完全解决您的问题,但会简化功能的使用。在这种情况下,输出也应该是一个矩阵。
您还可以使用m(:,:) = m(:)
将矩阵转换为一个长列。但是,这取决于你的功能是否有意义。