1
votes

I would like to take values that are calculated in IML to be used in SAS' printing functionality %PRNTINIT. This functionality is used to provide weekly reports from a database that can get updated.

I have some legacy code that uses proc sql to declare macro-type values that are called upon later, e.g.:

Declaring variables: tot1-tot4

*Get total number of subjects in each group in macro variable;
proc sort data = avg3; by description; run;
proc sql noprint;
select _freq_
into: tot1-:tot4
from avg3;
quit;

Calling variables tot1-tot4 for printing

%print(column = 1, style = bold, just = center, lines = bottom:none);
%print("(N= &tot1)", column = 2, just = center, lines = bottom:none);
%print("(N= &tot2)", column = 3, just = center, lines = bottom:none);
%print("(N= &tot3)", column = 4,  just = center, lines = bottom:none);
%print("(N= &tot4 )", column = 5,  just = center, lines = bottom:none);
%print(column = 6, just = center, lines = bottom:none);

I would like to be able to call values from IML similarly, if possible.


Example data:

data test ;
input age  type  gender $;
cards;
1 1 m
1 1 m
1 1 m
1 1 f
1 1 f
1 2 f
2 1 m
2 1 f
2 2 m
2 2 m
2 2 m
2 2 m
2 2 m
2 2 f
2 2 f
2 2 f
;




proc freq data = test;
tables type*age /  chisq norow nocol nopercent outexpect out=out1 ;
tables type*gender / chisq norow nocol nopercent outexpect out=out2 ;
run;


options missing=" ";

proc iml;

reset print; 

use out2;
read all var {count} into count;

type1 = count[1:2] ;
type2 = count[3:4] ;

tab = type1 || type2 ;

cols = tab[+,] ;
rows = tab[,+] ;
tot  = sum(tab) ;

perc = round(cols / tot, .01) ;

cell_perc = round(tab / (cols//cols) , .01) ;


expect = (rows * cols) / tot ;
chi_1 = sum((tab - expect)##2/expect) ;
p_chi_1 = 1-CDF('CHISQUARE',chi_1, ((ncol(tab)-1)*(nrow(tab)-1)));



print tab p_chi_1 perc cell_perc;



out_sex = tab || (. // p_chi_1);

print out_sex;

print out_sex[colname={"1","2"} 
              rowname={"f" "m" "p-value"}
              label="Table of Type by Gender"];




call symput(t1_sum, cols[1,1]) ;

%let t2_sum = put(cols[1,2]) ;
%let t1_per = perc[1,1] ;
%let t2_per = perc[1,2] ; 



%let t1_f = tab[1,1] ;
%let t1_m = tab[2,1] ;
%let t2_f = tab[1,2] ;
%let t2_m = tab[2,2] ;

%let t1_f_p = cell_perc[1,1] ;
%let t1_m_p = cell_perc[2,1] ;
%let t2_f_p = cell_perc[1,2] ;
%let t2_m_p = cell_perc[2,2] ;



%let p_val = p_chi_1 ;


*****  is it possible to list output values here for use in table building ???   ;
*  like:    %let t1_f = tab[1,1]
            %let t2_f = tab[2,1]   etc...  ;

quit;

So I would like to declare a print statement like the following:

%print( "(N=&tab[1,1], column = 1, just=center, lines = bottom:none);
%print( "(N=&tab[1,2], column = 2, just=center, lines = bottom:none);
etc...

Any help on this is greatly appreciated...


Update: Unable to extract declared macro values out of IML

I have been able to calculate the correct values and format the table successfully.

However, I am unable to extract the values for use in the print macro.

I have created some matrices and calculated values in IML, but when I try to declare macro variables for use later, the only thing that is returned is the literal value that I declared the variable to be... e.g.:

table with missing IML values

and

another table with missing IML values

You can see in the table what I want the numbers to be, but have thus far been unsuccessful. I have tried using %let, put, symput , and symputx without success.

call symput(t1_sum, cols[1,1]) ;

%let t2_sum = put(cols[1,2]) ;
%let t1_per = perc[1,1] ;
%let t2_per = perc[1,2] ; 



%let t1_f = tab[1,1] ;
%let t1_m = tab[2,1] ;
%let t2_f = tab[1,2] ;
%let t2_m = tab[2,2] ;

%let t1_f_p = cell_perc[1,1] ;
%let t1_m_p = cell_perc[2,1] ;
%let t2_f_p = cell_perc[1,2] ;
%let t2_m_p = cell_perc[2,2] ;

Blerg...

2
What exactly are you trying to accomplish here? %PRINT is not a built in macro in SAS, so you're using some custom macro (perhaps this one? informationsoftworks.com/sugi21 ; if that's the case, that paper was written in 1996 (!!) and is so out of date as to be irrelevant). Nowadays you'd use ODS to do what you're suggesting. What exactly does the output you're looking for need to look like - is this a text file, a PDF, an RTF/Word file, HTML?Joe
@Joe Agreed that this is very old technology, and the site you mention is the only place that I could find a reference to it. The object is to produce an RTF file that we can compile into a weekly report. However, all of the required tables are "sketched out" by the research team (kind of like Figure 5 on the site). So, we use the %print functionality to build the table as specified. It is quite tedious, but is stable. I am definitely open to other suggestions.blue and grey
I couldn't say anything in specific without actually seeing the 'sketch', but in general you should be able to come up with anything reasonable [or at least close enough for researchers to usually be okay] with a combination of ODS RTF and PROC REPORT or PRINT, or ODS TEXT, or PROC TEMPLATE and one of the FREQ/TABULATE/etc. procs. lexjansen.com/phuse/2005/ts/ts01.pdf is a good place to start - it has a good example of PROC TEMPLATE to get your colors and table formatting right, and a lot of the flexibility available. It should be a lot less tediuos, I'd think, once you learn it.Joe

2 Answers

0
votes

A SAS/IML matrix must be all numeric or all character, which is why your attempt did not work. However, the SAS/IML PRINT statement has several options that enable you to label columns and rows and to apply formats. See http://blogs.sas.com/content/iml/2011/08/01/options-for-printing-a-matrix/ Together with the global SAS OPTIONS statement, I think you can get the output that you want.

1) Use the global statement

options missing=" ";

to tell SAS to print missing values as blanks.

2) Your goal is to append a column to the 2x2 TAB matrix. You can use (numeric) missing values for the rows that have no data:

   out_age = tab || (. // p_chi_1);

3) You can now print this 2x3 table, and use the COLNAME= and ROWNAME= options to display row headings:

print out_age[rowname={"1","2"} 
              colname={"f" "m" "p-value"}
              label="Table of Type by Gender"];

If you really want to use your old-style macro, you can use the SYMPUTX statement to copy values from SAS/IML into macro variables, as shown in this article: http://blogs.sas.com/content/iml/2011/10/17/does-symput-work-in-iml/

0
votes

After much searching, and finding some help here on SO, I was able to piece the answer together.

  1. The output value has to be a string
  2. The name of the macro variable has to be in quotes
  3. The call has to be to symputx in order to trim extra whitespace (when compared to symput)

Code to extract IML values to macro variables

call symputx('t1_sum', char(cols[1,1])) ;
call symputx('t2_sum', char(cols[1,2])) ;

call symputx('t1_per', char(perc[1,1])) ;
call symputx('t2_per', char(perc[1,2])) ;

call symputx('t1_f' , char(tab[1,1])) ;
call symputx('t1_m' , char(tab[2,1])) ;
call symputx('t2_f' , char(tab[1,2])) ;
call symputx('t2_m' , char(tab[2,2])) ;

call symputx('t1_f_p' , char(cell_perc[1,1])) ;
call symputx('t1_m_p' , char(cell_perc[2,1])) ;
call symputx('t2_f_p' , char(cell_perc[1,2])) ;
call symputx('t2_m_p' , char(cell_perc[2,2])) ;

call symputx('p_val' , char(round(p_chi_1, .001))) ;

Partial code used to build table using old SAS %PRNTINIT macro

...
%print("Female",            column = 1,  just = center  );
%print("&t1_f (&t1_f_p)",   column = 2,  just = center  );
%print("&t2_f (&t2_f_p)",   column = 3,  just = center  );
%print(,                    column = 4,  just = center  );
%print(proc = newrow);

%print("Male",              column = 1,  just = center  );
%print("&t1_m (&t1_m_p)",   column = 2,  just = center  );
%print("&t2_m (&t2_m_p)",   column = 3,  just = center  );
%print("&p_val",            column = 4,  just = center  );
...

The desired result:

table detail with correct numbers

additional table detail with correct numbers