Skip to content

Instantly share code, notes, and snippets.

@jonesor
Last active November 1, 2022 14:57
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonesor/132f531a520c3b331543 to your computer and use it in GitHub Desktop.
Save jonesor/132f531a520c3b331543 to your computer and use it in GitHub Desktop.
Calculate a circular mean
#Circular means are useful if you are dealing with data that are inherently "circular" such as the day or month of the year, or direction.
#For example, imagine your data consists of the month in which an event occurs, and you want to report the average month. If you had 3 observations in December, and 3 in February, the average should be in January (1) whereas the more conventional arithmetic mean would tell you the answer was 7. The trick to dealing with this issue is to convert the data into radians, and do a bunch of trigonometry.
#This is how you might approach it in R:
#You have 3 observations in December (12), and 3 in February.
m = c(12,12,12,2,2,2)
#First you convert these values to an angle, then to radians. There are 12 (approximately) equally spaced points in the year for month, which we specify with np.
np = 12
deg.m = m * (360 / np)
rad.m = deg.m * (pi / 180)
#Calculate the mean of the cosines and sines:
mean.cos = mean(cos(rad.m))
mean.sin = mean(sin(rad.m))
#Take the arctangent:
x = atan2(mean.sin , mean.cos)
#Convert to degrees:
x.deg = x * (180 / pi)
#Convert degrees to month
x.month = x.deg / (360 / np)
x.month
#Now, x.month should be 1.
#This can all be wrapped in a function like this
circ.mean <- function(m,int){
rad.m = m*(360/int)*(pi/180)
mean.cos = mean(cos(rad.m))
mean.sin = mean(sin(rad.m))
x.deg = atan2(mean.sin,mean.cos)*(180/pi)
return(x.deg/(360/int))
}
#Reference: http://en.wikipedia.org/wiki/Mean_of_circular_quantities
@79seismo
Copy link

This should be x.deg = atan2(mean.sin,mean.cos)*(180/pi) correct?

@csaki01
Copy link

csaki01 commented Nov 1, 2022

This should be x.deg = atan2(mean.sin,mean.cos)*(180/pi) correct?

Yes, and I learned the hard way.
Very useful script though, I used it to calculate 2D surface normals.

@jonesor
Copy link
Author

jonesor commented Nov 1, 2022

You're right. Updated now.
Thanks for spotting this @79seismo !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment