turn on suggestions

Auto-suggest helps you quickly narrow down your search results by suggesting possible matches as you type.

Showing results for

Find a Community

Topic Options

- RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page

Highlighted
# Matrix diagonal operation

Options

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

02-14-2018 01:28 PM

Hi Guys,

I’m in process of converting an excel report into sas proc iml code.

I have to achieve the below, can anyone give me a hand please?

- For all diagonal values I want to get 1.
- For non-diagonal values, divide the respective values by column total. If division ends in error populate value 0.

Attached in the sample data set.

Accepted Solutions

Solution

02-15-2018
05:39 AM

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to akpattnaik

02-15-2018 04:49 AM - edited 02-15-2018 05:02 AM

I think this will do what you want:

```
proc iml;
x = {1 . 3, 4 5 6, -5 4 1};
n = nrow(x);
y = x / x[+, ]; /* divide by zero warnings in log */
y[do(1,n#n,n+1)] = 1; /* set diagonal to 1 */
idx = loc(y=.); /* find any missing values and replace with zero */
if ncol(idx)>0 then y[idx] = 0;
print x, y;
quit;
```

I have set up the first column of x to have a sum of zero, this generates missing values in the first column of y which are then replaced with zero.

All Replies

Solution

02-15-2018
05:39 AM

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to akpattnaik

02-15-2018 04:49 AM - edited 02-15-2018 05:02 AM

I think this will do what you want:

```
proc iml;
x = {1 . 3, 4 5 6, -5 4 1};
n = nrow(x);
y = x / x[+, ]; /* divide by zero warnings in log */
y[do(1,n#n,n+1)] = 1; /* set diagonal to 1 */
idx = loc(y=.); /* find any missing values and replace with zero */
if ncol(idx)>0 then y[idx] = 0;
print x, y;
quit;
```

I have set up the first column of x to have a sum of zero, this generates missing values in the first column of y which are then replaced with zero.

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to IanWakeling

02-15-2018 11:20 AM

Hi Ian,

A quick question. I want to check a condition .i.e. if the value is not zero then set the diagonal to 1.

I tried a lot but couldn't find what needs to be done to the below. Any help will really be appreciated.

Cheers

` y[do(1,n#n,n+1)] = 1; /* set diagonal to 1 */`

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to akpattnaik

02-15-2018 11:51 AM

I think the following is what you need:

`y[do(1,n#n,n+1)] = vecdiag(y)^=.;`

which sets the diagonal to 1 wherever it is non-missing after the division, otherwise it is set to zero.

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to IanWakeling

02-16-2018 11:04 AM

Excellent. Great stuff.

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to akpattnaik

02-19-2018 08:32 AM

Hi Ian,

Trust you well. Just wondering if you can help with the below:

Now instead of 1 on the diagonal, i want 1- a matrix element.

For example:

`y[do(1,n#n,n+1)] = 1- AR; (where AR is a matrix, of same shape)`

`y[do(1,n#n,n+1)] = (1- AR); `

Both doesn't work. I get a error - "Matrix do not conform to the operation"

Any idea?

` `

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to akpattnaik

02-19-2018 08:49 AM

The left hand side is referring only to the diagonal elements, while the right hand side contains n^2 elements this is the reason for the non-conforming error message. The solution is to extract only the diagonal element of AR using the vecdiag function.

`y[do(1,n#n,n+1)] = 1 - vecdiag(AR);`

- Mark as New
- Bookmark
- Subscribe
- RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content

Posted in reply to IanWakeling

02-19-2018 09:18 AM

Thanks a Ton Ian. You are a genius!

Cheers