A breakpoint-based method to detect ontogenetic shifts in univariate time-activity budget series of central-place foraging insects. The method finds a single changepoint in time series where parameters change at some unknown timepoints t* is done by simply sweeping all possible breaks, and finding the most-likely changepoint according to the likelihood. The method was developed with honey bees in order to detect the Age at Onset of Foraging (AOF), but can be used for the detection of other ontogenetic shifts in other central-place foraging insects. For more details, see Requier et al. (2020) Measuring ontogenetic shifts in central-place foraging insects: a case study with honey bees. Journal of Animal Ecology.
# mu1 and mu2: behavioural values at stage 1 and stage 2.
# Both values mu1 and mu2 are equal (e.g. mu1=mu2=50) if no behavioural change is
# simulated, or different (e.g. mu1=25 and mu2=50) if behavioural change is
# simulated.
# rho1 and rho2 : interval frequency (default value 0.5 for both stages)
# n.obs: no. observations randomly selected in the time series, from 5 to 45
# sigma1 and sigma2: variance around the behavioural value, from 0.1 to 3
# t.full: time series from 0 to 50
# n.obs: no. observations randomly selected in the time series, from 5 to 45
# t.break: the time of the simulated behavioural change (default value of 25)
getTimeBudget <- function(
mu1 = 50,
mu2 = 50,
rho1 = 0.5,
rho2 = 0.5,
n.obs = 5,
sigma1 = 3,
sigma2 = 3,
t.full = 0:50,
t.break = 25
){
SimTS <- function(n, mu, rho, sigma){
X.standard <- arima.sim(n, model = list(ar = rho))
X.standard/sd(X.standard)*sigma + mu
}
x.full <- c(SimTS(t.break, mu1, rho1, sigma1),
SimTS(max(t.full) - t.break + 1, mu2, rho2, sigma2))
keep <- sort(sample(1:length(x.full), n.obs))
TimeBudget <- data.frame(
name = "A",
Age = t.full[keep],
x = x.full[keep])
return(TimeBudget)
}
getAofPlot <- function(
TimeBudget = TimeBudget,
AOF = AOF,
t.break = 25,
poly = FALSE,
ylabX = "x"
){
oldpar <- par(no.readonly =TRUE)
par(mar = c(4, 4, 1, 1), mfrow = c(1, 1))
plot(
x = TimeBudget$Age,
y = TimeBudget$x,
las = 1,
xlab = "Age (day)", ylab = ylabX,
pch = 21,
col = "gray20", bg = "gray80")
goodbreak1 = max(TimeBudget$Age[TimeBudget$Age < t.break])
goodbreak2 = min(TimeBudget$Age[TimeBudget$Age >= t.break])
if(poly == TRUE){
polygon(
c(
goodbreak1 - 0.5,
goodbreak2 + 0.5,
goodbreak2 + 0.5,
goodbreak1 - 0.5),
c(0, 0, 100, 100),
col = "gray50", border = NA)
}
abline(v = AOF$AOF, col = "black", lwd = 2, lty = 3)
lines(
x = c(min(TimeBudget$Age), AOF$AOF),
y = c(AOF$behav.stage1, AOF$behav.stage1),
col = "black", lwd = 2)
lines(
x = c(AOF$AOF, max(TimeBudget$Age)),
y = c(AOF$behav.stage2, AOF$behav.stage2),
col = "black", lwd = 2)
par(oldpar)
return(c(goodbreak1, goodbreak2))
}
TimeBudget <- getTimeBudget(
n.obs = 5,
sigma1 = 0.1,
sigma2 = 0.1)
print(TimeBudget)
#> name Age x
#> 1 A 10 49.86454
#> 2 A 13 49.88205
#> 3 A 15 49.83634
#> 4 A 34 50.14661
#> 5 A 39 49.97453
AOF <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[,3])
#>
|
| | 0%
|
|======================================================================| 100%
print(AOF)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A x undetected 49.94081 NA NA
#> [1] 15 34
TimeBudget <- getTimeBudget(
n.obs = 5,
sigma1 = 3,
sigma2 = 3)
print(TimeBudget)
#> name Age x
#> 1 A 1 53.93361
#> 2 A 8 49.51130
#> 3 A 15 47.30424
#> 4 A 32 45.69737
#> 5 A 38 50.57546
AOF <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[,3])
#>
|
| | 0%
|
|======================================================================| 100%
print(AOF)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A x undetected 49.40439 NA NA
#> [1] 15 32
TimeBudget <- getTimeBudget(
n.obs = 45,
sigma1 = 0.1,
sigma2 = 0.1)
print(TimeBudget)
#> name Age x
#> 1 A 0 49.79949
#> 2 A 2 50.06325
#> 3 A 3 49.97564
#> 4 A 4 50.03406
#> 5 A 5 49.85947
#> 6 A 6 50.08880
#> 7 A 7 49.94319
#> 8 A 8 49.96156
#> 9 A 9 50.14011
#> 10 A 10 50.14781
#> 11 A 11 49.97831
#> 12 A 12 50.00836
#> 13 A 13 50.15423
#> 14 A 14 50.10220
#> 15 A 15 50.13328
#> 16 A 16 50.28095
#> 17 A 17 50.00153
#> 18 A 18 50.06551
#> 19 A 19 50.06366
#> 20 A 20 50.13580
#> 21 A 21 50.00360
#> 22 A 22 50.04374
#> 23 A 23 50.02622
#> 24 A 24 50.08001
#> 25 A 25 49.84788
#> 26 A 26 49.68481
#> 27 A 27 49.96712
#> 28 A 28 50.04032
#> 29 A 30 50.04384
#> 30 A 31 50.12079
#> 31 A 32 50.01217
#> 32 A 33 50.10344
#> 33 A 34 49.91626
#> 34 A 35 49.81358
#> 35 A 36 49.90493
#> 36 A 38 49.94685
#> 37 A 39 50.01172
#> 38 A 40 50.02130
#> 39 A 42 49.82340
#> 40 A 43 49.99481
#> 41 A 44 49.92107
#> 42 A 47 49.94244
#> 43 A 48 50.07751
#> 44 A 49 49.94487
#> 45 A 50 49.92414
AOF <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[,3])
#>
|
| | 0%
|
|======================================================================| 100%
print(AOF)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A x undetected 50.00342 NA NA
#> [1] 24 25
TimeBudget <- getTimeBudget(
n.obs = 45,
sigma1 = 3,
sigma2 = 3)
print(TimeBudget)
#> name Age x
#> 1 A 0 55.24727
#> 2 A 1 47.52394
#> 3 A 2 51.56274
#> 4 A 4 45.51155
#> 5 A 5 46.21602
#> 6 A 6 49.61906
#> 7 A 7 52.73307
#> 8 A 8 50.75370
#> 9 A 9 47.06997
#> 10 A 10 45.67862
#> 11 A 11 47.60879
#> 12 A 12 43.59124
#> 13 A 14 45.54905
#> 14 A 15 50.34642
#> 15 A 16 50.24850
#> 16 A 17 53.95103
#> 17 A 18 50.73535
#> 18 A 19 48.99151
#> 19 A 20 47.46919
#> 20 A 22 50.27780
#> 21 A 23 49.88799
#> 22 A 24 46.55145
#> 23 A 25 54.79777
#> 24 A 26 50.80541
#> 25 A 27 47.63259
#> 26 A 28 46.67526
#> 27 A 29 52.27467
#> 28 A 30 51.12071
#> 29 A 31 49.68613
#> 30 A 33 50.33801
#> 31 A 34 46.19189
#> 32 A 35 48.43791
#> 33 A 36 49.22889
#> 34 A 37 44.66182
#> 35 A 38 52.20056
#> 36 A 40 54.01488
#> 37 A 41 52.15239
#> 38 A 42 52.12979
#> 39 A 43 52.01276
#> 40 A 44 50.71855
#> 41 A 45 52.95068
#> 42 A 46 54.59617
#> 43 A 47 57.49672
#> 44 A 48 55.18699
#> 45 A 49 47.79365
AOF <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[,3])
#>
|
| | 0%
|
|======================================================================| 100%
print(AOF)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A x 37 50.00508 49.08751 52.8412
#> [1] 24 25
TimeBudget <- getTimeBudget(
mu1 = 25,
n.obs = 5,
sigma1 = 0.1,
sigma2 = 0.1)
print(TimeBudget)
#> name Age x
#> 1 A 1 25.07584
#> 2 A 14 24.91868
#> 3 A 15 24.79700
#> 4 A 27 49.98822
#> 5 A 37 49.95404
AOF <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[,3])
#>
|
| | 0%
|
|======================================================================| 100%
print(AOF)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A x 15 34.94676 24.93051 49.97113
#> [1] 15 27
TimeBudget <- getTimeBudget(
mu1 = 25,
n.obs = 5,
sigma1 = 3,
sigma2 = 3)
print(TimeBudget)
#> name Age x
#> 1 A 9 27.88885
#> 2 A 11 22.80746
#> 3 A 14 28.46289
#> 4 A 19 29.75055
#> 5 A 29 51.69794
AOF <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[,3])
#>
|
| | 0%
|
|======================================================================| 100%
print(AOF)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A x 14 32.12154 26.3864 40.72424
#> [1] 19 29
TimeBudget <- getTimeBudget(
mu1 = 25,
n.obs = 45,
sigma1 = 0.1,
sigma2 = 0.1)
print(TimeBudget)
#> name Age x
#> 1 A 0 25.06383
#> 2 A 1 25.10548
#> 3 A 2 25.08661
#> 4 A 3 25.05588
#> 5 A 4 25.13950
#> 6 A 5 25.03946
#> 7 A 6 25.16317
#> 8 A 7 25.12013
#> 9 A 8 24.91666
#> 10 A 9 24.89625
#> 11 A 10 24.92021
#> 12 A 11 25.09579
#> 13 A 12 24.83038
#> 14 A 13 24.85163
#> 15 A 14 24.98805
#> 16 A 15 25.02943
#> 17 A 16 25.05736
#> 18 A 19 24.90666
#> 19 A 20 24.84695
#> 20 A 21 24.89475
#> 21 A 22 25.08274
#> 22 A 23 24.98707
#> 23 A 24 25.00009
#> 24 A 25 49.88403
#> 25 A 26 49.93289
#> 26 A 27 50.05070
#> 27 A 28 49.95815
#> 28 A 29 49.98170
#> 29 A 30 50.09180
#> 30 A 31 50.10574
#> 31 A 33 50.03549
#> 32 A 34 49.96310
#> 33 A 35 50.05577
#> 34 A 36 49.96945
#> 35 A 38 49.99370
#> 36 A 39 50.17485
#> 37 A 40 50.20040
#> 38 A 41 50.04373
#> 39 A 42 50.02976
#> 40 A 44 50.01886
#> 41 A 45 50.19031
#> 42 A 46 50.21498
#> 43 A 48 50.04803
#> 44 A 49 50.01212
#> 45 A 50 49.98949
AOF <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[,3])
#>
|
| | 0%
|
|======================================================================| 100%
print(AOF)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A x 24 37.24496 25.00339 50.04296
#> [1] 24 25
TimeBudget <- getTimeBudget(
mu1 = 25,
n.obs = 45,
sigma1 = 3,
sigma2 = 3)
print(TimeBudget)
#> name Age x
#> 1 A 0 27.34048
#> 2 A 1 31.60753
#> 3 A 2 24.12454
#> 4 A 3 23.73634
#> 5 A 4 24.45264
#> 6 A 5 26.53546
#> 7 A 6 27.48494
#> 8 A 7 20.84885
#> 9 A 8 21.75204
#> 10 A 9 22.21847
#> 11 A 10 20.95324
#> 12 A 11 25.16355
#> 13 A 12 26.76076
#> 14 A 13 27.07178
#> 15 A 15 24.99816
#> 16 A 16 29.21724
#> 17 A 19 24.33274
#> 18 A 20 21.97713
#> 19 A 21 22.52308
#> 20 A 22 25.16924
#> 21 A 23 25.87922
#> 22 A 24 20.80284
#> 23 A 25 50.30887
#> 24 A 26 51.04345
#> 25 A 27 50.48078
#> 26 A 28 52.96206
#> 27 A 30 56.70277
#> 28 A 31 51.00239
#> 29 A 32 50.05614
#> 30 A 33 50.80385
#> 31 A 34 50.21664
#> 32 A 36 53.48042
#> 33 A 38 47.44452
#> 34 A 39 47.53315
#> 35 A 40 48.75047
#> 36 A 41 48.07113
#> 37 A 42 55.33352
#> 38 A 43 52.40236
#> 39 A 44 53.50399
#> 40 A 45 53.52737
#> 41 A 46 52.02733
#> 42 A 47 47.61836
#> 43 A 48 46.31564
#> 44 A 49 44.43269
#> 45 A 50 51.17067
AOF <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[,3])
#>
|
| | 0%
|
|======================================================================| 100%
print(AOF)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A x 24 38.00308 24.77047 50.66037
#> [1] 24 25
This is a subset of 5 bees randomly selected in the experimental design of Requier et al. (J. Animal Ecology).
TimeBudget <- dataExample
head(TimeBudget, n = 25)
#> name Age Number Duration Time
#> 1 A00103C00020FD24 15 2 63.5000 55166.0
#> 2 A00103C00020FD24 20 1 176.0000 71609.0
#> 3 A00103C00020FD24 22 4 1708.5000 41340.0
#> 4 A00103C00020FD24 23 5 2762.2000 42941.0
#> 5 A00103C00020FD24 24 1 562.0000 67521.0
#> 6 A00103C00020FD24 26 2 695.0000 40153.0
#> 7 A00103C00020FD24 27 1 700.0000 48959.0
#> 8 A00103C000402590 14 1 22.0000 64725.0
#> 9 A00103C000402590 16 1 227.0000 45238.0
#> 10 A00103C000402590 23 7 205.5714 62908.0
#> 11 A00103C000402590 24 14 360.1429 54300.0
#> 12 A00103C000402590 25 3 357.3333 64024.0
#> 13 A00103C000402590 26 10 680.4000 56767.5
#> 14 A00103C000402590 27 7 781.1429 56320.0
#> 15 A00103C000402590 28 3 2786.3333 51801.0
#> 16 A00103C000402590 29 1 8.0000 42236.0
#> 17 A00103C000406D60 13 1 14.0000 56166.0
#> 18 A00103C000406D60 14 2 89.0000 60514.5
#> 19 A00103C000406D60 15 4 150.5000 46005.5
#> 20 A00103C000406D60 16 1 4.0000 68591.0
#> 21 A00103C000406D60 17 2 330.5000 58752.5
#> 22 A00103C000406D60 18 3 781.0000 54998.0
#> 23 A00103C000406D60 20 4 1981.0000 57991.0
#> 24 A00103C000406D60 22 2 735.0000 52296.5
#> 25 A00103C000406D60 23 7 1908.2857 44964.0
# working on Number of trips
varX <- "Number"
AOF_number <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[varX])
#>
|
| | 0%
|
|============== | 20%
|
|============================ | 40%
|
|========================================== | 60%
|
|======================================================== | 80%
|
|======================================================================| 100%
print(AOF_number)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A00103C00020FD24 Number undetected 2.285714 NA NA
#> 2 A00103C000402590 Number 23 5.222222 3.000000 6.333333
#> 3 A00103C000406D60 Number 20 3.300000 2.428571 5.333333
#> 4 A00103C00040A5D5 Number undetected 1.636364 NA NA
#> 5 A00103C00040A5F4 Number 23 11.125000 1.333333 17.000000
# working on Duration of trips
varX <- "Duration"
AOF_duration <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[varX])
#>
|
| | 0%
|
|============== | 20%
|
|============================ | 40%
|
|========================================== | 60%
|
|======================================================== | 80%
|
|======================================================================| 100%
print(AOF_duration)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A00103C00020FD24 Duration 20 952.4571 119.75000 1285.5400
#> 2 A00103C000402590 Duration 25 603.1026 234.40952 1063.9690
#> 3 A00103C000406D60 Duration 17 757.0571 117.60000 1396.5143
#> 4 A00103C00040A5D5 Duration 25 798.9091 81.64286 2054.1250
#> 5 A00103C00040A5F4 Duration 24 228.5120 211.82143 245.2026
# working on Time of trips
varX <- "Time"
AOF_time <- aof(
name = TimeBudget[,1],
Age = TimeBudget[,2],
x = TimeBudget[varX])
#>
|
| | 0%
|
|============== | 20%
|
|============================ | 40%
|
|========================================== | 60%
|
|======================================================== | 80%
|
|======================================================================| 100%
print(AOF_time)
#> name parameter AOF behav.total behav.stage1 behav.stage2
#> 1 A00103C00020FD24 Time 20 52527.00 63387.50 48182.80
#> 2 A00103C000402590 Time 23 55368.83 57623.67 54241.42
#> 3 A00103C000406D60 Time 18 54637.80 57504.58 50337.62
#> 4 A00103C00040A5D5 Time 25 56072.86 59164.14 50663.12
#> 5 A00103C00040A5F4 Time 25 59626.88 62104.80 55497.00
goodbreak <- lapply(seq_along(unique(TimeBudget[,1])), function(i){
print(as.character(unique(TimeBudget[,1])[i]))
oldpar <- par(no.readonly =TRUE)
par(mfrow = c(1, 3))
varXList <- list("Number", "Duration", "Time")
varAOFList <- list(AOF_number, AOF_duration, AOF_time)
varYlabList <- list("Trip number (per day)", "Trip duration (seconds)", "Trip time (seconds)")
varXRes <- sapply(1:3, function(j){
TimeBx <- TimeBudget[
TimeBudget[,1] == unique(TimeBudget[,1])[i],
c("name", "Age", varXList[[j]])]
names(TimeBx)[3] <- "x"
getAofPlot(
TimeBudget = TimeBx,
AOF = varAOFList[[j]][i,],
ylabX = varYlabList[[j]])
})
par(oldpar)
return(varXRes)
})
#> [1] "A00103C00020FD24"
#> [1] "A00103C000402590"
#> [1] "A00103C000406D60"
#> [1] "A00103C00040A5D5"
#> [1] "A00103C00040A5F4"