Search code examples
rmeanstandard-deviationdegreesradians

Calculating SD of compass directions using Circular


My goal is to calculate a mean and standard deviation for a series of compass degrees. Since I may cross the 360/ 0 mark, I can't use the a standard mean or sd calculation.

I've been using the circular packing in R, which seems to give me the correct means (though negative values are used when crossing the 360 mark as opposed to positive). But the sd values are way too small. Any thoughts on what might be wrong, or a better way to calculate mean and sd for compass directions?

The below code is my attempt to test my calculations of mean and sd on various compass directions, and compare to a standard mean and sd calculation (they should agree unless I cross the 360/ 0 mark)

library(circular)

Tester<-c(20,40,60)
Tester<-c(340,360,20)
Tester<-c(340,0,20)
Tester<-c(300,320,340)
Tester<-c(160,180,200)

ToCirc<- circular(Tester, type="angles", units="degrees",rotation="clock")

mean(ToCirc)
sd(ToCirc)
mean(Tester)
sd(Tester)

Solution

  • When you load circular, it has a separate sd function that calculates standard deviation for circular data differently.

    #DATA
    Tester<-c(160,180,200)
    ToCirc<- circular(Tester, type="angles", units="degrees",rotation="clock")
    
    
    sd(ToCirc)
    #[1] 0.2864803
    
    #The above is equivalent to 
    r = rho.circular(ToCirc) #Resultant Length
    sqrt(-2*log(r)) #Then sd
    #[1] 0.2864803
    

    If you want to use the sd of base after loading circular, use sd.default

    sd.default(ToCirc)
    #[1] 20
    
    #which is equal to
    sd.default(Tester)
    #[1] 20
    

    OR calculate everything yourself

    Tester<-c(340,360,20)
    sine = sum(sin(Tester * pi/180)) #sin of each angle, convert to radian first
    cosine = sum(cos(Tester * pi/180)) #cos of each angle, convert to radian first
    
    Tester_mean = (atan2(sine, cosine) * 180/pi) %% 360
    
    mu = (Tester - Tester_mean + 180) %% 360 - 180 #Difference of each angle from mean
    Tester_sd = sqrt(sum(mu^2)/(length(Tester) - 1)) #Standard Deviation
    
    Tester_mean
    #[1] 0
    Tester_sd
    #[1] 20