Obsidian | Level 7

## Rank Rows of a Matrix Without Looping

Is there a technique that would allow ranking each row of a matrix without looping?

So the returned matrix would have within-row ranks.

For example if A held all non-missing numeric data, then imaginary function rowRank(A) would return values 1:ncol(A) in each row.

10 REPLIES 10
Super User

## Re: Rank Rows of a Matrix Without Looping

Show an example with data please. Sounds like you want to rank each row of data.
Obsidian | Level 7

## Re: Rank Rows of a Matrix Without Looping

``a = {1 3 10, 6 9 5};  print a ,,   (rank(a))[l="Ranks from rank(a)"] ,,   ({1 2 3, 2 3 1})[l="Desired Ranks (row-wise ranks)"];``

A

1 3 10
6 9 5

Ranks from rank(a)

1 2 6
4 5 3

Desired Ranks (row-wise ranks)

1 2 3
2 3 1

Barite | Level 11

## Re: Rank Rows of a Matrix Without Looping

I think this can be done with a two pass solution.  The initial rank matrix needs to be adjusted so that each row has values that are larger than the row before, then the second ranking is operating within row.  For example:

``````proc iml;
a = {1 3 10, 6 9 5};
print a;

b = row(a) - 1;
r = rank( rank(a) + nrow(a) # ncol(a) # b ) - ncol(a) # b;
print r;
quit;``````
Rhodochrosite | Level 12

## Re: Rank Rows of a Matrix Without Looping

The ranks given to second row seems to be wrong. I think it has to be 3 1 2. I have less expertise in IML. Do you accept a Data Step solution?

The steps include the sorting of each row by using SORTN() function and at the same time switching the index of the array. Then re-ordered index will be the rank. SMALLEST() takes care of the sorting in the background and returns

the i-th smallest value. Using WHICHN() with the i-th smallest value gives the desired Rank.

Note, no attempt is made to check for ties.

``````
%let vn = 3;
data rank;
set A;
array x x1-x&vn;
array R R1 - R&vn;
do i = 1 to dim(x);
R[i] = whichN(smallest(i, of x[*]), of x[*]);
put R[i] =;
end;
keep R:;
run;``````
Obsidian | Level 7

## Re: Rank Rows of a Matrix Without Looping

Great ideas -- thank you. The "r2" array in DO loop below is what I have been using.

``````proc iml;

a = {2 4 6, 15 11 13, 29 28 27};

r1 = rank(a);

r2 = j(nrow(a), ncol(a), .);

do i = 1 to nrow(a);
r2[i,] = rank(a[i,]);
end;

print a ,, r1[l="Rank(a) - whole matrix - don't want"] ,, r2[l="Desired 'Row Ranks' from looping rank(row-by-row)"];

quit;``````
SAS Super FREQ

## Re: Rank Rows of a Matrix Without Looping

Ian is a master at these manipulation tricks!

I think you can make a small improvement to his idea to make it more efficient. This computation requires only a translation, a rank, and another translation.

``````proc iml;
a = {2 4 6,
15 11 13,
29 28 27,
2 4 6,
4 1 6,
2 6 4,
6 4 2 };

maxDiff = range(a) + 1;  /* largest difference between elements */
b = a + maxDiff*row(a);  /* uniquify each row */
r = rank(b) - ncol(a)* T(0:(nrow(a)-1));
print r;
``````
Barite | Level 11

## Re: Rank Rows of a Matrix Without Looping

I like your modification Rick, surely the way to go if the OP is looking for an IML solution.

Ammonite | Level 13

## Re: Rank Rows of a Matrix Without Looping

If your matrix is in the form of a SAS data set, it is a simple 3 step process and 7 statements (including 3 RUN statements):

1. Proc TRANSPOSE.

2. Proc RANK.

3. Proc TRANSPOSE.

Kind regards

Paul D.

Ammonite | Level 13

## Re: Rank Rows of a Matrix Without Looping

Had no SAS access on the first response, but now that I do and can test, consider:

``````data have ;
input v1-v3 ;
cards ;
6 9  5
1 3 10
0 0  0
0 0  1
0 1  1
;
run ;

proc transpose data = have out = t (drop = _:) ;
run ;
proc rank data = t out = r ;
var col: ;
run ;
proc transpose data = r out = want (drop=_:) prefix=v ;
run ;
``````

Result:

``` v1     v2     v3
-----------------
2.0    3.0    1.0
1.0    2.0    3.0
2.0    2.0    2.0
1.5    1.5    3.0
1.0    2.5    2.5
```

Plus, you have all the bells and whistles of proc RANK to handle the ties differently, should you wish.

Kind regards

Paul D.

SAS Super FREQ

## Re: Rank Rows of a Matrix Without Looping

If the OP wants to control how to rank tied values, the RANKTIE function in SAS/IML supports exactly the same methods as PROC RANK.

From The DO Loop
Discussion stats
• 10 replies
• 1153 views
• 14 likes
• 6 in conversation