/*** TIP 00405 ***/
 /*** this libname used for demo purposes ***/
 **** libname  mylib    'c:\download\sas_salary\';

 /**************************************************************************/
 /*** _deciles_.sas                                                      ***/
 /***                                                                    ***/
 /***   Author: Charles Patridge                                         ***/
 /***   Date: November 30, 2004                                          ***/
 /***                                                                    ***/
 /***   Macro to calculate deciles of a list of sas variables from a     ***/
 /***   single sas dataset, and merge all of the deciles onto a single   ***/
 /***   record into an output sas dataset.                               ***/
 /***                                                                    ***/
 /***   1st parameter = name of sas dataset to create deciles from       ***/
 /***                   ie: mylib.mydataset                              ***/
 /***                                                                    ***/
 /***   2nd parameter = list of sas variables to use to make deciles     ***/
 /***                   each sas variable needs to be separated by a     ***/
 /***                   blank                                            ***/
 /***                   medage medincome weight height                   ***/
 /***                                                                    ***/
 /***                   no sas variable name can be longer than 29 pos.  ***/
 /***                                                                    ***/
 /***    !!!!!!!!!!!!!  sas variables are not checked for misspellings   ***/
 /***                   or if they exist                                 ***/
 /***                                                                    ***/
 /***   3rd parameter = name of sas output dataset to store deciles      ***/
 /***                   mylib.mydeciles                                  ***/
 /***                                                                    ***/
 /***                                                                    ***/
 /***   4th parameter = name of sas variable for weighting deciles,      ***/
 /***                   leave blank is none needed                       ***/
 /***                                                                    ***/
 /***   5th parameter = print or noprint - output Univariate Results     ***/
 /***                                                                    ***/
 /**************************************************************************/


 %macro _deciles_ ( _sasdsnin_=, _class_=, _sasvars_=, _sasdsnout_=, _sasweight_=, _print_=noprint);
   %let _print_ = %upcase( &_print_);
   %if &_print_ ne NOPRINT %then %let _print_ = ;

   /*** get number of sas variables being deciled ***/
   %let numwords = %eval(1 + %length(%cmpres(&_sasvars_)) -
                             %length(%sysfunc(compress(&_sasvars_)));

   %put "Number of SAS Variables being deciled = &numwords";

   /*** check to see if _sasweight_ is empty - blank ***/
   %if "&_sasweight_.dummy" = "dummy" %then %let _sasweight_ = _dummy_;

   %do i = 1 %to &numwords;
   /*** loop through list of sas variables to create deciles for each one ***/
    %let _stat_ = %scan( &_sasvars_, &i);
     proc univariate data=&_sasdsnin_ &_print_ ;
	  %if "&_class_" ne '' %then %do;
       class &_class_;
      %end; 
      var &_stat_;

      %if &_sasweight_ ne _dummy_ %then %do;
      /*** apply a weighting factor if requested ***/
         freq &_sasweight_;
      %end;

      output out=&_stat_ pctlpts=10 to 100 by 10 pctlpre=&_stat_;
     run;
     
	 /*** print the actual deciles for review ***/
	 proc print data=&_stat_ label; 
	 run;
   %end;

 /*** now merge all deciles onto a single record ***/
 data &_sasdsnout_;
  merge &_sasvars_;
 run;

%if ".&_class_" ne "." %then %do;
 proc sort data=&_sasdsnin_ out=_tempsort_; by &_class_; run;

 /*** join deciles with input sas dataset ***/
 data &_sasdsnout_;
  merge _tempsort_ 
        &_sasdsnout_;
  by &_class_;
%end;

%if ".&_class_" eq "." %then %do;
 data &_sasdsnout_;
  /*** join deciles with input sas dataset ***/
  if _n_ = 1 then set &_sasdsnout_; set &_sasdsnin_;
%end;

  %do i = 1 %to &numwords;
    %let _stat_ = %scan( &_sasvars_, &i);

    /*** create decile number for decile by attaching bin to sas variable name ***/
    if &_stat_ le &_stat_.100 then &_stat_.bin = 10;
    if &_stat_ le &_stat_.90  then &_stat_.bin = 9 ;
    if &_stat_ le &_stat_.80  then &_stat_.bin = 8 ;
    if &_stat_ le &_stat_.70  then &_stat_.bin = 7 ;
    if &_stat_ le &_stat_.60  then &_stat_.bin = 6 ;
    if &_stat_ le &_stat_.50  then &_stat_.bin = 5 ;
    if &_stat_ le &_stat_.40  then &_stat_.bin = 4 ;
    if &_stat_ le &_stat_.30  then &_stat_.bin = 3 ;
    if &_stat_ le &_stat_.20  then &_stat_.bin = 2 ;
    if &_stat_ le &_stat_.10  then &_stat_.bin = 1 ;

    /*** drop stat variables - no longer needed ***/
    drop
    &_stat_.10 &_stat_.20 &_stat_.30 &_stat_.40 &_stat_.50
    &_stat_.60 &_stat_.70 &_stat_.80 &_stat_.90 &_stat_.100;
  %end;
 run;

 /*** delete the temporary sas datasets ***/
 /*** proc datasets library=work nolist; delete &_sasvars_  _tempsort_; quit; ***/

 %mend _deciles_;


/*** example call to _deciles_ ***/
/***
 %let mystatvars = salary   hrlyrate   billrate ;
 
 *** %_deciles_( _sasdsnin_  = mylib.sasalary,
                 _class_     = group_state,
                 _sasvars_   = &mystatvars,
                 _sasdsnout_ = accumulate,
                 _sasweight_ = ,
                 _print_     = print
               );
***/
/*** end of _deciles_.sas ***/

/*** another similar tip - except this will divide the SAS Dataset into evenly divided 
Bins by record count and dump the remaining records into the LAST Bin Group 

This will sort the incoming Dataset and attach a new variable to the file ***/



%macro my_bin( _sasdsnin_=, _rankvar_=, _bingrp_=10, fmt_file=);
proc sort data=&_sasdsnin_ out=&_sasdsnin_; by &_rankvar_; run;

DATA _NULL_;
   IF 0 THEN SET &_sasdsnin_ NOBS=NUMOBS;
   CALL SYMPUT('_NUMOBS_' ,PUT(NUMOBS , BEST.));
   STOP;
RUN;

data _bingrp_ (keep=_low_ _high_ _value_);
 group = floor( &_numobs_ / &_bingrp_ );
 _group_ = 0;
 do i = 1 to &_bingrp_;
    _value_ = i;
    _low_   = _group_ + 1;
    _group_ = group * i;
	 _high_ = _group_;
	if i = &_bingrp_ then _high_ = &_numobs_;
	output;
 end;
run;

data creatFmt;
 set _bingrp_ end=eof;
 file &fmt_file;
 if _n_ = 1 then do;
  put "Proc Format; Value BinGrp ";
 end;
  put _low_ '-' _high_ " = " _value_;
 if eof then put ";";
run;

%include &fmt_file;

data &_sasdsnin_;
 set &_sasdsnin_;
 &_rankVar_._rank = input( put( _n_, BinGrp.), best.);
run;

proc datasets library=work nolist; delete _bingrp_ creatFmt; quit;
%mend my_bin;
/*** example call to macro 
%my_bin( _sasdsnin_=claim_level, _rankvar_=sum_amt, _bingrp_=10, fmt_file="C:\downloads\_bingrp_.sas");
***/

/*** end of tip 00405 ***/