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

Hi I am new to this board and trying to translate a matlab code to sas and am having some problems with the do until loop in proc iml:

The matlab code is:

while any(a<0) 
a(a<0) = 0;
ind = find(a>0);
b = a(ind);
k = length(b);
b = b - 1/k *(sum(b)-1);
a(ind) = b;
end

 

and the sas code that I wrote is:

proc iml;
use XXX 
read all XXX
close XXX
...
do until (ncol(loc(a<0))=0);
a[1,loc(a<0)]=0;
ind=loc(a>0); b=a[ind]; k=ncol(b); b=b-((sum(b)-1)/k);
a[ind]=b;
end;
run;quit;

 

So I am trying to run teh do loop till none of the element in matrix a is negative (using do until (ncol(loc(a<0))=0);) not sure if thats whats causing the problem...

1 ACCEPTED SOLUTION

Accepted Solutions
Ksharp
Super User

So you want process it row by row .



proc iml;
a={-1 -2 1 2,
   -3 3 4 6,
   -3 3 9 -2,
   9 3 4 -2};
   
do i=1 to nrow(a);
 temp=a[i,];
 do while(any(temp<0));
  temp[loc(temp<0)]=0;
  ind=loc(temp>0);
  b=temp[ind];
  k=nrow(b);
  b=b-(1/k)#(sum(b)-1);
  temp[ind]=b;
 end;
 a[i,]=temp;
end;
print a;
quit;

View solution in original post

8 REPLIES 8
dougc
SAS Employee

Here is another translation of your original Matlab code:

 

do while (any(a<0));
    a[loc(a<0)] = 0;
    ind = loc(a>0);
    b = a[ind];
    k = nrow(b)#ncol(b);
    b = b - 1/k #(sum(b)-1);
    a[ind] = b;
end;

 

I ran it with randomly generated vectors and matrices, and it *seemed* to give reasonable output.  Without a better understanding of what you are trying to do, I can't say whether it is correct or not.

Newph
Calcite | Level 5

Thanks so much for the help! The code ran but the results seems a little strange... essentially what I am trying to do is to convert my matrix (in this example below matrix5, its a 22*22 matrix) to its closest stochastic matrix with the below logic: 1) go through the matrix row by row starting with row 1 2) if any of the element in row 1 is negative, then replace the negative number with 0 and if the rest in the row are positive, then normalize all other elements with ind=loc(a>0); b=a[ind]; k=nrow(b)#ncol(b); b=b-1/k#(sum(b)-1); a[ind]=b; keep on looping till all elements are >=0 3) once row 1 satisfies the above condition, go to row 2, and keep on going till row 22 4) output to a below is my updated code:

proc iml; 
use OLD; 
read all var _ALL_ into matrix5[colname=varNames]; 
close OLD; 
a=matrix5; 
do ii=1 to nrow(matrix5); 
   call symputx("iii",ii); 
   a=matrix5[num(symget("iii")), ]; 
   do while (any(a<0)); 
      a[loc(a<0)]=0; 
      ind=loc(a>0); 
      b=a[ind]; k=nrow(b)#ncol(b); 
      b=b-1/k#(sum(b)-1); 
      a[ind]=b; 
   end; 
   rA[num(symget("iii")), ] = a; 
   print rA[L="new4" format=7.4]; 
end; 
quit; 

 

any help would be greatly appreciated!

ballardw
Super User

Post code into the box opened using the {i} menu item in the form to preserve formatting.

dougc
SAS Employee

If I understand what you are trying to do correctly, I believe the following re-working of your code is what you want (with some comments):

 

do ii = 1 to nrow(a);
    do while (any(a[ii,] < 0));     /* search for negative value in row ii */
        a[ii,loc(a[ii,] < 0)] = 0;  /* set negative values in row ii to 0 */
        ind=loc(a[ii,]>0);          /* find remaining non-negative elements in row ii */
        b=a[ii,ind];                /* extract non-negative elements into column vector */
        k=nrow(b)#ncol(b);          /* length of vector, could just use nrow(b) */
        b=b-(sum(b)-1)/k;           /* normalize */
        a[ii,ind]=b;                /* update positive elements */
    end;
end;

 

If I misunderstand your algorithm, perhaps you could provide an example and what you expect as output.

Ksharp
Super User

So you want process it row by row .



proc iml;
a={-1 -2 1 2,
   -3 3 4 6,
   -3 3 9 -2,
   9 3 4 -2};
   
do i=1 to nrow(a);
 temp=a[i,];
 do while(any(temp<0));
  temp[loc(temp<0)]=0;
  ind=loc(temp>0);
  b=temp[ind];
  k=nrow(b);
  b=b-(1/k)#(sum(b)-1);
  temp[ind]=b;
 end;
 a[i,]=temp;
end;
print a;
quit;

Newph
Calcite | Level 5

Thanks so much! 😉  

Ksharp
Super User
Maybe you want this.


http://blogs.sas.com/content/iml/2012/11/28/computing-the-nearest-correlation-matrix.html

Rick_SAS
SAS Super FREQ

You say that your goal is "to convert my matrix to its closest stochastic matrix."

Why do you think that this process will converge to a stochastic matrix? Do you have a reference for this algorithm? Or is this your attempt to create such an algorithm.

 

Notice that if the elements of the input matrix are all positive, but the row sums are not unity, then the algorithm you are implementing does nothing to  change the matrix. For example,

a = {
   0.1 0.2 0.1 0.2 ,
   0.3 0.3 0.4 0.6 ,
   0.3 0.3 0.9 0.2 ,
   0.9 0.3 0.4 0.2 };

 

 

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

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
  • 8 replies
  • 1925 views
  • 2 likes
  • 5 in conversation