2 votes

Appliquer la fonction à toutes les lignes

J'ai une fonction, ranker qui prend un vecteur et lui attribue des rangs numériques dans l'ordre croissant. Par exemple,
ranker([5 1 3 600]) = [3 1 2 4] o
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 dans variable data . C'est ma solution actuelle, mais je pense qu'il y a un moyen de la vectoriser et de la rendre 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

3voto

Amro Points 72743

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

Considérons cet exemple simple d'application de 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 ça :

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

Encore une fois, votre version avec la boucle for est probablement plus rapide

3voto

Elpezmuerto Points 1528

Avec la collaboration d'Amro et de Jonas

variable_ranks = tiedrank(variable_data')';

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

[R,TIEADJ] = tiedrank(X) calcule la rangs des valeurs du vecteur X. Si des valeurs X sont à égalité, tiedrank calcule leur rang moyen. La valeur de retour TIEADJ de valeur de retour TIEADJ est un ajustement pour les égalités requis par les tests non paramétriques non paramétriques signrank et ranksum, et pour le le calcul du rang de Spearman. de Spearman.

TIEDRANK calcule le long des colonnes dans Matlab 7.9.0 (R2009b), mais il n'est pas documenté. Ainsi, en transposant la matrice d'entrée, les lignes se transforment en colonnes et les classeront. La seconde transposition est ensuite utilisée pour organiser les données de la même manière que l'entrée. Voilà en substance un hack très classe :p

2voto

Jonas Points 54073

Une façon de procéder serait de réécrire ranker pour prendre l'entrée du tableau

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

EDITAR

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

variable_rank = tiedrank(variable_data')';

1voto

Daniel Points 11

J'ai écrit une fonction qui fait ça, elle 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 cela aidera quelqu'un.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X