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