Answers:
许多内置操作,例如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
这是使用更复杂的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
true = false
一种有效的语言来说,我敢肯定有一种方法可以做到((
sum(M, 1)
。初学者可能认为sum
可以将这种方法用于任意大小的矩阵,然后在一天的矩阵结束时陷入困境1-by-n
。
您可能想要更晦涩的Matlab函数bsxfun。从Matlab文档中,bsxfun“将功能句柄fun指定的逐元素二进制操作应用于启用了单例扩展的数组A和B。”
@gnovice上面已经说过sum和其他基本功能已经在第一个非单维度上起作用(即,如果有多个行,则为行;如果只有一行,则为列;如果较低的维度都具有size == 1,则为较高的维度) )。但是,bsxfun适用于任何功能,包括(尤其是)用户定义的功能。
例如,假设您有一个矩阵A和一个行向量BEg,例如:
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以经典方式进行此操作,该方法在内部负责repmat步骤:
C = bsxfun(@(x,y) x.^y, A, B)
因此,bsxfun为您节省了一些步骤(您无需显式计算A的尺寸)。但是,在我的一些非正式测试中,事实证明,如果要应用的函数(例如上面的幂函数)很简单,则repmat的速度大约是它的两倍。因此,您需要选择要简单还是要加快速度。
基于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));
这是两个功能之间的比较:
>> % 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))'
为了完整性/兴趣,我想补充一下,matlab确实具有允许您按行而不是按元素对数据进行操作的功能。它被称为rowfun
(http://www.mathworks.se/help/matlab/ref/rowfun.html),但是唯一的“问题”是它对表进行操作(http://www.mathworks.se/help/ matlab / ref / table.html)而不是矩阵。
从r2016b开始,此问题的答案不断演变,从本质上讲,MATLAB将隐式扩展单例尺寸,从而bsxfun
在许多情况下无需这样做。
隐式扩展:将元素的操作和函数应用于数组,并自动扩展长度为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-mean(A)从每一列中减去平均值向量。
以前,可以通过bsxfun函数使用此功能。现在建议用对支持隐式扩展的函数和运算符的直接调用替换bsxfun的大多数用法。与使用bsxfun相比,隐式扩展提供了更快的速度,更好的内存使用率以及更高的代码可读性。
以上所有答案对我来说都不是“开箱即用”的,但是,通过复制其他答案的思想而获得的以下功能有效:
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
公认的答案似乎是先转换为单元,然后用于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)项将是的第i个元素vec1
乘以的第j个元素vec2
。
您可以使用bsxfun
各种内置函数,也可以声明自己的函数。该文档列出了许多内置函数,但是基本上您可以命名任何接受两个数组(向量或矩阵)作为参数的函数,并使它起作用。
在寻求如何计算矩阵的行总和时偶然发现了这个问题/答案。
我只想补充一下,Matlab的SUM函数实际上支持对给定维度(即具有两个维度的标准矩阵)求和。
因此,要计算列总和:
colsum = sum(M) % or sum(M, 1)
对于行总和,只需执行
rowsum = sum(M, 2)
我敢打赌,这比编程for循环和转换为单元格都快:)
所有这些都可以在SUM的matlab帮助中找到。
如果您知道行的长度,则可以执行以下操作:
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) )