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
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 ;
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
Thanks Rick. I do not have SAS/IML 12.1 - going to try the Do Loop approach.
ivs
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?
"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).
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!
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
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 ;
Thank you Rick! Now i see how the function works. sorry i am a bit slow.
I'm glad you solved your problem.
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
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.