<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: SAS Function to Calculate Circular Mean in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/323083#M71565</link>
    <description>&lt;P&gt;This should be close...&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;options cmplib=sasuser.fcmp;

/* Circular mean. Returns a value between -cycleLength/2 and +cycleLength/2 */ 
proc fcmp outlib=sasuser.fcmp.test; function cmean (cycleLength, x[*]) varargs;
    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]);
            sinTot = sinTot + sin(factor*x[i]);
            n = n + 1;
            end;
        end;
    if n &amp;gt; 0 and fuzz(sinTot) ne 0 then return(atan2(sinTot/n, cosTot/n)/factor);
    else return (.);
endsub;
run;

data _null_;
array x{2}; /* Argument list must be an array */
x1 = 100;
x2 = 270;
mean = cmean(360, x);
   put mean=;
run;
&lt;/CODE&gt;&lt;/PRE&gt;</description>
    <pubDate>Fri, 06 Jan 2017 21:03:27 GMT</pubDate>
    <dc:creator>PGStats</dc:creator>
    <dc:date>2017-01-06T21:03:27Z</dc:date>
    <item>
      <title>SAS Function to Calculate Circular Mean</title>
      <link>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/323056#M71548</link>
      <description>&lt;P&gt;I'd like to develop a SAS function using PROC FCMP to calculate the circular mean of a set of values, but before I go to the effort I wonder if anyone has already done this.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here's some background on the circular mean:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="https://en.wikipedia.org/wiki/Mean_of_circular_quantities" target="_self"&gt;https://en.wikipedia.org/wiki/Mean_of_circular_quantities&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So, I'd like to develop a user function for circular mean--let's call it CMEAN--similar to the MEAN and MEDIAN function:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;mean_days = mean(of rb1-rb200);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;median_days = median(of rb1-rb200);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;avg_day_of_week = cmean(of wd1-wd200);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;avg_month_of_year = cmean(of m1-m200);&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I did find some appropriate SAS code referenced by Ulric Lund--see the last link on this page:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://statweb.calpoly.edu/ulund/" target="_self"&gt;http://statweb.calpoly.edu/ulund/&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;But it requires an input and output dataset, and I would like to turn this code (or something similar) into a SAS function as described above.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Or is there a better approach?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thanks much,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;David Oesper&lt;/P&gt;</description>
      <pubDate>Fri, 06 Jan 2017 18:07:10 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/323056#M71548</guid>
      <dc:creator>doesper</dc:creator>
      <dc:date>2017-01-06T18:07:10Z</dc:date>
    </item>
    <item>
      <title>Re: SAS Function to Calculate Circular Mean</title>
      <link>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/323083#M71565</link>
      <description>&lt;P&gt;This should be close...&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;options cmplib=sasuser.fcmp;

/* Circular mean. Returns a value between -cycleLength/2 and +cycleLength/2 */ 
proc fcmp outlib=sasuser.fcmp.test; function cmean (cycleLength, x[*]) varargs;
    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]);
            sinTot = sinTot + sin(factor*x[i]);
            n = n + 1;
            end;
        end;
    if n &amp;gt; 0 and fuzz(sinTot) ne 0 then return(atan2(sinTot/n, cosTot/n)/factor);
    else return (.);
endsub;
run;

data _null_;
array x{2}; /* Argument list must be an array */
x1 = 100;
x2 = 270;
mean = cmean(360, x);
   put mean=;
run;
&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Fri, 06 Jan 2017 21:03:27 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/323083#M71565</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2017-01-06T21:03:27Z</dc:date>
    </item>
    <item>
      <title>Re: SAS Function to Calculate Circular Mean</title>
      <link>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324150#M71937</link>
      <description>&lt;P&gt;This even closer&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;options cmplib=sasuser.fcmp;

/* Circular mean. Returns a value between -cycleLength/2 and +cycleLength/2 */ 
proc fcmp outlib=sasuser.fcmp.test; function cmean (cycleLength, x[*]) varargs;
    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]);
            sinTot = sinTot + sin(factor*x[i]);
            n = n + 1;
            end;
        end;
    if n &amp;gt; 0 then return(atan2(sinTot/n, cosTot/n)/factor);
    else return (.);
endsub;
run;

data _null_;
array x{2}; /* Argument list must be an array */
x1 = 100;
x2 = 270;
mean = cmean(360, x);
   put mean=;
x1 = 350;
x2 = 380;
mean = cmean(360, x);
   put mean=;
x1 = 260;
x2 = 280;
mean = cmean(360, x);
   put mean=;
run;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Thu, 12 Jan 2017 04:13:06 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324150#M71937</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2017-01-12T04:13:06Z</dc:date>
    </item>
    <item>
      <title>Re: SAS Function to Calculate Circular Mean</title>
      <link>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324238#M71962</link>
      <description>&lt;P&gt;PGStat's &amp;nbsp;second attempt does not handle the case&amp;nbsp;where the Cartesian average of the points is the origin. &amp;nbsp;You need to handle data for which&lt;/P&gt;
&lt;P&gt;FUZZ(sinTot)=0 and FUZZ(cosTot)=0&lt;/P&gt;
&lt;P&gt;or else you get the wrong answer for the following examples:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data _null_;
array x{4}; /* Argument list must be an array */
x1 = 45; x3 = 225;   /* rotational symmetry by 180 degrees */
mean = cmean(360, x);
   put mean=;
x2 = 135; x4 = 315;    /* rotational symmetry by 90 degrees */
mean = cmean(360, x);
   put mean=;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;I suggest the using the statement&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;    if n = 0 OR (fuzz(sinTot)=0 AND fuzz(sinTot)=0) then return(.);
    else return(atan2(sinTot/n, cosTot/n)/factor);&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 12 Jan 2017 13:37:58 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324238#M71962</guid>
      <dc:creator>Rick_SAS</dc:creator>
      <dc:date>2017-01-12T13:37:58Z</dc:date>
    </item>
    <item>
      <title>Re: SAS Function to Calculate Circular Mean</title>
      <link>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324406#M72021</link>
      <description>&lt;P&gt;I suspected I was missing something. Thank you &lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/13684"&gt;@Rick_SAS&lt;/a&gt;!&lt;/P&gt;</description>
      <pubDate>Thu, 12 Jan 2017 21:29:01 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324406#M72021</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2017-01-12T21:29:01Z</dc:date>
    </item>
    <item>
      <title>Re: SAS Function to Calculate Circular Mean</title>
      <link>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324766#M72116</link>
      <description>&lt;P&gt;Thank you, PGStats and Rick_SAS! &amp;nbsp;I took what you had and made some additional changes. &amp;nbsp;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).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;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 &amp;lt; 0            then rslt = rslt + cycleLength;
         if rslt &amp;gt;= 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); /* &amp;lt;-- 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);  /* &amp;lt;-- months of the year, function subtracts 1 from all x before calculating */
   output;
run;

proc print data=cmeans;
   title 'cmeans';
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Also, keep in mind that the array you are passing to PROC FCMP &lt;STRONG&gt;has&lt;/STRONG&gt; to be called x (x1, x2, ...). &amp;nbsp;The way I handled passing arrays not called x is shown in the following code snippet:&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let ae = 300; /* number of array elements */
.
.
.
array om{&amp;amp;ae} om1-om&amp;amp;ae;&lt;BR /&gt;array od{&amp;amp;ae} od1-od&amp;amp;ae;&lt;BR /&gt;array x{&amp;amp;ae} _temporary_;&lt;BR /&gt;.&lt;BR /&gt;.&lt;BR /&gt;.&lt;BR /&gt;call missing(of x{*});&lt;BR /&gt;do i = 1 to dim(om);&lt;BR /&gt;   x{i} = om{i};&lt;BR /&gt;end;&lt;BR /&gt;mean_order_month = cmean(12,x);&lt;BR /&gt;&lt;BR /&gt;call missing(of x{*});&lt;BR /&gt;do i = 1 to dim(od);&lt;BR /&gt;   x{i} = od{i};&lt;BR /&gt;end;&lt;BR /&gt;mean_order_dow = cmean(7,x);&lt;BR /&gt;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&lt;SPAN&gt;Many thanks!&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Dave&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Sat, 14 Jan 2017 00:47:18 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324766#M72116</guid>
      <dc:creator>doesper</dc:creator>
      <dc:date>2017-01-14T00:47:18Z</dc:date>
    </item>
    <item>
      <title>Re: SAS Function to Calculate Circular Mean</title>
      <link>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324767#M72117</link>
      <description>&lt;P&gt;Here's the code snippet properly formatted. &amp;nbsp;Sorry about that!&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let ae = 300; /* number of array elements */
.
.
.
array om{&amp;amp;ae} om1-om&amp;amp;ae;
array od{&amp;amp;ae} od1-od&amp;amp;ae;
array x{&amp;amp;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);&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Sat, 14 Jan 2017 00:52:36 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324767#M72117</guid>
      <dc:creator>doesper</dc:creator>
      <dc:date>2017-01-14T00:52:36Z</dc:date>
    </item>
    <item>
      <title>Re: SAS Function to Calculate Circular Mean</title>
      <link>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324865#M72159</link>
      <description>&lt;P&gt;No need to make a special case of some cycle length. I think you could get the desired results by shifting the data by half a cycle to calculate the mean and then to shift it back to report the result. Note: the array passed to the function can have any valid name.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;/* Circular mean. Returns a value &amp;gt; 0 and &amp;lt;= cycleLength.  */ 
proc fcmp outlib=sasuser.fcmp.test;
   function cmean (cycleLength, x[*]) varargs;
      factor = 2 * constant("PI") / cycleLength;
      offset = cycleLength/2;
      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]-offset));
            sinTot = sinTot + sin(factor*(x[i]-offset));
            n = n + 1;
         end;
      end;
      if n = 0 then return(.);
      if fuzz(sinTot) = 0 and fuzz(cosTot) = 0 then return(.);
      return ( atan2(sinTot/n,cosTot/n) / factor + offset );
   endsub;
run;

options cmplib=sasuser.fcmp;

data cmeans;
array y{4}; /* cmean argument list must be an array */
call missing(of y{*});
cycleLength = 7;
y1 = 1;
do y2 = 1 to cycleLength;
    cmean = cmean(cycleLength, y);
    output;
    end;

call missing(of y{*});
cycleLength = 12;
y1 = 1;
do y2 = 1 to cycleLength;
    cmean = cmean(cycleLength, y);
    output;
    end;
run;

proc print data=cmeans;
title 'cmeans';
run;
&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Sun, 15 Jan 2017 04:26:00 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/SAS-Function-to-Calculate-Circular-Mean/m-p/324865#M72159</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2017-01-15T04:26:00Z</dc:date>
    </item>
  </channel>
</rss>

