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

Hi,

 

Suppose I have a matrix A, and a scalar I want to apply to A, called B. I then want to find apply an inverse so each row in A#B still sums to 1.

proc iml;
	A = {	0.20	0.80	0.00	0.00,
			0.00	0.20	0.80	0.00,
			0.00	0.00	0.20	0.80,
			0.50	0.00	0.30	0.20}; /*Initial Matrix*/
	B = A[ ,+];
	C = {	1.0		1.2		1.0		1.0,
		1.0		1.0		1.1		1.0,
		1.0		1.0		1.25	        1.40,
		1.2		1		1		1}; /*Scalar Matrix*/
	D = A#C;
	E = D[ ,+];
	F = (D#(C ^= 1))[,+];
	G = (1-F)/(E-F);
	H = (G-1)#(C=1) +1;
	J = D#H;
	J[loc(j=.)] = a[loc(j=.)]; /*Work around*/
	K =J[,+]; /*Verify it sums to 1*/

All the code above works, in that it applies the scalar, then changes the values not impacted by the scalar in order for each row to sum to 1. So the values from A#B remain the same, while the others decrease. 

 

But the issue is stemming from when all the values in a row are impacted by the scalar. In the third row, both .2 and .8 are being multiplied by scalar values, thus throwing off the procedure of finding an inverse to multiply the row by. I've created a temporary workaround of setting the missing values back to the original values which is what should happen, but I'd like to use a cleaner way, if possible as this method still creates divide by 0 warnings. 

 

The divide by 0 comes from the e-f in the calculation of G, as both e and f are equal. 

 

Is there a clean way around this?

 

Thank you.

1 ACCEPTED SOLUTION

Accepted Solutions
Rick_SAS
SAS Super FREQ

I can't figure out what you are trying to accomplish (or why). However, to answer your question, you can detect the zero divisors BEFORE you do the division and thereby avoid the "division by zero" error. For example,

 

   divisor = E - F;
/* allocate matrix for (1-F)/(E-F).  I've used missing values for the default
   values, but you can also initialize from existing matrices  */
   G = j(nrow(F), 1, .);    
   idx = loc(divisor ^= 0);  /* good values */
   if ncol(idx) > 0 then      /* only operate on good values */
      G[idx] = (1-F)[idx] / divisor[idx];
   print divisor G;

For more about this technique, see the article "Trap and Cap: Avoid division-by-zero and domain errors when evaluating functions". You might also be interested in learning about the CHOOSE function.

View solution in original post

2 REPLIES 2
Rick_SAS
SAS Super FREQ

I can't figure out what you are trying to accomplish (or why). However, to answer your question, you can detect the zero divisors BEFORE you do the division and thereby avoid the "division by zero" error. For example,

 

   divisor = E - F;
/* allocate matrix for (1-F)/(E-F).  I've used missing values for the default
   values, but you can also initialize from existing matrices  */
   G = j(nrow(F), 1, .);    
   idx = loc(divisor ^= 0);  /* good values */
   if ncol(idx) > 0 then      /* only operate on good values */
      G[idx] = (1-F)[idx] / divisor[idx];
   print divisor G;

For more about this technique, see the article "Trap and Cap: Avoid division-by-zero and domain errors when evaluating functions". You might also be interested in learning about the CHOOSE function.

jl1005
Obsidian | Level 7

Thanks Rick, this worked great.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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
  • 2 replies
  • 856 views
  • 0 likes
  • 2 in conversation