*
;
              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 */

*
;