Thank you, PGStats and Rick_SAS! I took what you had and made some additional changes. Since the SAS MONTH function returns the numbers 1 through 12 rather than 0 through 11, and the WEEKDAY function returns the numbers 1 through 7 rather than 0 through 6, I took the liberty of detecting a cycleLength of either 7 or 12 and subtracting 1 accordingly (and adding it back in to the result).
options cmplib=_null_;
/* Circular mean. Returns a value between -cycleLength/2 and +cycleLength/2 */
proc fcmp outlib=sasuser.fcmp.test;
function cmean (cycleLength,x[*]) varargs;
if cycleLength in(7,12) then s = 1;
else s = 0;
factor = 2 * constant("PI") / cycleLength;
cosTot = 0;
sinTot = 0;
n = 0;
do i = 1 to dim(x);
if not missing(x{i}) then do;
cosTot = cosTot + cos(factor*(x[i]-s));
sinTot = sinTot + sin(factor*(x[i]-s));
n = n + 1;
end;
end;
if n = 0 or (fuzz(sinTot) = 0 and fuzz(cosTot) = 0) then return(.);
else do;
rslt = atan2(sinTot/n,cosTot/n)/factor + s;
if rslt < 0 then rslt = rslt + cycleLength;
if rslt >= cycleLength then rslt = rslt - cycleLength;
return(rslt);
end;
endsub;
run;
options cmplib=sasuser.fcmp;
data cmeans;
array x{4}; /* Argument list must be an array */
call missing(of x{*});
x1 = 100;
x2 = 270;
cmean = cmean(360,x);
output;
call missing(of x{*});
x1 = 1.5707963265;
x2 = 3.1415926536;
cmean = cmean(2*constant("pi"),x);
output;
call missing(of x{*});
x1 = 1;
x2 = 3;
cmean = cmean(7,x); /* <-- days of the week, function subtracts 1 from all x before calculating */
output;
call missing(of x{*});
x1 = 5;
x2 = 7;
cmean = cmean(12,x); /* <-- months of the year, function subtracts 1 from all x before calculating */
output;
run;
proc print data=cmeans;
title 'cmeans';
run;
Also, keep in mind that the array you are passing to PROC FCMP has to be called x (x1, x2, ...). The way I handled passing arrays not called x is shown in the following code snippet:
%let ae = 300; /* number of array elements */
.
.
.
array om{&ae} om1-om&ae; array od{&ae} od1-od&ae; array x{&ae} _temporary_; . . . call missing(of x{*}); do i = 1 to dim(om); x{i} = om{i}; end; mean_order_month = cmean(12,x); call missing(of x{*}); do i = 1 to dim(od); x{i} = od{i}; end; mean_order_dow = cmean(7,x);
Many thanks!
Dave
... View more