*
; options nosource; /* NEAREST2 - CALCULATES MIN, MAX, MEAN DISTANCES TO FUNCTION-VALUES, WHERE THE DISTANCE CAN BE SUM OF SQUARE OR ROOT OF SUM OF SQUARE TO A GIVEN POINT OR TO PREVIOUS (LAGGED) VALUE. Written: June 20, 1995 Developed using SAS 6.10 for Windows Runable: SAS 6.09 under AIX Unix, SAS 6.08 for Windows, SAS 6.04 under DOS, SAS 6.10, SAS 6.11, SAS 6.12 Author: Arnold Schick Procs: PROC RANK, SORT and DATASETS Other: SAS MACRO language Macros: only NEAREST2 Note: Do not use _TEMP_ as a data set name. Please don't call %NEAREST2; or %NEAREST2(); Macro Call: %NEAREST2(DATA,N,RESULT,X,Y,SQRT,TO_X,TO_Y); MACRO VARIABLE DESCRIPTION ------------------+------------------------------------------------- In Request: DATA Name of SAS data set with input data. If this parameter is missing or blank _LAST_ is used. N Number of nearest and remotest function-values. If blank or missing N is set to 1. RESULT Name of SAS data set created by this macro. If missing or blank stops the %macro. Three new variables are created: DISTANCE, RANK_DIS, and ORDER DISTANCE assumed the calculated distance or square distance RANK_DIS assumed the rank of DISTANCE. ORDER assumed the ordernumber of funtion-values from input data set DATA. X Variablename of (independent) variable in input SAS data set DATA. If missing or blank, X is used. Y Variablename of (dependent) variable in input SAS data set DATA. If missing or blank, Y is used. SQRT Name of option for sort of distance. SQRT or JOIN join-distance to the previous function-value, calculated as: d = sqrt(Xi-Xi-1)**2 + (Yi-Yi-1)). If otherwise specified, sum of square in X-,Y-directions: d = (Xi-Xi-1)**2 + (Yi-Yi-1)**2 is used, where Xi-1,Yi-1 is fix given or are lagged values. TO_X Value of fix point to which are the distances calculated, if missing or blank, this point is the previous (lagged) value from variable X in input data set DATA. TO_Y Value of fix point to which are the distances calculated, if missing or blank, this point is the previous (lagged) value from variable Y in input data set DATA. Example: data one; do x=-1 to 8*atan(1) by atan(1)/64; y=sin(x); output; end; run; *%macro nearest2(data,n,result,x,y,sqrt,to_x, to_y); %nearest2( one,.,two, x,y,sqrt, 0 , 0.0125); proc print data=two; run; For more information: Arnold Schick University of Marburg Academic Computing Center Hans-Meerwein-Str. 35032 Marburg/Lahn Germany Internet: schick@hrz.uni-marburg.de If you find an error-condition (it is provided 'as it is') please let me know about this error-condition. And when you have good tips for better formulation in SAS, let it also know. */ options nosource; %macro nearest2(data,n,result,x,y,sqrt,to_x,to_y); options nosource nostimer nosymbolgen nonotes nomprint; %if &data = or &data = . %then %let data = _LAST_ ; %if &n = or &n = . %then %let n = 1; %if &result = or &result = . %then %goto quit_1; %if &x = or &x = . %then %let x = x; %if &y = or &y = . %then %let y = y; %if &to_x = or &to_x = . %then %let to_x =.; %if &to_y = or &to_y = . %then %let to_y =.; %if &sqrt = or &sqrt = . or %upcase(&sqrt) = %upcase(sqrt) or %upcase(&sqrt) = %upcase(join) %then %let sqrt = SQRT; %else %let sqrt = square; %local empty; data _NULL_ ; if 0 then set &data nobs=last; call symput('empty',last); stop; run; %if &empty < 2 %then %goto quit_2; %if %upcase(&sqrt) = %str(SQRT) %then %do; data _temp_; set &data end=last; retain sum 0 ; drop sum mean_d; order = _N_; if &x=. or &y=. then delete; if &to_x ^=. or &to_y ^=. then distance = sqrt((&to_x-&x)**2 + (&to_y-&y)**2); else do; distance = sqrt(dif(&x)**2 + dif(&y)**2); if order=1 then delete; end; sum+distance; if last then do; if &to_x=. or &to_y=. then mean_d = sum/(order-1); else mean_d = sum/order; call symput('mean',mean_d); call symput('var_x', '&x'); call symput('var_y', '&y'); end; run; %end; %else %do; data _temp_; set &data end=last; retain sum 0 ; drop sum mean_d; order = _N_; if &x=. or &y=. then delete; if &to_x ^=. or &to_y ^=. then distance = (&to_x-&x)**2 + (&to_y-&y)**2; else do; distance = dif(&x)**2 + dif(&y)**2; if order=1 then delete; end; sum+distance; if last then do; if &to_x=. or &to_y=. then mean_d = sum/(order-1); else mean_d = sum/order; call symput('mean',mean_d); call symput('var_x', '&x'); call symput('var_y', '&y'); end; run; %end; proc rank data=_temp_ out=&result; var distance; ranks rank_dis; run; proc datasets nolist; delete _temp_ ; quit; proc sort data=&result out=&result; by rank_dis; run; options notes; data &result; set &result nobs=obs; mean_dis = &mean; to_&var_x = &to_x; to_&var_y = &to_y; if _N_ < &n+1 or fuzz(distance) = fuzz(&mean) or _N_ > obs-&n; run; options nonotes; %goto final ; %quit_1 : %put MACRO-HALT: Please define result data set. ; %goto final; %quit_2 : %put MACRO-HALT: Number of observations in input data set less than 2 or; %put input data set &data is empty. ; %final : ; options source stimer notes; %mend nearest2; options source; /* Example Section */ data one; do x=-1 to 1 by 0.001; y= sin(x/cos(x)); if x=0.1 then y=.; output; end; run; *%macro nearest2 (data,n,result,x,y,sqrt, to_x, to_y); %nearest2 (one ,2,result, , ,nosqrt); proc print data=result; run; %nearest2 (one ,2,result, , ,nosqrt, 0 , 0.0125); proc print data=result; run; %nearest2 (one ,9999,result,,,nosqrt, 0, 0.0125); proc sort data=result out=result; by order; run; title 'input function'; proc gplot data=result; symbol i=join r=123 ; plot y * x / nolegend; run; title 'distance to point x=0 and y=0.0125'; proc gplot data=result; symbol i=join r=123 ; plot distance * x / nolegend; run; %nearest2 (one ,9999,result,,,sqrt); proc sort data=result out=result; by order; run; title 'distance to lagged input function-value'; proc gplot data=result; symbol i=join r=123 ; plot (distance) * x / nolegend; run; title; /* End of Example Section */ *;