Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I calculate average hour of an event?

I have some data from different dates and want to know what the average (median or mean) hour that events occur. The problem is that normal averages don't work here as time is circular (e.g. 1 comes after 24). For example, the average of 11pm and 1am should be midnight, but the normal average function would give midday. However, I can't find any functions that are built to do this! Is there a way to do this in R?

Example data:

hours <- c(20, 21, 22, 23 , 0, 1, 2, 3, 4)

Expected result: mean = 0, median = 0

like image 995
unknown Avatar asked Oct 21 '25 16:10

unknown


2 Answers

1) nondecreasing Assuming the times are non-decreasing and that each time is less than 24 hours from the prior time we can determine the day of each time by adding 1 every time we encounter an hour that is less than the prior hour. Add 24 times the day to hour giving hours2 which is the total number of hours since hour 0. Finally take the mean or median modulo 24 to ensure it is in the interval [0, 24) .

hours <- c(20, 21, 22, 23 , 0, 1, 2, 3, 4)

day <- cumsum(c(0, diff(hours) < 0))
hours2 <- hours + 24 * day

mean(hours2) %% 24
## [1] 0

median(hours2) %% 24
## [1] 0

2) circular In this alternative we map the times to a circle and use mean.circular and median.circular from the circular package. More information on that package is available in its help files as well at Answering biological questions using circular data and analysis in R

library(circular)

hours <- c(20, 21, 22, 23 , 0, 1, 2, 3, 4)

hours.circ <- circular(hours, template = "clock24", units = "hours")

mean.circ <- mean(hours.circ)
as.numeric(mean.circ) %% 24
## [1] 0

median.circ <- median(hours.circ)
as.numeric(median.circ) %% 24
## [1] 0

plot(hours.circ)
points(mean.circ, col = "red", cex = 3)
points(median.circ, col = "blue", cex = 2)

[continued after graph]

screenshot

Note

You may also find it useful to try the above with a more asymmetric input.

hours <- c(20, 21, 22, 23 , 12)
like image 80
G. Grothendieck Avatar answered Oct 24 '25 06:10

G. Grothendieck


For the circular average, you do the following:

  1. Map the hours to a 24H circle by multiplying them by (2*pi/24).
  2. Calculate the mean x and y coordinates respectively.
  3. Transform these average circle coordinates back to hours.

I don't know if there exists a well-accepted definition of the circular median.

average_time <- function(x) {

  circle_hours <- x*(2*pi/24)

  mean_x <- mean(cos(circle_hours))
  mean_y <- mean(sin(circle_hours))

  atan2(mean_y, mean_x) / (2*pi) * 24
}

hours <- c(20, 21, 22, 23 , 0, 1, 2, 3, 4)
average_time(hours)
## [1] -1.078441e-15
like image 36
Aron Strandberg Avatar answered Oct 24 '25 08:10

Aron Strandberg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!