Применить функцию ко всем строкам - PullRequest
2 голосов
/ 17 августа 2010

У меня есть функция, 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

Ответы [ 4 ]

3 голосов
/ 18 августа 2010

При сотрудничестве с Amro и Jonas

variable_ranks = tiedrank(variable_data')';

Ранкер был заменен функцией Matlab в наборе инструментов Stat (извините за тех, у кого его нет),

[R, TIEADJ] = tiedrank (X) вычисляет ранги значений в векторе X. Если любые значения X связаны, tiedrank вычисляет их средний ранг.Возвращаемое значение TIEADJ является корректировкой для связей, требуемых непараметрическими тестами signrank и ranksum, и для вычисления ранговой корреляции Спирмена.

TIEDRANK будет вычисляться по столбцам в Matlab 7.9.0 (R2009b), однако это недокументировано.Таким образом, путем транспонирования входной матрицы строки превращаются в столбцы и ранжируют их.Затем вторая транспонирование используется для организации данных таким же образом, как и ввод.Там по сути очень стильный взломать: p

3 голосов
/ 17 августа 2010

Если вы поместите строки матрицы в массив ячеек, вы можете применить функцию к каждой ячейке.

Рассмотрим этот простой пример применения функции 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, вероятно, быстрее ..

2 голосов
/ 17 августа 2010

Один из способов - переписать 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);

EDIT

Вместо этого вы можете просто использовать TIEDRANK от TMW (спасибо, @Amro):

variable_rank = tiedrank(variable_data')';
1 голос
/ 31 января 2012

Я написал функцию, которая делает это, она находится на 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

Надеюсь, это кому-нибудь поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...