Turn on suggestions

Auto-suggest helps you quickly narrow down your search results by suggesting possible matches as you type.

Showing results for

Options

- RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Mute
- Printer Friendly Page

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

Posted 09-12-2019 05:02 PM
(1152 views)

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

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

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

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

`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

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

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

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

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

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

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

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

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

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

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

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

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.

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

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.

- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content

Registration is open! SAS is returning to Vegas for an AI and analytics experience like no other! Whether you're an executive, manager, end user or SAS partner, SAS Innovate is designed for everyone on your team. Register for just $495 by 12/31/2023.

**If you are interested in speaking, there is still time to submit a session idea. More details are posted on the website. **

Multiple Linear Regression in SAS

Learn how to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.

Find more tutorials on the SAS Users YouTube channel.