***************************************************** * * * Truncate Macro * * Capable to truncate defined top * * and/or bottom percentages, * * and truncate within by variable groups * * Created by Allen Huang * * Last updated: 9/11/2018 * * * *****************************************************; /* Example : %truncate( var = airasm airfcg, by_var = , left = 10, right = 95, input = airlines_ann, output = airlines_ann_after); Explanation of the input parameter: var = variables to truncate by_var = by variables, truncate is done within each group of by variable left = left truncate percentage, e.g., 1 is bottom 1% right = right truncate percentage, e.g., 99 is top 99% input = input dataset output = output dataset */ %MACRO truncate(var, by_var, left, right, input, output); * Read in variables to truncate; %LET var_number = 1; %LET var&var_number = %QSCAN(&var, &var_number, %STR( )); %DO %WHILE (&&var&var_number NE); %LET var_number = %EVAL(&var_number + 1); %LET var&var_number = %QSCAN(&var, &var_number, %STR( )); %END; %LET var_number = %EVAL(&var_number - 1); * check if both left and right percentile are missing; %IF &left = AND &right = %THEN %DO; %PUT ERROR: Both top and bottom percentiles to truncate are missing, no truncate is needed!!!; %GOTO exit; %END; * set by variable to a dummy if it is missing, to help with merging afterward; %IF &by_var = %THEN %DO; %LET by_var = just_for_merge; DATA &output; SET &input; just_for_merge = 1; RUN; %END; %ELSE %DO; DATA &output; SET &input; RUN; %END; PROC SORT data = &output; BY &by_var; RUN; * determine value at the cut-off percentile; PROC UNIVARIATE DATA = &output NOPRINT; BY &by_var; VAR %DO i = 1 %TO &var_number; &&var&i %END;; OUTPUT OUT = truncated PCTLPTS = %IF &left ^= %THEN %DO; &left %END; %IF &right ^= %THEN %DO; &right %END; PCTLPRE = %DO i=1 %TO &var_number; var_&i %END; PCTLNAME = %IF &left ^= %THEN %DO; _pct_&left %END; %IF &right ^= %THEN %DO; _pct_&right %END;; RUN; * merge the cut-off percentile back to original database and truncate variables; DATA &output; MERGE &output truncated; BY &by_var; %DO i=1 %TO &var_number; IF &&var&i ^= . THEN DO; %IF &left ^= %THEN %DO; IF &&var&i < var_&i._pct_&left THEN &&var&i = .; DROP var_&i._pct_&left; %END; %IF &right ^= %THEN %DO; IF &&var&i > var_&i._pct_&right THEN &&var&i = .; DROP var_&i._pct_&right; %END; END; %END; %IF &by_var = just_for_merge %THEN DROP just_for_merge;; RUN; %exit: %MEND truncate;