I have created a numeric variable using the Prompt Manager in EG.
This variable is called HYr for the highest year of data that I am pulling.
When running the program I create 4 new variables based on the highest year and this is where I am having issues.
I have the following:
%Let Yr2 = &HYr. - 1;
%Let Yr3 = "&HYr." - 2;
%Let Yr4 = &HYr. - 3;
%Let Yr5 = '&HYr.' - 4;
I am trying to subtract the value from the year and the new variable will be used in determining date ranges that are being pulled. I am trying several things and learning in the process but I am still stuck.
I know it is probably just a simple syntax issue and given enough time I will probably be able to get it but no one in my office has any better SAS skills than I do and that isn't much.
thanks in advance.
Use %EVAL() to do calculations with integers and macro variables.
%let HYR = 2018;
%Let Yr2 = %eval(&HYr. - 1);
%Let Yr5 = %eval(&HYr. - 4);
%put HYR: &hyr;
%put YR2: &yr2.;
%put YR5: &yr5.;
EDIT: If you were trying to do other calculations that included decimals you would need to use %SYSEVALF instead.
%let HYR = 2018;
%Let Yr2 = %sysevalf(&HYr. - 0.1);
%Let Yr5 = %sysevalf(&HYr. - 0.4);
%put HYR: &hyr;
%put YR2: &yr2.;
%put YR5: &yr5.;
Related
I am working on a macro for regressions using the following code:
%Macro Regression;
%let index = 1;
%do %until (%Scan(&Var2,&index," ")=);
%let Ind = %Scan(&Var2,&index," ");
ods output SelectionSummary = SelectionSummary;
proc reg data = Regression2 plots = none;
model &Ind = &var / selection = stepwise maxstep=1;
output out = summary R = RSQUARE;
run;
quit;
%if &index = 1 %then %do;
data final;
set selectionsummary;
run;
%end;
%else %do;
data final;
set final selectionsummary;
run;
%end;
%let index = %eval(&Index + 1);
%end;
%mend;
%Regression;
This code works and gives me a table which highlights the independent variable that explains with the most variation the dependent variable.
I'm looking for a way to run this but the regression gives me the three best independent variables to explain the dependent variable if it was chosen to be the first variable, for example:
models chosen:
GDP = Human Capital
GDP = Working Capital
GDP = Growth
DependentVar Ind1 Ind2 Ind3 Rsq1 Rsq2 Rsq3
GDP human capital working capital growth 0.76 0.75 0.69
or
DependentVar Independent1 Rsq
GDP human capital 0.76
GDP working capital 0.75
GDP growth 0.69
EDIT:
It would be an absolute bonus if there is a way to put stepwise maxstep = 3 and have the best three independent variable combinations for each dependent variable with the condition that the first independent variable is unique.
TIA.
Try STOP=3 option on your model statement. It will fit the best model with up to three variables. However, it does not work with the stepwise option, but will work with the R^squared option.
model &Ind = &var / selection = maxR stop=3;
If you only want to consider 3 variable models include start=3 as well.
model &Ind = &var / selection = maxR stop=3 start=3;
I have two macro variables value.
a=20150501
b=20160530
I want to create a new macro variable that will display the number of months between a and b.
Same logic as Allan's response but using a data step to simplify the code...
%let a = 20150501;
%let b = 20160530;
data _null_;
a = input(put("&a", 8.), yymmdd8.);
b = input(put("&b", 8.), yymmdd8.);
diff = intck("month", a, b);
call symputx("diff", put(diff, best.));
run;
%put &diff;
12
See documentation for intck for alternative ways to calculate the difference in months.
You can use the INTCK function for that - see documentation
%let a=20150501;
%let b=20160530;
/**
* first - convert to date values
* (DATE_A=01MAY2015 DATE_B=30MAY2016)
*/
%let date_a=%sysfunc(putn(%sysfunc(
INPUTN(%sysfunc(PUTN(&a, Z8.)), YYMMDD8.)
), date9.));
%let date_b=%sysfunc(putn(%sysfunc(
INPUTN(%sysfunc(PUTN(&b, Z8.)), YYMMDD8.)
), date9.));
%put &=date_a &=date_b;
/**
* Now calculate difference using INTCK
* (DIFF=12)
*/
%let diff=%sysfunc(intck(MONTH,"&date_a"d,"&date_b"d));
%put &=diff;
You can use the intck() function to get the number of months difference.
If you are performing a calculation such as age, or tenure, then be sure to use the 'continuous' parameter of intck().
If you simply need to know that there is 1 month difference between the 31-May and the 01-Jun, then use the 'discrete' (default) parameter.
%let a=20150531;
%let b=20150601;
* CONVERT TO SAS DATES;
%let date1 = %sysfunc(inputn(&a,yymmdd8.));
%let date2 = %sysfunc(inputn(&b,yymmdd8.));
* CALCULATE # DISCRETE MONTHS DIFFERENCE;
%let discrete_months = %sysfunc(intck(month, &date1, &date2, d));
%put &=discrete_months;
* CALCULATE # CONTINUOUS MONTHS DIFFERENCE;;
%let cont_months = %sysfunc(intck(month, &date1, &date2, c));
%put &=cont_months;
Output:
DISCRETE_MONTHS=1
CONT_MONTHS=0
I have a variable date=201611 and I need to create the first day of the next month in the following format '2016-12-01'. The following code works fine for the months up till 11:
%let date = 201611;
%let rok = %sysfunc(substr(&date,1,4));
%let month = %sysfunc(substr(&date,5,2));
%let xdat2_ii = &rok-%eval(&month + 1)-01;
%let xdat1 = %str(%')&xdat2_ii.%str(%');
%put &xdat1;
'2016-12-01'
I need to add some improvement to make the code working for the month 12, i.e. when the date is 201612 then to obtain '2017-01-01'.
My idea was to do it using macro, but it does not work.
%macro promenne;
%if &month < 12 %then %let xdat2_ii = &rok-%eval(&month + 1)-01
%else %if &month= 12 %then %let xdat2_ii = %eval(&rok + 1)-01-01;
%mend promenne;
Thank you for any suggestions which way to go.
When working with dates, is often easiest to use the built in date shifting functions - in this case, intnx.
/* define variable (this is a macro STRING) */
%let date=201612;
/* convert to SAS date value (numeric, num of days since 01JAN1960) */
%let dateval=%sysfunc(mdy(%substr(&date,5,2),1,%substr(&date,1,4)));
/* finally - shift to beginning of following month and format output */
%let xdat2_ii=%sysfunc(intnx(MONTH,&dateval,1,B),yymmddd10.);
%put &xdat2_ii; /* 2017-01-01 */
I have the following variables: A_Bldg B_Bldg C_Bldg D_Bldg. I want to multiply them by INTSF and store the result in a new variable, Sale_i. For example, A_Bldg * INTSF = Sale_A, B_Bldg * INTSF = Sale_B, and so on.
My code is:
%macro loopit(mylist);
%let n=%sysfunc(countw(&mylist));
%do J = 1 %to &n;
%let i = %scan(&mylist,&J);
data test;
set data;
sale_&i. = &i._Bldg * INTSF;
run;
%end;
%mend;
%let list = A B C D;
%loopit(&list);
This only produces Sale_D, which is the last letter in the list. How do I get Sales A-C to appear? The first four lines of code are so I can loop through the text A-D. I thought about doing it with arrays, but didn't know how to choose the variables based on the A-D indicators. Thanks for your help!
You're currently looping through your list and recreating the test dataset every time, so it only appears to have sale_d because you're only viewing the last iteration.
You can clean up your loop by scanning through your list in one data step to solve your problem:
%let list = A B C D;
%macro loopit;
data test;
set data;
%do i = 1 %to %sysfunc(countw(&list.));
%let this_letter = %scan(&list., &i.);
sale_&this_letter. = &this_letter._Bldg * INTSF;
%end;
run;
%mend loopit;
%loopit;
Your %DO loop is in the wrong place. But really you do not need to use macro code to do something that the native SAS code can already do.
data want;
set have ;
array in A_Bldg B_Bldg C_Bldg D_Bldg ;
array out sale_1-sale4 ;
do i=1 to dim(in);
out(i)=intsf*in(i);
end;
run;
SAS is interpreting in_year_tolerance and abs_cost as text vars in the below if statement. Therefore the if statement is testing the alphabetical order of the vars rather than the numerical order. How do I get SAS to treat them as numbers? I have tried sticking the if condition, and the macro vars, in %sysevalf but that made no difference. in_year_tolerance is 10,000,000 and cost can vary, but in the test run starts around 20,000,000 before dropping to 9,000,000 at which point it should exit the loop but doesn't.
%macro set_downward_caps(year, in_year_tolerance, large, small, start, end, increment);
%do c = &start. %to &end. %by &increment.;
%let nominal_down_large_&year. = %sysevalf(&large. + (&c. / 1000));
%let nominal_down_small_&year. = %sysevalf(&small. + (&c. / 100));
%let real_down_large_&year. = %sysevalf((1 - &&nominal_down_large_&year.) * &&rpi&year.);
%let real_down_small_&year. = %sysevalf((1 - &&nominal_down_small_&year.) * &&rpi&year.);
%rates(&year.);
proc means data = output.s_&scenario. noprint nway;
var transbill&year.;
output out = temporary (drop = _type_ _freq_) sum=cost;
run;
data _null_;
set temporary;
call symputx('cost', put(cost,best32.));
run;
data temp;
length scenario $ 30;
scenario = "&scenario.";
large = &&real_down_large_&year.;
small = &&real_down_small_&year.;
cost = &cost.;
run;
data output.summary_of_caps;
set output.summary_of_caps temp;
run;
%let abs_cost = %sysevalf(%sysfunc(abs(&cost)));
%if &in_year_tolerance. > &abs_cost. %then %return;
%end;
%mend set_downward_caps;
Use %sysevalf(&in_year_tolerance > &abs_cost,boolean).
As you have seen, compares are text based. If you put it in an %eval() or %sysevalf() the values will be interpreted as numbers.
The ,boolean option lets it know you want a TRUE/FALSE.