PDF macro in SAS - macros

I have written a macro which takes multiple datasets and the variables common with those datasets and generates a frequency table using proc freq, as follows:
%macro f(input= , vars= );
%let n_d=%sysfunc(countw(&input));
%do i = 1 %to &n_d;
%let dataset = %scan(&input, &i);
%let n=%sysfunc(countw(&vars));
%do j = 1 %to &n;
%let values = %scan(&vars, &j);
title "Frequency of &dataset and &values";
proc freq data = &dataset;
tables &values/nocum;
run;
%end;
%end;
%mend;
I work with UNIX SAS and my version of SAS doesn't have access to HTML output because of some network issues.
I want to create a pdf output and for each of the above frequency tables and store it either in a single pdf or in a multiple pdf's(not too particular on that). Please help!!

You can sandwich the code between ODS PDF file='' and ods pdf close. Where you place the code determines if you get a single or multiple files.
For example, to generate a single file, put it at the outmost loop:
%macro f(input= , vars= );
ods pdf file="myoutout.pdf" style=meadow;
%let n_d=%sysfunc(countw(&input));
%do i = 1 %to &n_d;
%let dataset = %scan(&input, &i);
%let n=%sysfunc(countw(&vars));
%do j = 1 %to &n;
%let values = %scan(&vars, &j);
title "Frequency of &dataset and &values";
proc freq data = &dataset;
tables &values/nocum;
run;
%end;
%end;
ods pdf close;
%mend;

Related

SAS: Merge two plots into one by group

I have two plots that I would like to merge into one. Each plot represents the proportion of present / not-present observations by their corresponding cumulative test results for the year
So on the plot I would like to see bars, side by side for groups of test scores but counting number of present to not-present
To represent this problem, this is what I have currently:
data test_scores;
do i = 1 to 200;
score = ranuni(200);
output;
end;
drop i;
run;
data test_scores_2;
set test_scores;
if _n_ le 100 then flag = 0;
else flag = 1;
run;
data test_scores_2_0 test_scores_2_1;
set test_scores_2;
if flag = 0 then output test_scores_2_0;
else if flag = 1 then output test_scores_2_1;
run;
PROC GCHART
DATA=test_scores_2_0
;
VBAR
score
/
CLIPREF
FRAME
LEVELS=20
TYPE=PCT
COUTLINE=BLACK
RAXIS=AXIS1
MAXIS=AXIS2
;
RUN;
QUIT;
PROC GCHART
DATA=test_scores_2_1
;
VBAR
score
/
CLIPREF
FRAME
LEVELS=20
TYPE=PCT
COUTLINE=BLACK
RAXIS=AXIS1
MAXIS=AXIS2
;
RUN;
QUIT;
bars should sum up to 100% for present
bars should sum up to 100% for non-present
TIA
proc sgplot to the rescue. Use the group= option to specify two separate groups. Set the transparency to 50% so one histogram does not cover the other.
proc sgplot data=test_scores_2;
histogram score / group=flag transparency=0.5 binwidth=.05;
run;
With Proc GCHART you can use VBAR options GROUP= and G100 to get bars that represent percent within group. This is useful when the groups have different counts.
The SUBGROUP= option splits the vertical bar according to the different values of the subgroup variable, and produces automatic coloration and legend corresponding to the subgroups.
When the SUBGROUP variable (or values) correspond 1:1 to the group the result is a chart with a different color for each group and a legend corresponding to the group.
For example, modify your data so group 1 has a 50 count and group 2 has 150 count:
data test_scores;
do _n_ = 1 to 200;
score = ranuni(200);
flag = _n_ > 50;
output;
end;
run;
axis1 label=("score");
axis2 ;
axis3 label=none value=none;
PROC GCHART data=test_scores;
VBAR score
/ levels=10
GROUP=flag G100
SUBGROUP=flag
SPACE=0 TYPE=PERCENT freq gaxis=axis3 maxis=axis1 ;
run;
Output
Similar chart showing the effect of a subgroup variable with values different than group values.
data test_scores;
do _n_ = 1 to 200;
subgroup = ceil(5 * ranuni(123)); * random 1 to 5;
score = ranuni(200);
flag = _n_ > 50;
output;
end;
run;
axis1 label=("score");
axis2 ;
axis3 label=none value=none;
PROC GCHART data=test_scores;
VBAR score
/ levels=10
GROUP=flag G100
SUBGROUP=subgroup /* has integer values in [1,5] */
SPACE=0 TYPE=PERCENT freq gaxis=axis3 maxis=axis1;
run;

How to use cycles in sas macro data step

I need to use cycles in a sas macro that writes a data step
I have a code that should work but it doesn't. How can i fix it?
%macro ci;
data
%do i=1 %to 3;
_z%sysfunc(putn(%eval(&i),z2.)) ;
%end;
;
set _06;
%do i=1 %to 3;
if num="%sysfunc(putn(%eval(&i),z2.))" then output _z%sysfunc(putn(%eval(&i),z2.));
%end;
run;
%mend;
%ci;
I'd like to get the following output:
data
_z01
_z02
_z03;
set _06 ;
if num="01" then output _z01;
if num="02" then output _z02;
if num="03" then output _z03;
run;
You are very close. You simply had an extra ; in your first loop.
You need to change:
data
%do i=1 %to 3;
_z%sysfunc(putn(%eval(&i),z2.)) ;
%end;
;
to:
data
%do i=1 %to 3;
_z%sysfunc(putn(%eval(&i),z2.))
%end;
;
Adding option mprint; to the beginning of your code would show you the code that was generated from your macro statement and helped you to debug it.
how about If you would use a simpler approach instead of using converting the number to character
data _06;
num='01';
output;
num='02';
output;
num='03';
output;
run;
%macro ci;
data
%do i=1 %to 3;
_z0&i
%end;
;
set _06;
%do i=1 %to 3;
if num="0&i" then output _z0&i;
%end;
run;
%mend;
%ci;

Error message 'unclosed %DO statement' for sas macro to compare two numeric values

I am using the macro below to compare two numeric values as part of an exercise.
options mlogic mprint;
%let price_trd = 93.68;
%put &price_trd.;
%let max_price = 100.94;
%put &max_price.;
%macro test;
%if &price_trd. < &max_price %then %do;
%if %sysevalf(&price_trd. LT &max_price) %then %do;
%put Pass HERE;
%end;
%mend;
%test;
I am getting the errors below:
There is one unclosed %DO statement.
The macro was not compiled.
Please let me know our advice to solve it. Thanks.
you did not state/instruct in your code what has to happen with first %if and %do condition and also did not close the %do with %end. try something like below.
%macro test;
%if &price_trd. < &max_price %then %do;
%put something HERE;
%end;
%if %sysevalf(&price_trd. > &max_price) %then %do;
%put Pass HERE;
%end;
%mend;
%test;

SAS: Write a macro...

I am having a question on SAS Macro (I do analytics in R and python, No SAS). SO, it is getting me into some lack of understanding in syntax of SAS in solving the following question.
Write a macro that accepts a table name, a column name, a list of integers, a main axis label and an x axis label. This function should scan over each element in the list of integers and produce a histogram for each integer value, setting the bin count to the element in the input list, and labeling main and x-axis with the specified parameters. You should label the y-axis to read Frequency, bins = and the number of bins.
Also I need to test macro with a data set, using bin numbers 12, 36, and 60. So, that I am able to call macro with something like
%plot_histograms(data, y, 12 36 60, main="Title", xlabel="x_label");
to plot three different histograms of the data set.
Hint: Assume 12 36 60 resolve to a single macro parameter and use %scan, macro definition can look something like
%macro plot_histograms(table_name, column_name, number_of_bins, main="Main", xlabel="X Label")
Thanks in Advance.
I don't fully understand your question and this is not a free code platform anyway but this should point you in the right direction
%macro plot_histograms(table_name, column_name, number_of_bins, main="Main", xlabel="X Label");
%do i=1 %to %sysfunc(countw(&number_of_bins.); /* loop accross elements in your input list */
proc gchart data=&table_name.; /*make a chart for the provided table */
...
/* whatever it is you actually need to do, fetch the current element of the input list like this */
%scan(&number_of_bins.,&i.)
...
run;
%end;
%mend;
First, you really should try this on your own and let us know where you get stuck.
That said, let's break down how to solve this problem.
Make some test data;
data test;
do i=1 to 10000;
r = rannor(1);
output;
end;
run;
How do I create a histogram with this? Use PROC SGPLOT
proc sgplot data=test;
histogram r / nbins=10;
xaxis label="X LABEL";
yaxis label="Y LABEL";
run;
Produces this:
So, if I make a macro to create this generally:
%macro histogram(data,column,bin,xlabel,ylabel);
proc sgplot data=&data;
histogram &column / nbins=&bin;
xaxis label="&xlabel";
yaxis label="&ylabel";
run;
%mend;
Now %histogram(test,r,10,X LABEL,Y LABEL)' produces the same image.
Let's write something that loops over the values of bins and call this macro:
%macro make_histograms(data,column,bins,xlabel,ylabel);
%local i n bin;
%let n=%sysfunc(countw(&bins)); /*Number of words in &bins*/
%do i=1 %to &n;
%let bin=%scan(&bins,&i); /*Get the nth bin*/
%histogram(&data,&column,&bin,&xlabel,&ylabel);
%end;
%mend;

Logistic regression Macro

%macro intercept(i1= ,i2= );
%let n = %sysfunc(countw(&i1));
%do i = 1 %to &n;
%let val_i1 = %scan(&i1,&i,'');
%let val_i2 = %scan(&i2,&i,'');
data scores;
set repeat_score2;
/* Segment 1 probablity score */
p1 = 0;
z1 = &val_i1 +
a * 0.03 +
r * -0.0047841 +
p * -0.000916081 ;
p1 = 1/(1+2.71828**-z1);
/* Segment 2 probablity score */
p2 = 0;
z2 = &val_i2 +
r * 0.09 +
m * 0.012786245 +
c * -0.00179618 +
p2 = 1/(1+2.71828**-z2);
logit_score = 0;
if max(p1,p2) = p1 then logit_score = 1;
else if max(p1,p2) = p2 then logit_score = 2;
run;
proc freq data = scores;
table logit_score * clu_ /nocol norow nopercent;
run;
%end;
%mend;
%intercept (i1=-0.456491042, i2=-3.207379842, i3=-1.380627318 , i4=0.035684096, i5=-0.855283373);
%intercept (i1=-0.456491042 0, i2=-3.207379842 -3.207379842, i3=-1.380627318 -1.380627318, i4=0.035684096 0.035684096,
i5=-0.855283373 -0.855283373);
I have the above macro which takes the intercept for the two of the above models and then calculates the probablity score and then assigns a a value to to a segment based on that probablity score.
The first problem with above macro is when I execute the macro with one argument each it's resolving macro variable 'n' to 2 and executing twice. First iteration, it's giving the right results while for second it's wrong.
For the second implementation(macro with two aruguments each) n is resolving to 3 and scan is resolving to both of those values together at a time (eg. i1 for the iteration itself is -0.45 and 0), If I remove the space, then it taking '.' to be the delimiter and resolving that to ( 0,45,0 - one for each iteration). I don't get any results for this case.
How do I get this to work the right way?
Thanks!!!
%SCAN and COUNTW function by default consider punctuation symbols and blanks as delimiters. Since your arguments include decimal points, you need to state explicitly that delimiter should be blank for both COUNTW and %SCAN. Which you have done for %SCAN, but not for COUNTW.
So the 2nd line of the code should be:
%let n = %sysfunc(countw(&i1,' '))
And I'm not sure if it's a typo or just formatting thing, but in your %SCAN functions third argument looks like two quotes together '', not quote-blank-quote ' ' as it should be.