BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
ivs
Calcite | Level 5 ivs
Calcite | Level 5

hi i have an IML question. i am trying to determine coordinates for a maximum value within a matrix. for example:

data one;

input name $ a b c;

datalines;

a 10 20 30

b 10 100 30

c 30 20 10

;

run;

proc iml;

use one;

read all into X [rowname=name colname=VarName];

n=max(X);

print n;

quit;

output just lists "N 100." how to output that n is variable "b" in row name "b"? Many thanks in advance for your help!

ivs                   

1 ACCEPTED SOLUTION

Accepted Solutions
Rick_SAS
SAS Super FREQ

Your logic looks OK, but the code is inefficient. There is no need to loop over all rows and columns of your matrix. You can use arithmetic to find the row and column directly, which is what I show in the blog post that I linked to earlier.

start ind2sub( p, ind );
   idx = colvec(ind);
   n = nrow(idx);
   col = 1 + mod(idx-1, p);
   row = 1 + (idx-col) / p;
   return ( row || col );
finish;

a=X[<:>]; *finding position of max value within the entire matrix;
rowcol = ind2sub(ncol(X), a); *call function get (row,col) directly without looping;
RowM=rowcol[1];
ColM=rowcol[2];

RowN=name[RowM]; *lookup row name for max value;
ColN=VarName[ColM]; *lookup col name for max value;
print a RowN ColN ;

View solution in original post

9 REPLIES 9
Rick_SAS
SAS Super FREQ

Use the <:> opertor to find the index of the largest element. See SAS/IML(R) 9.3 User's Guide

Because the elements of a matrix are enumerated in row-major order, you can figure out the row and column by knowing the dimensions of the matrix and the index of the maximum.  You can do this by hand or you can use the NDX2SUB function in SAS/IML 12.1.  If you don't have SAS/IML 12.1, you can easily write down an equivalent function, as shown in this article: Converting matrix subscripts to indices - The DO Loop

/* 12.1 solution */

maxIdx = X[<:>];

rowcol = ndx2sub(dimension(X), maxIdx);

print maxIdx rowcol;

maxIdx     rowcol

5                2  2

ivs
Calcite | Level 5 ivs
Calcite | Level 5

Thanks Rick. I do not have SAS/IML 12.1 - going to try the Do Loop approach.

ivs

ivs
Calcite | Level 5 ivs
Calcite | Level 5

hi Rick, there is no DO LOOP solution to my question in the link you provided - just discussion on converting subscripts to indices and the other way around via declaring a module. in fact there is no singe DO LOOP in the entire article. I am looking for something simple without complex module declarations.

thanks for pointing out the X[<:>] option. now that i know the element index and can calc ncol and nrow what's a simple way to add corresponding row number and column name to the element?

Rick_SAS
SAS Super FREQ

"The DO Loop" is the name of the blog.

If you know the row and column of the maximum, then name[row] is the name of row ("b") and VarName[col] is the name of the variable (also "b" for this example).

ivs
Calcite | Level 5 ivs
Calcite | Level 5

thank you for your quick response. i am still unable to determine the row and column for the maximum base on its index value. please help!

ivs
Calcite | Level 5 ivs
Calcite | Level 5

hey Rick, i think i solved it. Let me know if you see any errors in my logic. Many thanks in advance for your opinion.

ivs

data one;

input name $ a b c d;

datalines;

a 10 10 30 10

b 10 10 300 10

c 30 10 10 10

;

run;

proc iml;

use one; *reading data into matrix;

read all into X [rowname=name colname=VarName];

a=X[<:>]; *finding position of max value within the entire matrix;

col=ncol(X); *number of columns in the matrix;

row=nrow(X); *number of rows in the matrix;

/*calc row number 'RowM' for the max value based on the max value position*/

do i=1 to row;

if a<=col then RowM=1;

else do j=1 to col;

  if a=j+col*(i-1) then RowM=i;

  end;

end;

ColM=a-col*(RowM-1); *calc column 'ColM' number for the max value;

RowN=name[RowM]; *lookup row name for max value;

ColN=VarName[ColM]; *lookup col name for max value;

print X RowN ColN ;

run;

quit;

result:

X             a         b         c         d    ROWN     COLN

a               10        10        30        10 b        c

b               10        10       300        10

c               30        10        10        10

Rick_SAS
SAS Super FREQ

Your logic looks OK, but the code is inefficient. There is no need to loop over all rows and columns of your matrix. You can use arithmetic to find the row and column directly, which is what I show in the blog post that I linked to earlier.

start ind2sub( p, ind );
   idx = colvec(ind);
   n = nrow(idx);
   col = 1 + mod(idx-1, p);
   row = 1 + (idx-col) / p;
   return ( row || col );
finish;

a=X[<:>]; *finding position of max value within the entire matrix;
rowcol = ind2sub(ncol(X), a); *call function get (row,col) directly without looping;
RowM=rowcol[1];
ColM=rowcol[2];

RowN=name[RowM]; *lookup row name for max value;
ColN=VarName[ColM]; *lookup col name for max value;
print a RowN ColN ;

ivs
Calcite | Level 5 ivs
Calcite | Level 5

Thank you Rick! Now i see how the function works. sorry i am a bit slow.

Rick_SAS
SAS Super FREQ

I'm glad you solved your problem.

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

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.

From The DO Loop
Want more? Visit our blog for more articles like these.
Discussion stats
  • 9 replies
  • 2853 views
  • 3 likes
  • 2 in conversation