我有一个函数ranker
,它接受一个向量并按升序为其分配数字排名。例如,
ranker([5 1 3 600]) = [3 1 2 4]
或
ranker([42 300 42 42 1 42] = [3.5 6 3.5 3.5 1 3.5]
。
我正在使用矩阵variable_data
,我想将排名函数应用于variable data
中所有行的每一行。这是我目前的解决方案,但我觉得有一种方法可以对其进行矢量化并使其同样快速:p
variable_ranks = nan(size(variable_data));
for i=1:1:numel(nmac_ids)
variable_ranks(i,:) = ranker(abs(variable_data(i,:)));
end
答案 0 :(得分:3)
如果将矩阵行放入单元格数组中,则可以将函数应用于每个单元格。
考虑将SORT函数应用于每一行的简单示例
a = rand(10,3);
b = cell2mat( cellfun(@sort, num2cell(a,2), 'UniformOutput',false) );
%# same as: b = sort(a,2);
你甚至可以这样做:
b = cell2mat( arrayfun(@(i) sort(a(i,:)), 1:size(a,1), 'UniformOutput',false)' );
同样,使用for循环的版本可能更快..
答案 1 :(得分:3)
与Amro和Jonas合作
variable_ranks = tiedrank(variable_data')';
Ranker已经被Stat工具箱中的Matlab函数所取代(对那些没有它的人来说很抱歉),
[R,TIEADJ] = tiedrank(X)计算 向量X中的值的等级。 如果任何X值被绑定,则绑定 计算他们的平均排名。该 返回值TIEADJ是一个调整 对于非参数所需的联系 测试signrank和rankum,并为 斯皮尔曼等级的计算 的相关性。
TIEDRANK
将沿着Matlab 7.9.0(R2009b)中的列进行计算,但它没有记录。因此,通过转置输入矩阵,行将变为列并对它们进行排名。然后使用第二个转置以与输入相同的方式组织数据。实质上是一个非常优雅的黑客:p
答案 2 :(得分:2)
一种方法是重写ranker
以获取数组输入
sizeData = size(variable_data);
[sortedData,almostRanks] = sort(abs(variable_data),2);
[rowIdx,colIdx] = ndgrid(1:sizeData(1),1:sizeData(2));
linIdx = sub2ind(sizeData,rowIdx,almostRanks);
variable_ranks = variable_data;
variable_ranks(linIdx) = colIdx;
%# break ties by finding subsequent equal entries in sorted data
[rr,cc] = find(diff(sortedData,1,2) == 0);
ii = sub2ind(sizeData,rr,cc);
ii2 = sub2ind(sizeData,rr,cc+1);
ii = sub2ind(sizeData,rr,almostRanks(ii));
ii2 = sub2ind(sizeData,rr,almostRanks(ii2));
variable_ranks(ii) = variable_ranks(ii2);
修改强>
相反,你可以使用TMW的TIEDRANK(谢谢,@ Amro):
variable_rank = tiedrank(variable_data')';
答案 3 :(得分:1)
我编写了一个执行此操作的函数,它位于FileExchange tiedrank_(X,dim)上。它看起来像这样......
%[Step 0a]: force dim to be 1, and compress everything else into a single
%dimension. We will reverse this process at the end.
if dim > 1
otherDims = 1:length(size(X));
otherDims(dim) = [];
perm = [dim otherDims];
X = permute(X,perm);
end
originalSiz = size(X);
X = reshape(X,originalSiz(1),[]);
siz = size(X);
%[Step 1]: sort and get sorting indicies
[X,Ind] = sort(X,1);
%[Step 2]: create matrix [D], which has +1 at the start of consecutive runs
% and -1 at the end, with zeros elsewhere.
D = zeros(siz,'int8');
D(2:end-1,:) = diff(X(1:end-1,:) == X(2:end,:));
D(1,:) = X(1,:) == X(2,:);
D(end,:) = -( X(end,:) == X(end-1,:) );
clear X
%[Step 3]: calculate the averaged rank for each consecutive run
[a,~] = find(D);
a = reshape(a,2,[]);
h = sum(a,1)/2;
%[Step 4]: insert the troublseome ranks in the relevant places
L = zeros(siz);
L(D==1) = h;
L(D==-1) = -h;
L = cumsum(L);
L(D==-1) = h; %cumsum set these ranks to zero, but we wanted them to be h
clear D h
%[Step 5]: insert the simple ranks (i.e. the ones that didn't clash)
[L(~L),~] = find(~L);
%[Step 6]: assign the ranks to the relevant position in the matrix
Ind = bsxfun(@plus,Ind,(0:siz(2)-1)*siz(1)); %equivalent to using sub2ind + repmat
r(Ind) = L;
%[Step 0b]: As promissed, we reinstate the correct dimensional shape and order
r = reshape(r,originalSiz);
if dim > 1
r = ipermute(r,perm);
end
我希望能帮助别人。