Question

J'ai une fonction, ranker, qui prend un vecteur et les Ayants rangs numérique pour en ordre croissant. Par exemple,
 ranker([5 1 3 600]) = [3 1 2 4] ou
ranker([42 300 42 42 1 42] = [3.5 6 3.5 3.5 1 3.5].

J'utilise une matrice, variable_data et je veux appliquer la fonction Ranker à chaque ligne pour toutes les lignes variable data. Ceci est ma solution actuelle, mais je pense qu'il ya une façon et à vectoriser ont comme tout aussi rapide: p

variable_ranks = nan(size(variable_data));
for i=1:1:numel(nmac_ids)
    variable_ranks(i,:) = ranker(abs(variable_data(i,:)));
end
Était-ce utile?

La solution 2

Avec la collaboration de Amro et Jonas

variable_ranks = tiedrank(variable_data')';

Ranker a été remplacée par la fonction Matlab dans la boîte à outils Stat (désolé pour ceux qui ne l'ont pas),

  

[R, TIEADJ] = tiedrank (X) calcule le   rangs des valeurs dans le vecteur X.   Si les valeurs de X sont à égalité, tiedrank   calcule leur rang moyen. le   La valeur de retour est un ajustement TIEADJ   pour les liens requis par le nonparamétrique   des tests signrank et ranksum, et   le calcul du rang de Spearman   corrélation.

TIEDRANK calculera le long des colonnes dans Matlab 7.9.0 (version 2009b), mais il est en situation irrégulière. Ainsi, en transposant la matrice d'entrée, les lignes se transforment en colonnes et les classera. La deuxième transposition est ensuite utilisé pour organiser les données de la même manière que l'entrée. Il en essence est un hack très classe: p

Autres conseils

Si vous placez les lignes de la matrice dans une matrice de cellules, vous pouvez alors appliquer une fonction à chaque cellule.

Considérez cet exemple simple d'appliquer la fonction SORT à chaque ligne

a = rand(10,3);
b = cell2mat( cellfun(@sort, num2cell(a,2), 'UniformOutput',false) );
%# same as: b = sort(a,2);

Vous pouvez même faire ceci:

b = cell2mat( arrayfun(@(i) sort(a(i,:)), 1:size(a,1), 'UniformOutput',false)' );

Encore une fois, vous version avec la boucle est probablement plus rapide ..

Une façon serait de réécrire ranker pour prendre un tableau en entrée

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);

EDIT

Au lieu de cela, vous pouvez simplement utiliser TIEDRANK de TMW (grâce, @Amro):

variable_rank = tiedrank(variable_data')';

J'ai écrit une fonction qui fait cela, il est sur le FileExchange tiedrank_ (X, dim) . Et ça ressemble à ça ...

%[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

J'espère que quelqu'un aide.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top