tassones
tassones

Reputation: 1692

How can I calculate difference between max and min over varying time series lengths in R?

I have a timeseries of water depth measurements (15-min intervals) and I want to calculate the tidal height of each tidal cycle. Tidal height is the absolute difference between max depth and min depth for an outgoing tide (or vice versa for an incoming tide, hence the absolute difference). To complicate things, not all of my sites have 6-hour variations between high and low tides; some have more, some have less. I would like to have a way of calculating the absolute difference between max and min values that vary in the length of time between consecutive highs and lows.

Just some random data:

dat <- data.frame(matrix(vector(),20,2,
                         dimnames=list(c(), c("Time", "Depth"))),
                  stringsAsFactors = F)
dat[,1] <- seq(from = 1, to = 20, by = 1)
dat[1:5,2] <- seq(from = 0.5, to = 2.5, by = 0.5)
dat[6:13,2] <- seq(from = 2.6, to = 0.4, by = -0.28)
dat[14:20,2] <- seq(from = 0.4, to = 2.8, by = 0.4)

The output should have the following results:

    Tide TidalHeight
1   1    2.1
2   2    2.2
3   3    2.4

Tide 1 would be the absolute difference between the low of 0.5 and high of 2.6, tide 2 would be the absolute difference between the high of 2.6 and low of 0.4, and tide 3 would be the absolute difference between the low of 0.4 and high of 2.8. The length of time between consecutive high and low tides varies, in the above example by 6, 8, and 6-time steps but in the real data this could be any number of time steps.

I would like to know how to automatically calculate the absolute difference between high and low tides that vary in length of time between tides.

Upvotes: 1

Views: 259

Answers (2)

Onyambu
Onyambu

Reputation: 79208

You could also do:

library(tidyverse)
dat$grp <- with(rle(sign(c(diff(dat$Depth),0))), rep(seq_along(values),lengths))
abs(diff(subset(dat, ave(grp,grp,FUN = seq_along)==1)$Depth))
[1] 2.1 2.2 2.4

Upvotes: 2

Limey
Limey

Reputation: 12461

If you assume that water depth is monotonic during both rising tides and falling tides, then @Onyamu's comment, whilst strictly correct, can be ignored.

The trick is to use rle to work out the number of observations for which each tide lasts.

library(tibble)

dat <- dat %>% 
         mutate(Direction=ifelse(Depth > lag(Depth), "Rising", "Falling"))
dat$Direction[1] <- dat$Direction[2]  # Handle the first observation.

tides <- rle(dat$Direction)
dat <- dat %>% 
         add_column(Tide=unlist(lapply(1:length(tides$length), function(x) rep(x, tides$length[x]))))
dat %>% 
  group_by(Tide) %>% 
  summarise(
    HighTide=max(Depth), 
    LowTide=min(Depth), 
    .groups="drop"
  ) %>% 
  mutate(
    TideHeight=ifelse(
                 Tide == 1, 
                 HighTide - LowTide,
                 ifelse(
                   Tide == nrow(.), 
                   HighTide - lag(LowTide), 
                   lag(HighTide) - LowTide
                 )
               )
  )
dat
# A tibble: 3 x 4
   Tide HighTide LowTide TideHeight
  <int>    <dbl>   <dbl>      <dbl>
1     1     2.6      0.5        2.1
2     2     2.32     0.4        2.2
3     3     2.8      0.8        2.4

Upvotes: 4

Related Questions