How to detect sign change (eg, positive to negative) in time series data?
-
02-01-2020 - |
Question
I have data of fluxes over time and would like to obtain a list of times when the flux changed from negative to positive or vice versa. This seems like a simple thing so it probably has a simple answer but I haven't been able to find one with my search terms.
Sample data:
day=c(1,2,3,5,10,20)
flux=c(-2,-4,1,-2,4,11)
I'd like to get something like a vector crossover_times= (2.5, 4, 7.5) to indicate the interpolated days that the change occurred and, ideally, also information indicating which way the sign change went, e.g. sign_changes =(positive, negative, positive).
I could, of course, write a loop to iterate through the data but I'm guessing that R has one or more helpful functions for this. Any suggestions?
Solution
diff(sign(flux))
will be non-zero at cross-overs and will have the sign of the crossing:
updn <- c(0, diff(sign(flux)))
ix <- which(updn != 0)
(day[ix] + day[ix-1])/2
## [1] 2.5 4.0 7.5
sign(updn)[ix]
## [1] 1 -1 1
UPDATED: Added sign of crossing. Improvements.
OTHER TIPS
You could use the nifty rle
function to compute the vector of positions where it crosses over and directions. rle
computes the lengths and values of the runs of a vector where it's identical, and we've passed it the binary vector of whether your values are non-negative.
pos <- head(cumsum(rle(flux >= 0)$lengths), -1)
pos
# [1] 2 3 4
All the remains is the interpolation and getting the directions:
(day[pos] + day[pos+1]) / 2
# [1] 2.5 4.0 7.5
c("positive", "negative")[head(rle(flux >= 0)$values + 1, -1)]
# [1] "positive" "negative" "positive"