I am looking to generate a matrix that's based on two others (letters are column names and numbers are row numbers to visualize😞
X = {u1 h1 a1, u2 h2 a2, u3 h3 a3};
Y = {b1 f1 r1, b2 f2 r2};
what I am trying to come up with is this:
Z = {(b1-u1)+(f1-h1)+(r1-a1) (b2-u1)+(f2-h1)+(r2-a1)
, (b1-u2)+(f1-h2)+(r1-a2) (b2-u2)+(f2-h2)+(r2-a2)
, (b1-u3)+(f1-h3)+(r1-a3) (b2-u3)+(f2-h3)+(r2-a3)
, (b1-u4)+(f1-h4)+(r1-a4) (b2-u4)+(f2-h4)+(r2-a4)}
what's the most efficient way to go about this? I can only think of do-loops for each expression within parenthesis to create submatrices and then add them together? has any one done something similar. please point me in the right direction. many thanks in advance!
I assume you made a mistake and the z[1,2] element should be -5 and the Z[3,1] element should be -9.
It looks like you want to form the matrices
M1 = Y[1, ] - X;
M2 = Y[2,] - X;
and then sum the rows of these matrices to form the columns of Z.
For this example, you can use this one-liner, which uses the '+' subscript reduction operator to get the row sums:
proc iml;
X = {2 7 4,
3 2 1,
5 9 3};
Y = {1 3 4,
2 5 1};
Z = ((Y[1,] - X)[ ,+]) ||
((Y[2,] - X)[ ,+]);
print Z;
If you have an arbitrary number of rows in Y, you can loop over the rows of Y like this:
free Z;
do i = 1 to nrow(Y);
Z = Z || (Y[i,] - X)[ ,+];
end;
print Z;
It might also be possible to get this result by using matrix operators instead of a loop. Maybe by using a strategic application of the Kronecker product? If so, @IanWakeling might have a suggestion.
> I am looking to generate a matrix that's based on two others (letters are column names and
> numbers are row numbers to visualize
X = {u1 h1 a1, u2 h2 a2, u3 h3 a3};
Y = {b1 f1 r1, b2, f2, r2};
I don't understand. Can you provide numbers for the "two other" matrices and what you expect for X and Y? I don't even know what "two other" matrices you are talking about. It looks like the matrices are u, h, a, b, f, and r.
Without more information, the best I can suggest is vertical concatenation:
X = u || h || a;
Y = b || f || r;
my apologies - I made a mistake with extra commas in the second matrix. I corrected the original post. here is what I am after in numbers
X = {2 7 4, 3 2 1, 5 9 3}
Y = {1 3 4, 2 5 1}
I am trying to have Z calculate like so:
Z = {(1-2)+(3-7)+(4-4) (2-2)+(5-7)+(4-1)
,(1-3)+(3-2)+(4-1) (2-3)+(5-2)+(1-1)
,(1-5)+(3-9)+(4-3) (2-5)+(5-9)+(1-3)}
so result looks like this:
Z = {-5 1, 2 2, 9 -9}
many thanks in advance for your thoughts!
I assume you made a mistake and the z[1,2] element should be -5 and the Z[3,1] element should be -9.
It looks like you want to form the matrices
M1 = Y[1, ] - X;
M2 = Y[2,] - X;
and then sum the rows of these matrices to form the columns of Z.
For this example, you can use this one-liner, which uses the '+' subscript reduction operator to get the row sums:
proc iml;
X = {2 7 4,
3 2 1,
5 9 3};
Y = {1 3 4,
2 5 1};
Z = ((Y[1,] - X)[ ,+]) ||
((Y[2,] - X)[ ,+]);
print Z;
If you have an arbitrary number of rows in Y, you can loop over the rows of Y like this:
free Z;
do i = 1 to nrow(Y);
Z = Z || (Y[i,] - X)[ ,+];
end;
print Z;
It might also be possible to get this result by using matrix operators instead of a loop. Maybe by using a strategic application of the Kronecker product? If so, @IanWakeling might have a suggestion.
Thank you! This is almost there!
I just can't figure out why calculation is always on the first element of X and Y
here is Z after calculating it both ways (loop or no loop, same result)
Because both rows of Y sum to 8. You can further simplify the computation to become
rowSumX = X[ ,+]; /* sum of rows of X */
Z = Y[1 ,+] - rowSumX ||
Y[1 ,+] - rowSumX;
print Z;
this is great! Thank you so much!
You could apply the Kroneker product (the @ operator) and avoid the loop as follows:
diff = Y @ j(nrow(X), 1) - j(nrow(Y), 1) @ X;
Z = shapecol( diff[ ,+], nrow(X));
print Z;
It is not as easy to see what is going on, so you may prefer Rick's solution if others need to use your code.
Thank you! I need to study up this approach - not easy to see.
I am just curious - how to make this work on multiplication?
a = {1 2 3}
b={1 2 3, 4 5 6, 7 8 9}
to get to:
c={1 4 9, 4 10 18, 7 16 27}
never mind - this is just element wise multiplication. I am thinking too much I suppose. 🙂
Indeed it is elementwise multiplication, but if you want the row sums of c, which was part of the original problem, then the whole process simplifies to normal matrix multiplication:
a = {1 2 3};
b = {1 2 3, 4 5 6, 7 8 9};
d = b * a`;
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
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.