Week 11+ “IML” Class Activities

File: week-11-12nov07-IML.doc

Directory (hp):

C:\baileraj\Classes\Fall 2007\sta402\handouts

Directory: \\Muserver2\USERS\B\\baileraj\Classes\sta402\handouts

SAS/IML Programming

* Basic matrix concepts: rows, columns, scalars

* matrix operators

* subscripting

* matrix functions

* creating matrices from data sets and vice versa

* sample applications

Acknowledgments:

Thanks to Jim Deddens (UC) for sharing handouts that served

as the starting place for a number of the illustrations contained herein (Deddens Handouts #17-22)

References:

SAS/IML User's Guide on SAS OnlineDoc (

Links of particular interest …

> Understanding the Language

> Working with Matrices

> Working with SAS Data Sets (bringing a SAS data set into IML)

> Programming Statements (program control/module definition)

Introductory remarks

* IML = Interactive Matrix Language – it is a programming

language for matrix manipulations (can control flow of

operations with commands (e.g. DO/END, START/FINISH, IF-THEN/

ELSE, etc.). Lots of built-in matrix manipulation functions

and subroutines are available.

* basic object = data matrix (so can perform operations on

entire matrices)

* can run interactively or store statements in a module

* can build functions/subroutines using these modules

Matrix Definitions and vocabulary

* Matrices have entries of the same type (either all numeric or character – note the difference

from a SAS data set which can include variables of either type).

* Matrix names are 1 to 8 characters (begin with letter or underscore and continue with letters,

numbers or underscores)

* Matrix possess property of DIMENSION (# rows and columns)

* ROW VECTOR = 1xn matrix

COLUMN vector = mx1 matrix

SCALAR = 1x1 matrix

Example 1: Basic matrix definition + subscripting

options nodate nocenter formdlim="-";

PROCIML;

*makes a 2x3 matrix;

C = {123,456};

print '2x3 example matrix C = {1 2 3,4 5 6} =' C;

*select 2nd row;

C_r2 = C[2,];

print '2nd row of C = C[2,] =' C_r2;

*select 3rd column;

C_c3 = C[,3];

print '3rd column of C = C[,3] =' C_c3;

*select the (2,3) element of C;

C23 = C[2,3];

print '(2,3) element of C = C[2,3] =' C23;

*makes a 1x3 matrix by summing over rows in each of the columns;

C_csum=C[+,];

print '1x3 column sums of C = C[+,] =' C_csum;

*makes a 2x1 matrix by summing over columns in each of the rows;

C_rsum=C[,+];

print '2x1 row sums of C = C[,+] =' C_rsum;

run;

C

2x3 example matrix C = {1 2 3,4 5 6} = 1 2 3

4 5 6

C_R2

2nd row of C = C[2,] = 4 5 6

C_C3

3rd column of C = C[,3] = 3

6

C23

(2,3) element of C = C[2,3] = 6

C_CSUM

1x3 column sums of C = C[+,] = 5 7 9

C_RSUM

2x1 row sums of C = C[,+] = 6

15

Example 2: Basic IML code and matrix definitions

options nodate nocenter formdlim="-";

PROCIML;

*makes a 2x3 matrix;

C = {123,456};

print '2x3 example matrix C = {1 2 3,4 5 6} =' C;

*makes a 1x3 matrix by summing over the rows in each of the columns;

C1=C[+,];

print '1x3 column sums of C = C[+,] =' C1;

*makes a 2x1 matrix by summing over the columns in each of the rows;

C2=C[,+];

print '2x1 row sums of C = C[,+] =' C2;

*makes a matrix out of second column of C;

F = C[,2];

print 'extract 2nd column of C into new vector (F) = C[,2] =' F;

*puts second column of c on diagonal;

D = DIAG( C[,2] );

print 'put 2nd column of C into a diagonal matrix (D) = DIAG(C[,2]) =' D;

*makes a vector out of the diagonal;

CC= VECDIAG(D);

print 'convert diagonal (of D) into vector (CC) = VECDIAG(D) =' CC;

*exponentiates each entry;

DD = EXP(D);

print 'exponentiate D yielding DD = EXP(D) =' DD;

*puts c next to itself - column binds C with itself;

E = C || C;

print 'Column bind C with itself yielding E = C||C =' E;

*puts a row of 2's below C - row bind ;

F = C // SHAPE(2,1,3);

print "Row bind C with vector of 2's (F) = C // SHAPE(2,1,3) =" F;

*creates a 3x2 matrix with matrix entry C;

K = REPEAT(C,3,2);

print '6x6 matrix = ' K;

*raises each entry of columns 2 & 3 of C to the third power then multiples by 3 and adds 3;

G = 3+3*(C[,2:3]##3);

print '3 + 3*(col2&3)^3 (G) = ' G;

*raises each entry of C to itself;

H = C ## C;

print 'raise C elements to itself (H) = C##C =' H;

*multiplies each entry of C by itself;

J = C # C;

print 'elementwise multiplication of C with itself (J) = C#C =' J;

quit;

SAS OUTPUT . . .

C

2x3 example matrix C = {1 2 3,4 5 6} = 1 2 3

4 5 6

C1

1x3 column sums of C = C[+,] = 5 7 9

C2

2x1 row sums of C = C[,+] = 6

15

F

extract 2nd column of C into new vector (F) = C[,2] = 2

5

D

put 2nd column of C into a diagonal matrix (D) = DIAG(C[,2]) = 2 0

0 5

CC

convert diagonal (of D) into vector (CC) = VECDIAG(D) = 2

5

D

exponentiate D yielding DD = EXP(D) = 7.3890561 1

1 148.41316

Column bind C with itself yielding E = C||C =

E

1 2 3 1 2 3

4 5 6 4 5 6

F

Row bind C with vector of 2's (F) = C // SHAPE(2,1,3) = 1 2 3

4 5 6

2 2 2

K

6x6 matrix = 1 2 3 1 2 3

4 5 6 4 5 6

1 2 3 1 2 3

4 5 6 4 5 6

1 2 3 1 2 3

4 5 6 4 5 6

G

3 + 3*(col2&3)^3 (G) = 27 84

378 651

H

raise C elements to itself (H) = C##C = 1 4 27

256 3125 46656

J

elementwise multiplication of C with itself (J) = C#C = 1 4 9

16 25 36

Example 3 More IML Matrix definitions

prociml;

c1 = shape(1,5,1); * using shape function;

c2 = {1,1,1,1,1};

c3 = T({11111}); * transpose matrix;

c4 = T({[5] 1}) ; * using repetition factors;

print 'shape(1,5,1) = ' c1;

print '{1,1,1,1,1} = ' c2;

print 'T({1 1 1 1 1}) = ' c3;

print 'T({[5] 1}) = ' c4;

quit;

C1

shape(1,5,1) = 1

1

1

1

1

C2

{1,1,1,1,1} = 1

1

1

1

1

C3

T({1 1 1 1 1}) = 1

1

1

1

1

C4

T({[5] 1}) = 1

1

1

1

1

Example 4:creating matrices from data sets and vice versa

libname mydat 'D:\baileraj\Classes\Fall 2003\sta402\data';

prociml;

/* read SAS data in IML */

use mydat.nitrofen;

read all var { total conc } into nitro;

/* alternative coding */

use mydat.nitrofen var{ total conc };

read all into nitro2;

nitro = nitro || nitro[,2]##2; * adding column with conc^2;

nitro2 = nitro2 || (nitro2[,2]-nitro2[+,2]/nrow(nitro2)) ; * add column with centered concentration;

nitro2 = nitro2 || nitro2[,3]##2; * adding column with scaled conc^2;

show names; * show matrices constructed in IML;

*print nitro;

*print nitro2;

create n2 from nitro2; * creates SAS data set n2 from matrix nitro;

append from nitro2;

/* a little graphing in IML */

call pgraf(nitro[,2:1],'*','Nitrofen concentration', 'Number of young', 'Plot of #young vs. conc');

quit;

procprint data=n2;

title 'print of data constructed in IML';

run;

Plot of #young vs. conc

40 ˆ

‚ * *

35 ˆ *

‚ *

‚ * *

‚ * *

‚ * * *

30 ˆ * *

‚ * *

N ‚

u ‚ * * * *

m ‚ * *

b 25 ˆ

e ‚ *

r ‚ * *

o ‚ *

f 20 ˆ

y ‚

o ‚ *

u ‚ *

n 15 ˆ * *

g ‚

‚ *

‚ *

10 ˆ

‚ * *

‚ *

5 ˆ *

‚ *

0 ˆ *

Šƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒˆƒƒƒƒ

0 20 40 60 80 100 120 140 160 180 200 220 240 260 280 300 320

Nitrofen concentration

print of data constructed in IML

print of data constructed in IML

Obs COL1 COL2 COL3 COL4

1 27 0 -157 24649

2 32 0 -157 24649

3 34 0 -157 24649

4 33 0 -157 24649

5 36 0 -157 24649

6 34 0 -157 24649

7 33 0 -157 24649

8 30 0 -157 24649

9 24 0 -157 24649

10 31 0 -157 24649

11 33 80 -77 5929

12 33 80 -77 5929

13 35 80 -77 5929

14 33 80 -77 5929

15 36 80 -77 5929

16 26 80 -77 5929

17 27 80 -77 5929

18 31 80 -77 5929

19 32 80 -77 5929

20 29 80 -77 5929

21 29 160 3 9

22 29 160 3 9

23 23 160 3 9

24 27 160 3 9

25 30 160 3 9

26 31 160 3 9

27 30 160 3 9

28 26 160 3 9

29 29 160 3 9

30 29 160 3 9

31 23 235 78 6084

32 21 235 78 6084

33 7 235 78 6084

34 12 235 78 6084

35 27 235 78 6084

36 16 235 78 6084

37 13 235 78 6084

38 15 235 78 6084

39 21 235 78 6084

40 17 235 78 6084

41 6 310 153 23409

42 6 310 153 23409

43 7 310 153 23409

44 0 310 153 23409

45 15 310 153 23409

46 5 310 153 23409

47 6 310 153 23409

48 4 310 153 23409

49 6 310 153 23409

50 5 310 153 23409

Example 5: sample applications I: estimating PI

prociml;

nsim = 4000;

temp_mat = J(nsim,3,0);

/* col 1 = random x coordinate

col 2 = random y coordinate

col 3 = 1 if y <= sqrt(1-x^2)

*/

do isim = 1 to nsim;

temp_mat[isim,1] = uniform(0); * generate X ~ unif(0,1);

temp_mat[isim,2] = uniform(0); * generate Y ~ unif(0,1);

end;

/*

print ‘temp_mat = ‘ temp_mat;

junk1 = temp_mat[,1]#temp_mat[,1];

print ‘temp_mat[,1]#temp_mat[,1] = ‘ junk1;

junk2 = temp_mat[,2];

print ‘temp_mat[,2] = ‘ junk2;

*/

temp_mat[,3] = (temp_mat[,2]<=

sqrt(J(nsim,1,1)-temp_mat[,1]#temp_mat[,1]));

pi_over4 = temp_mat[+,3]/nsim;

pi_est = 4*pi_over4;

se_est = 4*sqrt(pi_over4*(1-pi_over4)/nsim);

pi_LCL = pi_est – 2*se_est;

pi_UCL = pi_est + 2*se_est;

print ‘------‘;

print ‘Estimating PI using MC simulation methods with ‘ nsim ‘data points’;

print ‘PI-estimate = ‘ pi_est;

print ‘SE(PI-estimate) = ‘ se_est;

print ‘CI: [‘ pi_LCL ’ , ‘ pi_UCL ’]’;

print ‘------‘;

quit;

------

NSIM

Estimating PI using MC simulation methods with 4000 data points

PI_EST

PI-estimate = 3.126

SE_EST

SE(PI-estimate) = 0.0261349

PI_LCL PI_UCL

CI: [ 3.0737303 , 3.1782697 ]

------

Example 6: sample applications I: estimating PI using a MODULE

options nocenter nodate;

prociml;

/* MODULE TO ESTIMATE PI

- Monte Carlo simulation used

- Strategy:

Generate X~Unif(0,1) and Y~Unif(0,1)

Determine if Y <= sqrt(1-X*X)

PI/4 estimated by proportion of times condition above is true

- INPUT

nsim

- OUTPUT

estimate of PI along with SE and CI

*/

start MC_PI(nsim);

temp_mat = J(nsim,3,0);

do isim = 1 to nsim;

temp_mat[isim,1] = uniform(0); * generate X ~ unif(0,1);

temp_mat[isim,2] = uniform(0); * generate Y ~ unif(0,1);

end;

temp_mat[,3] = (temp_mat[,2]<=

sqrt(J(nsim,1,1)-temp_mat[,1]#temp_mat[,1]));

pi_over4 = temp_mat[+,3]/nsim;

pi_est = 4*pi_over4;

se_est = 4*sqrt(pi_over4*(1-pi_over4)/nsim);

pi_LCL = pi_est - 2*se_est;

pi_UCL = pi_est + 2*se_est;

print '------';

print 'Estimating PI using MC simulation methods with ' nsim 'data points';

print 'PI-estimate = ' pi_est;

print 'SE(PI-estimate) = ' se_est;

print 'CI: [' pi_LCL ' , ' pi_UCL ']';

print '------';

finish MC_PI;

/**************************************************************************/

run MC_PI(400);

run MC_PI(1600);

run MC_PI(4000);

quit;

SAS OUTPUT . . . (edited)

------

NSIM

Estimating PI using MC simulation methods with 400 data points

PI_EST

PI-estimate = 3.08

SE_EST

SE(PI-estimate) = 0.0841665

PI_LCL PI_UCL

CI: [ 2.911667 , 3.248333 ]

------

NSIM

Estimating PI using MC simulation methods with 1600 data points

PI_EST

PI-estimate = 3.125

SE_EST

SE(PI-estimate) = 0.0413399

PI_LCL PI_UCL

CI: [ 3.0423203 , 3.2076797 ]

------

NSIM

Estimating PI using MC simulation methods with 4000 data points

PI_EST

PI-estimate = 3.198

SE_EST

SE(PI-estimate) = 0.0253219

PI_LCL PI_UCL

CI: [ 3.1473562 , 3.2486438 ]

------

Example 7: Using IML to construct a randomization test for testing equality of 2 populations (revisiting WEEK7 example)

/* RECALL – t-test previously conducted

procttest;

title NITROFEN: t-test of (0, 160) concentrations;

class conc;

var total;

run;

NITROFEN: t-test of (0, 160) concentrations

The TTEST Procedure

Statistics

Lower CL Upper CL Lower CL Upper CL

Variable conc N Mean Mean Mean Std Dev Std Dev Std Dev Std Err

total 0 10 28.827 31.4 33.973 2.4737 3.5963 6.5654 1.1372

total 160 10 26.612 28.3 29.988 1.6229 2.3594 4.3073 0.7461

total Diff (1-2) 0.2424 3.1 5.9576 2.2981 3.0414 4.4977 1.3601

T-Tests

Variable Method Variances DF t Value Pr > |t|

total Pooled Equal 18 2.28 0.0351

total Satterthwaite Unequal 15.5 2.28 0.0372

Equality of Variances

Variable Method Num DF Den DF F Value Pr > F

total Folded F 9 9 2.32 0.2252

*/

/* ------

use PLAN to generate a set of indices for the randomization test

and then use TRANSPOSE to package the output

Do the calculations in PROC IML instead of DATA step programming

------*/

options nocenter nodate;

libname class 'D:\baileraj\Classes\Fall 2003\sta402\data';

title “Randomization test in IML – Nitrofen conc 0 vs. 160 compared”;

data test; set class.nitrofen;

if conc=0 | conc=160;

procplan;

factors test=4000 ordered in=20;

output out=d_permut;

run;

proctranspose data=d_permut prefix=in out=out_permut(keep=in1-in20); by test;

run;

prociml;

/* read SAS data in IML */

use class.nitrofen;

read all var { total conc } where (conc=0|conc=160) into nitro;

use out_permut;

read all into perm_index;

obs_vec = nitro[,1];

obs_diff = sum(obs_vec[1:10]) - sum(obs_vec[11:20]); * test statistic;

PERM_RESULTS = J(nrow(perm_index),2,0); * initialize results matrix;

do iperm = 1 to nrow(perm_index);

ind = perm_index[iperm,]; * extract permutation index;

perm_resp = obs_vec[ind]; * select corresponding obs;

perm_diff = sum(perm_resp[1:10]) - sum(perm_resp[11:20]);

PERM_RESULTS[iperm,1] = perm_diff; * store perm TS value/indicator;

PERM_RESULTS[iperm,2] = abs(perm_diff) >= abs(obs_diff);

end;

perm_Pvalue = PERM_RESULTS[+,2]/nrow(PERM_RESULTS);

print ‘Permutation P-value = ‘ perm_Pvalue;

from SAS OUTPUT . . .

PERM_PVALUE

Permutation P-value = 0.03575

/* code for testing components */

print nitro;

print perm_index;

obs_vec = nitro[,1];

print obs_vec;

ind = perm_index[1,];

print ind;

permdat = obs_vec[ind];

print permdat;

tranind = T(ind);

print obs_vec tranind permdat;

/* alternative coding */

obs_vec = shape(nitro[,1],1,20);

obs_diff = sum(obs_vec[1,1:10]) - sum(obs_vec[1,11:20]);

print obs_vec obs_diff;

PERM_RESULTS = J(nrow(perm_index),2,0); * initialize results matrix;

do iperm = 1 to nrow(perm_index);

ind = perm_index[iperm,];

perm_resp = shape(obs_vec[1,ind],1,20);

perm_diff = sum(perm_resp[1,1:10]) - sum(perm_resp[1,11:20]);

PERM_RESULTS[iperm,1] = perm_diff;

PERM_RESULTS[iperm,2] = abs(perm_diff) >= abs(obs_diff);

end;

perm_Pvalue = PERM_RESULTS[+,2]/nrow(PERM_RESULTS);

print'Permutation P-value = ' perm_Pvalue;

Noble IML example 1: bisection method

options ls=78 formdlim='-' nodate pageno=1;

/* find sqrt(x = 3) using bisection */

prociml;

x = 3;

hi = x;

lo = 0;

history = 0||lo||hi;

iteration = 1;

delta = hi - lo;

do while(delta > 1e-7);

mid = (hi + lo)/2;

check = mid**2 > x;

if check

then hi = mid;

else lo = mid;

delta = hi - lo;

history = history//(iteration||lo||hi);

iteration = iteration + 1;

end;

print mid;

create process var {iteration low high};

append from history;

------

MID

1.7320509

procprintdata=process;

run;

/* output from PROC PRINT

------

Obs ITERATION LOW HIGH

1 0 0.00000 3.00000

2 1 1.50000 3.00000

3 2 1.50000 2.25000

4 3 1.50000 1.87500

5 4 1.68750 1.87500

6 5 1.68750 1.78125

7 6 1.68750 1.73438

8 7 1.71094 1.73438

9 8 1.72266 1.73438

10 9 1.72852 1.73438

11 10 1.73145 1.73438

12 11 1.73145 1.73291

13 12 1.73145 1.73218

14 13 1.73181 1.73218

15 14 1.73199 1.73218

16 15 1.73199 1.73209

17 16 1.73204 1.73209

18 17 1.73204 1.73206

19 18 1.73204 1.73205

20 19 1.73205 1.73205

21 20 1.73205 1.73205

22 21 1.73205 1.73205

23 22 1.73205 1.73205

24 23 1.73205 1.73205

25 24 1.73205 1.73205

26 25 1.73205 1.73205

------

*/

symbol interpol=join value=#;

axis1label=('Limits');

procgplotdata=process;

plot (low high)*iteration / overlayvaxis=axis1;

run;

quit;

Noble IML example 2: Ridge regression

Ridge regression

where for

1. Center and scale all variables

Note:

for

2. Let

(i.e. biased estimation)

OLS solution when c = 0

Example:

A. Suppose k = 3 and the indendepent variables are orthogonal to each other then

B. Suppose k = 3 and the indendepent variables and two of the variables are highly correlated with each other then

Let c = 0.01

Illustration:

Measurements were taken on 17 U.S. Navy hospitals

Independent variables =

Average daily patient load

Monthly x-ray exposures

Monthly occupied bed days

Eligible population in area (divided by 1000)

Average length of patients’ stay in days

Response = Monthly labor hours

options ls=78 formdlim='-' nodate pageno=1;

data hospital;

input patient_load x_ray bed_days population stay_length labor_hours;

cards;

15.57 2463 472.92 18.0 4.45 566.52

44.02 2048 1339.75 9.5 6.92 696.82

20.42 3940 620.25 12.8 4.28 1033.15

18.74 6505 568.33 36.7 3.90 1603.62

49.20 5723 1497.60 35.7 5.50 1611.37

44.92 11520 1365.83 24.0 4.60 1613.27

55.48 5779 1687.00 43.3 5.62 1854.17

59.28 5969 1639.92 46.7 5.15 2160.55

94.39 8461 2872.33 78.7 6.18 2305.58

128.02 20106 3655.08 180.5 6.15 3503.93

96.00 13313 2912.00 60.9 5.88 3571.89

131.42 10771 3912.00 103.7 4.88 3741.40

127.21 15543 3865.67 126.8 5.50 4026.52

252.90 36194 7684.10 157.7 7.00 10343.81

409.20 34703 12446.33 169.4 10.78 11732.17

463.70 39204 14098.40 331.4 7.05 15414.94

510.22 86533 15524.00 371.6 6.35 18854.45

;

procregdata=hospital;

model labor_hours = patient_load x_ray bed_days population stay_length / vif;

run;

------

The SAS System 1

The REG Procedure

Model: MODEL1

Dependent Variable: labor_hours

Analysis of Variance

Sum of Mean

Source DF Squares Square F Value Pr > F

Model 5 490195304 98039061 238.74 <.0001

Error 11 4517236 410658

Corrected Total 16 494712540

Root MSE 640.82590 R-Square 0.9909

Dependent Mean 4978.48000 Adj R-Sq 0.9867

Coeff Var 12.87192

Parameter Estimates

Parameter Standard Variance

Variable DF Estimate Error t Value Pr > |t| Inflation

Intercept 1 1957.65555 1062.65900 1.84 0.0925 0

patient_load 1 -19.08612 96.18624 -0.20 0.8463 9348.14904

x_ray 1 0.05574 0.02123 2.62 0.0236 7.95401

bed_days 1 1.69311 3.04722 0.56 0.5896 8710.16847

population 1 -4.07037 7.11731 -0.57 0.5789 23.00120

stay_length 1 -392.64933 207.75252 -1.89 0.0854 4.21971

%macro find_c(datain=,y=,x=,dataout=);

/*------+

| parameters |

| datain = dataset to be analyzed |

| y = response variable |

| x = list of independent variables |

| dataout = dataset containing ridge estimates |

+------*/

proc iml;

/* read in data */

use &datain;

read all var {&x} into data;

/* center */

n = nrow(data);

k = ncol(data);

centered = data -j(n,n,1)*data/n;

/* scale */

r = j(k,k,.);

do i = 1 to k;

do j = 1 to k;

r[i,j] = (centered[,i]`*centered[,j])

/sqrt(centered[,i]`*centered[,i]*centered[,j]`*centered[,j]);

end;

end;

/* find c via bisection */

hi = 1;

lo = 0;

delta = hi - lo;

do while(delta > 1e-8);

c = (hi + lo)/2;

maxvif = max(diag(inv(r+c*i(k))*r*inv(r+c*i(k))));

if maxvif > 5

then lo = c;

else hi = c;

delta = hi - lo;

end;

mattrib c label='Biasing constant';

print c;

create temp var {c};

append from c;

data _null_;

set temp;

call symput('c',c);

run;

proc reg data=hospital outest=&dataout noprint;

model &y = &x / ridge=&c;

run;

%mend;

%find_c(datain=hospital,

y=labor_hours,

x=patient_load x_ray bed_days population stay_length,

dataout=ridge);

procprintdata = ridge;

run;

quit;

------

Biasing constant

0.0318075

------

Obs _MODEL_ _TYPE_ _DEPVAR_ _RIDGE_ _PCOMIT_ _RMSE_ Intercept

1 MODEL1 PARMS labor_hours . . 640.826 1957.66

2 MODEL1 RIDGE labor_hours 0.031808 . 724.538 798.25

patient_ stay_ labor_

Obs load x_ray bed_days population length hours

1 -19.0861 0.055738 1.69311 -4.07037 -392.649 -1

2 12.5864 0.063608 0.43146 2.24981 -171.973 -1

Example: Diagonalize a symmetric matrix:

(based on Deddens h.o.)

PROC IML;

A={1 2 3,4 5 6,5 7 9}; * this inputs a matrix;

print A;

G=GINV(A); * this is the generalized inverse;

print G;

B=A`*A;

print B;

CALL EIGEN(M,E,B); * this computes the eigenvalues of B;

print M; * M is a vector of eigenvalues;

print E; * E is a matrix whose columns are;

M=FUZZ(M);

print M;

BB=E*DIAG(M)*E`; * orthogonal eigenvectors;

print BB;

RUN;

A

1 2 3

4 5 6

5 7 9

G

-0.777778 0.6111111 -0.166667

-0.111111 0.1111111 7.027E-17

0.5555556 -0.388889 0.1666667

B

42 57 72

57 78 99

72 99 126

M

245.33969

0.660309

-1.14E-14

E

0.4115876 0.8148184 -0.408248

0.5638129 0.1242915 0.8164966

0.7160382 -0.566235 -0.408248

M

245.33969

0.660309

0

BB

42 57 72

57 78 99

72 99 126

Example Generating Multivariate Normal random variables

(based on Deddens h.o.)

/*

Generate a random sample of size 100 from a bivariate normal

distribution with mean (mu1,mu2)=(8,10), and variance covariance

matrix V=(4 3,3 9). X1~ N(8,4); X2 ~ N(10,9)

with Cov(X1, X2) = 3, so the correlation is 3/sqrt(4*9)=.5

*/

PROC IML;

X=SHAPE(0,2,100); *X= 2x100 matrix of 0s;

MU=8*SHAPE(1,1,100)//10*SHAPE(1,1,100); *MU=2x100 matrix of 8s and 10s;

DO N=1 TO 100;

DO M=1 TO 2;

X[M,N]=RANNOR(0); * X = 2x100 matrix with indep. z-values;

END;

END;

V={4 3,3 9};

CALL EIGEN (M,E,V);

T=E*DIAG(SQRT(M))*E`; * this is the square root of V;

Y=MU+T*X; *Y is a 2x100 matrix;

W=Y`; *W is a 100x2 matrix;

CREATE LAST FROM W; *creates a data set from the matrix W;

APPEND FROM W;

PROC CORR COV DATA=LAST; *computes covariances and correlations;

VAR COL1 COL2;

RUN;

The CORR Procedure

2 Variables: COL1 COL2

Covariance Matrix, DF = 99

COL1 COL2

COL1 4.42686739 3.57748316

COL2 3.57748316 10.77696443

Simple Statistics

Variable N Mean Std Dev Sum Minimum Maximum

COL1 100 8.00686 2.10401 800.68631 2.11136 13.18996

COL2 100 10.01085 3.28283 1001 2.90976 17.50832

Pearson Correlation Coefficients, N = 100

Prob > |r| under H0: Rho=0

COL1 COL2

COL1 1.00000 0.51794

<.0001

COL2 0.51794 1.00000

<.0001

This could also be done using the following code:

PROC IML;

MU={8 10};

COV={4 3, 3 9};

CALL VNORMAL(W,MU,COV,1000,0);

CREATE LAST FROM W;

APPEND FROM W;

PROC CORR COV DATA=LAST;

VAR COL1 COL2;

RUN;

The CORR Procedure

2 Variables: COL1 COL2

Covariance Matrix, DF = 999

COL1 COL2

COL1 4.252231110 3.409982609

COL2 3.409982609 9.263162292

Simple Statistics

Variable N Mean Std Dev Sum Minimum Maximum

COL1 1000 8.00001 2.06209 8000 1.44165 13.93833

COL2 1000 10.03342 3.04354 10033 -0.04513 19.35617

Pearson Correlation Coefficients, N = 1000

Prob > |r| under H0: Rho=0

COL1 COL2

COL1 1.00000 0.54333

<.0001

COL2 0.54333 1.00000

Example: Regression using matrix definition for LSE

(based on Deddens h.o.)

/*

PROC IML is a interactive matrix language that contains lots of

matrix functions, SAS functions, and various programming statements.

This handout uses PROC IML to perform usual linear regression. (from

h.o. #22)

*/

DATA DRAPER;

INPUT X1 X2 X3 X4 Y;

datalines;

7 26 6 60 78.5

1 29 15 52 74.3

11 56 8 20 104.3

11 31 8 47 87.6

7 52 6 33 95.9

11 55 9 22 109.2

3 71 17 6 102.7

1 31 22 44 72.5

2 54 18 22 93.1

21 47 4 26 115.9

1 40 23 34 83.8

11 66 9 12 113.3

10 68 8 12 109.4

PROC IML;

USE DRAPER;

READ ALL INTO XX; *this makes a matrix out of a data set;

Y=XX[,5]; N=NROW(XX); R=NCOL(XX);

ONE=SHAPE(1,N,1);

X=ONE||XX[,1:4];

BETA=INV(X`*X)*X`*Y;

SIGMA=SQRT((Y-X*BETA)`*(Y-X*BETA)/(N-R));

SE=SIGMA*SQRT(VECDIAG(INV(X`*X)));

TVALUE=BETA/SE;

PVALUE=(1-PROBT(ABS(TVALUE),N-R))*2;

FINAL=BETA||SE||TVALUE||PVALUE;

print FINAL (|colname={ESTIMATE SE TVALUE PVALUE}

rowname={INTERCPT X1 X2 X3 X4} FORMAT=8.4|);

CREATE LAST FROM FINAL; *this creates a SAS data set from a matrix;

APPEND FROM FINAL;

PROC print DATA=LAST;

RUN;

PROC REG DATA=DRAPER;

MODEL Y=X1 X2 X3 X4;

RUN;

Alternative coding: could read in the matrices XX, Y, and X using:

READ ALL VAR{ Y } INTO Y;

READ ALL VAR{ X1 X2 X3 X4 } INTO XX;

X=ONE||XX;

Example: MLE for Weibull Parameters using IML

/* ------

Find the maximium likelihood estimate for the Weibull distribution using the Newton Raphson method.

SUPPOSE

beta

beta-1 - alpha * x

f(x) = alpha * beta * x * e for x > 0

beta

log[f(x)] = log(alpha) + log(beta) + (beta-1) log(x) – alpha * x

In order to somewhat conform with PROC LIFEREG we will let:

mu=-log(alpha), i.e.

log[f(x)] = -mu + log(beta) + (beta-1)log(x) – exp(-mu)*x^beta

Recall that in order to find the mle, one forms the log-likelihood, takes the derivative F(theta) = LL'(theta). To find the maximium, one needs to find when the function F(theta) equals 0. One then uses the second derivative to find the standard error. Newton's method is an iterative procedure to find when a function is equal to 0.

-1

theta(n+1) = theta(n) - F'(theta(n)) * F(theta(n))

here theta=(alpha,beta) is the vector of unknown parameters. (based on Deddens h.o. #23)

revised: 2/26/2003

comments and elaboration: 11/09/2003

------*/

DATA D1;

DO I=1 TO 500;

X=RANEXP(123456789)/10; ONE=1; *we generate some data;

OUTPUT;

END;

/* obtain estimates from LIFEREG */

PROCLIFEREG data=D1;

MODEL X=ONE/D=WEIBULL; RUN;

Parameter DF Estimate Error Limits Square Pr > ChiSq

Intercept 1 -2.3355 0.0494 -2.4322 -2.2388 2239.54 <.0001

ONE 0 0.0000 0.0000 0.0000 0.0000 . .

Scale 1 1.0474 0.0366 0.9781 1.1216

Weibull Shape 1 0.9547 0.0333 0.8916 1.0224

/* repeat parameter estimation using IML */

DATA D2; SET D1; KEEP X ;

PROCIML;

USE D2;

READ ALL INTO X;

X=X`;

LL1= { 1, 1 };

NN=NCOL(X);

* compute an initial estimate of theta;

THETA={ 0 , .1 };

* do at most 20 iterations or until the deriv(of LL) is quite small;

DO JJ=1 TO 20 UNTIL ( SUM(LL1) < .0001 );

MU=THETA[1,];

BETA=THETA[2,];

SUMIT=SHAPE(1,NN,1); * vector of 1s;

* compute the Log-Likelihood;

LL = (MU +LOG(BETA) +LOG(X)*(BETA-1) -EXP(MU)*(X##BETA)) * SUMIT;

* compute the derivative of the log-likelihood;

LL1 = ( ( 1 - EXP(MU)*(X##BETA) ) * SUMIT ) //

( ( (1/BETA) + LOG(X) - EXP(MU)*LOG(X)#(X##BETA) )* SUMIT );

* compute the matrix of second derivatives;

LL2 = ( ( - EXP(MU)*(X##BETA) ) *SUMIT ||

( -(EXP(MU)*LOG(X)#(X##BETA) ) *SUMIT ) ) //

( ( -(EXP(MU)*LOG(X)#(X##BETA) ) * SUMIT ) ||

( (-1/(BETA*BETA) -EXP(MU)*LOG(X)#LOG(X)#(X##BETA) ) *SUMIT ) );

* iterate to find the mle;

THETA=THETA - INV(LL2)*LL1;

* compute the estimates corresponding to PROC LIFEREG;

SIGMA=1/BETA; INTERCEPT=-MU*SIGMA;

* print standard errors using the second derivative;

SE=SQRT(-VECDIAG(INV(LL2))); ZVALUE=THETA/SE;

* print iteration history;

print JJ THETA SE ;

END;

* print the final estimates;

print JJ THETA SE ZVALUE INTERCEPT SIGMA;

JJ THETA SE

1 0.6000362 0.0530356

0.1972324 0.0044464

2 1.0112191 0.0490821

0.3726667 0.0085816

3 1.6117082 0.0578591

0.6303589 0.0154567

4 2.0731078 0.0678525

0.8612001 0.0240567

5 2.2180598 0.0746581

0.9469739 0.030719

6 2.2296905 0.077051

0.9546784 0.0331178

7 2.2297713 0.0772825

0.9547346 0.0333382

8 2.2297713 0.0772842

0.9547346 0.0333398

JJ THETA SE ZVALUE INTERCEPT SIGMA

8 2.2297713 0.0772842 28.851564 -2.335488 1.0474115

0.9547346 0.0333398 28.63646

Example: Poisson Regression using IML and GENMOD

/*

This is SAS MACRO which uses PROC IML to perform maximium likelihood estimation, using Newtons method to find the iterative solution (based on Deddens h.o. #26).

Incidence of nonmelanoma skin cancer among women in Minn./

St. Paul vs. women in Dallas/Ft. Worth;

Ref: Lunneborg (1994) ch. 19 problem 2;

Kleinbaum, Kupper and Muller Regression book as well

Input variables:

age = midpt of age categ. 15-24, 25-34, . . . 75-84, 85+

city = 0 (Minneapolis-St. Paul)

= 1 (Dallas-Ft. Worth)

Response variables:

Cases = # nonmelanoma skin cancers

PYRS = person years of exposure

Additional documentation added: 9 November 2003

*/

DATA KKM;

INPUT CITY AGE CASES PYRS @@;

LAGE=LOG((AGE-15)/35);

LPYRS=LOG(PYRS);

CARDS;

0 20 1 172675 1 20 4 181343

0 30 16 123065 1 30 38 146207

0 40 30 96216 1 40 119 121374

0 50 71 92051 1 50 221 111353

0 60 102 72159 1 60 259 83004

0 70 130 54722 1 70 310 55932

0 80 133 32185 1 80 226 29007

0 90 40 8328 1 90 65 7538

;

%MACRO POISSON(DATASET,COUNT,NUMBER,XVAR);

%* &count = response/count of the number of cases;

%* &number = person years of exposure;

%* &xvar = predictor variables;

PROC IML;

/* select response variables, predictors and offset */

USE &DATASET;

READ ALL VAR{&XVAR} INTO XX; NR=NROW(XX); NC=NCOL(XX); NV=NC+1;

READ ALL VAR{&COUNT} INTO Y;

READ ALL VAR{&NUMBER} INTO P;

/* initialize BETA vector and set up design matrix */

BETA=J(NV,1,0);

ONE=J(NR,1,1);

XX=ONE||XX;

DO ITER=1 TO 20 UNTIL (ADLL<.00001);

EB=EXP(XX*BETA); * estimated RATE;

PEB=P#EB; * predicted number of cases;

* = person-years X RATE;

LL=ONE`*(Y#LOG(PEB)-PEB);

LL0=ONE`*(Y#LOG(Y)-Y);

DLL=XX`*(-PEB+Y);

ADLL=MAX(ABS(DLL));

TWO=J(1,NV,1);

DDLL=-XX`*((PEB*TWO)#(XX));

BETA=BETA-INV(DDLL)*DLL; * update estimate;

BETAP=BETA`;

print BETAP (|FORMAT=8.4|) ITER ADLL (|FORMAT=12.4|);

DEV=2*(LL0-LL);

VAR=-INV(DDLL);

SE=SQRT(VECDIAG(VAR));

ZVALUE=BETA/SE;

LOWER=BETA-1.96*SE;

UPPER=BETA+1.96*SE;

CHISQ=ZVALUE##2;

PVALUE=2*PROBNORM(-ABS(ZVALUE));

END;

FINAL=BETA||SE||LOWER||UPPER||CHISQ||PVALUE;

print FINAL (|colname={ESTIMATE SE LOWER UPPER CHISQUARE PVALUE}

rowname={intercept &xvar} FORMAT=12.4|);

print ITER ;

print DEV (| FORMAT=12.4 |) LL (| FORMAT=12.4 |) LL0 (| FORMAT=12.4 |);

%MEND;

%POISSON(KKM,CASES,PYRS,CITY LAGE)

BETAP ITER ADLL

-0.9983 0.0009 0.0014 1 1385394.0000

-1.9937 0.0032 0.0053 2 509192.4582

-2.9814 0.0096 0.0157 3 186857.4228

-3.9485 0.0266 0.0437 4 68281.0472

-4.8631 0.0707 0.1167 5 24670.1512

-5.6579 0.1763 0.2958 6 8655.4209

-6.2430 0.3814 0.6737 7 2835.8993

-6.6197 0.6290 1.2675 8 930.6167

-6.8890 0.7648 1.8734 9 355.1142

-7.0416 0.7992 2.2156 10 107.8144

-7.0748 0.8030 2.2859 11 21.2470

-7.0760 0.8031 2.2883 12 0.7735

-7.0760 0.8031 2.2883 13 0.0009

-7.0760 0.8031 2.2883 14 0.0000

FINAL

ESTIMATE SE LOWER UPPER CHISQUARE PVALUE

INTERCEPT -7.0760 0.0476 -7.1694 -6.9826 22070.6964 0.0000

CITY 0.8031 0.0522 0.7008 0.9054 236.9187 0.0000

LAGE 2.2883 0.0627 2.1654 2.4112 1331.6379 0.0000

ITER