在MATLAB中稳定准确的

MATLAB的内置函数accumarray接受函数fun作为第四个参数。

 A = accumarray(subs,val,sz,fun); 

这对val中每个具有相同下标的元素的子集适用fun 。 但是文件指出:

如果subs中的下标不是按照它们的线性索引进行sorting的, fun不应该依赖于其input数据中值的顺序。

我们怎样才能实现稳定accumarray版本,它没有这个限制,但是会保证子集采用与val给出的相同的顺序?

例:

 subs = [1:10,1:10]; val = 1:20; accumarray(subs(:), val(:), [], @(x)x(end)).' 

如果accumarray是稳定的话,预期的输出是11:20 。 其实输出是:

 ans = 11 12 13 14 5 6 7 18 19 20 

我们的实施应该产生:

 accumarrayStable(subs(:), val(:), [], @(x)x(end)).'` ans = 11 12 13 14 15 16 17 18 19 20 

我们可以使用sortrows作为预处理步骤,首先对索引和相应的值进行sorting,如其文档所述:

SORTROWS使用一个稳定版本的quicksort。

由于子索引中的下标应该按照它们的线性索引进行sorting,所以我们需要按照逆向词典顺序对它们进行sorting。 这可以通过在使用sortrows之前和之后翻转列顺序来sortrows

这给了我们一个稳定版本的accumarray的以下代码:

 function A = accumarrayStable(subs, val, varargin) [subs(:,end:-1:1), I] = sortrows(subs(:,end:-1:1)); A = accumarray(subs, val(I), varargin{:}); 

替代scheme:

正如路易斯·门多Luis sortrows所build议的那样,也可以用下标来生成线性索引,而不是使用sort

 function A = accumarrayStable(subs, val, varargin) if numel(varargin)>0 && ~isempty(varargin{1}) sz = varargin{1}; else sz = max(subs,[],1); end [~, I] = sort(subs*cumprod([1,sz(1:end-1)]).'); A = accumarray(subs(I,:), val(I), sz, varargin{:}); 

请注意,我们应该使用1+(subs-1)*cumprod([1,sz(1:end-1)]).' 用于转换为线性索引。 我们省略了+1-1sort的结果仍然是一样的; 这节省了我们几个周期。

上述哪一种解决scheme更快取决于你的机器和MATLAB版本。 你可以testing例如通过:

 A = randi(10, 1e4, 5); timeit(@()accumarrayStable(A(:,1:end-1), A(:,end), [], @(x)x(1)) 
Interesting Posts