Reputation: 599
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?
Upvotes: 3
Views: 6806
Reputation: 269654
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.
Upvotes: 16
Reputation: 44330
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"
Upvotes: 6