Warning: package 'slider' was built under R version 4.4.3
library(lubridate)
Attaching package: 'lubridate'
The following objects are masked from 'package:base':
date, intersect, setdiff, union
library(ggforce)
Warning: package 'ggforce' was built under R version 4.4.3
library(FKF)
Warning: package 'FKF' was built under R version 4.4.3
library(data.table)
Attaching package: 'data.table'
The following objects are masked from 'package:lubridate':
hour, isoweek, mday, minute, month, quarter, second, wday, week,
yday, year
The following object is masked from 'package:purrr':
transpose
The following objects are masked from 'package:dplyr':
between, first, last
Loading in Data
setwd("C:/Users/ipberg/OneDrive - Iowa State University/Spring26/Sensors/")load("4_1.RData")# setwd("/Users/IsaacBerg/Documents/Code/Sensors/")# load("4_1.RData")
Not keeping the first 12 hours of data collected and using the next 24 as training
training_data <- focused %>%group_by(Sow_ID) %>%# Filter out the first 12 hours of data per sow# filter(sensor_ts >= min(sensor_ts) + hours(12)) %>%mutate(hours_before =as.numeric(difftime(FD_Gestal, min(sensor_ts), units="hours")),reaches_farrow =max(sensor_ts) >=as.POSIXct(FD_Gestal) ) %>%filter(hours_before >=60& reaches_farrow ==TRUE) %>%filter(sensor_ts <as.POSIXct((FD_Gestal +days(2)))) %>%mutate(time_to_farrow =-as.numeric(difftime(as.POSIXct(FD_Gestal), sensor_ts, units ="hours")),m_mean_24h =slide_index_dbl(m, sensor_ts, mean, .before =hours(24)),m_var_24h =slide_index_dbl(m, sensor_ts, var, .before =hours(24)) ) %>%filter(as.numeric(format(sensor_ts, "%M")) %%15==0&as.numeric(format(sensor_ts, "%S")) ==0) %>%mutate(start_time =min(sensor_ts)) %>%# Filter for the window: between 12 and 36 hours from the startfilter(sensor_ts >= (start_time +hours(12)) & sensor_ts < (start_time +hours(36))) %>%select(-hours_before, -reaches_farrow) %>%nest()
Subset of data with only sows with 60 hours of data or greater before farrowing - removing the first 12 hours
sows_greater_60 <- focused %>%group_by(Sow_ID) %>%mutate(hours_before =as.numeric(difftime(FD_Gestal, min(sensor_ts), units="hours")),reaches_farrow =max(sensor_ts) >=as.POSIXct(FD_Gestal) ) %>%filter(hours_before >=60& reaches_farrow ==TRUE) %>%filter(sensor_ts <as.POSIXct((FD_Gestal +days(2)))) %>%mutate(time_to_farrow =-as.numeric(difftime(as.POSIXct(FD_Gestal), sensor_ts, units ="hours")),m_mean_24h =slide_index_dbl(m, sensor_ts, mean, .before =hours(24)),m_var_24h =slide_index_dbl(m, sensor_ts, var, .before =hours(24)) ) %>%filter(as.numeric(format(sensor_ts, "%M")) %%15==0&as.numeric(format(sensor_ts, "%S")) ==0) %>%mutate(start_time =min(sensor_ts)) %>%select(-hours_before, -reaches_farrow) %>%semi_join(training_data %>%unnest(data), by ="Sow_ID") %>%# <-- only keeps sows that exist in trainingnest()
Plotting the variance of each sow on the same plot relative to their date of farrowing
# 1. Prepare data for plottingplot_data <- sows_greater_60 %>%unnest(data)# 2. Create the plotggplot(plot_data, aes(x = time_to_farrow, y = m_var_24h)) +# Add a line for each individual sow (lightly colored)geom_line(aes(group = Sow_ID), alpha =0.1, color ="steelblue") +# Add a smoothed average line to see the general trendgeom_smooth(color ="red", method ="gam") +# Mark the farrowing eventgeom_vline(xintercept =0, linetype ="dashed", color ="black") +annotate("text", x =0.2, y =max(plot_data$m_var_24h, na.rm=T), label ="Farrowing Date", angle =90, vjust =-0.5) +theme_minimal() +labs(title ="Sow Activity Variance Relative to Farrowing",x ="Days Relative to Farrowing (0 = Start of FD_Gestal)",y ="24h Rolling Variance (m)" )
`geom_smooth()` using formula = 'y ~ s(x, bs = "cs")'
Warning: Removed 40 rows containing non-finite outside the scale range
(`stat_smooth()`).
Warning: Removed 40 rows containing missing values or values outside the scale range
(`geom_line()`).
using training data
# 1. Prepare data for plottingplot_data_12 <- training_data %>%unnest(data) # 2. Create the plotggplot(plot_data_12, aes(x = time_to_farrow, y = m_var_24h)) +# Add a line for each individual sow (lightly colored)geom_line(aes(group = Sow_ID), alpha =0.1, color ="steelblue") +# Add a smoothed average line to see the general trendgeom_smooth(color ="red", method ="gam") +# Mark the farrowing eventgeom_vline(xintercept =0, linetype ="dashed", color ="black") +annotate("text", x =0.2, y =max(plot_data_12$m_var_24h, na.rm=T), label ="Farrowing Date", angle =90, vjust =-0.5) +theme_minimal() +labs(title ="Sow Activity Variance Relative to Farrowing",x ="Days Relative to Farrowing (0 = Start of FD_Gestal)",y ="24h Rolling Variance (m)" )
`geom_smooth()` using formula = 'y ~ s(x, bs = "cs")'
Plotting a single sow
library(ggplot2)library(dplyr)# 1. Pick one sow and unnest her datasingle_sow_data <- sows_greater_60 %>%filter(Sow_ID =="26240") %>%unnest(data) %>%filter(sensor_ts >= (start_time +hours(12)))# 2. Plotggplot(single_sow_data, aes(x = time_to_farrow, y = m_var_24h)) +geom_line(color ="firebrick", size =1) +geom_point(size =0.5, alpha =0.5) +# Shows the 15-min steps clearlygeom_vline(xintercept =0, linetype ="dashed") +geom_vline(xintercept = single_sow_data$time_to_farrow[1] -12)+# geom_smooth(se=FALSE,span=0.2)+theme_minimal() +labs(title =paste("Activity Variance: Sow", unique(single_sow_data$Sow_ID)),subtitle ="24-hour rolling window sampled every 15 minutes",x ="Hours Relative to Farrowing (0 = Start of FD_Gestal)",y ="Variance of Magnitude (m)" )
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
plotting the training data for a single sow
library(ggplot2)library(dplyr)# 1. Pick one sow and unnest her datasingle_sow_data_12 <- training_data %>%filter(Sow_ID =="26240") %>%unnest(data) # 2. Plotggplot(single_sow_data_12, aes(x = time_to_farrow, y = m_var_24h)) +geom_line(color ="firebrick", size =1) +geom_point(size =0.5, alpha =0.5) +# Shows the 15-min steps clearlygeom_vline(xintercept =0, linetype ="dashed") +geom_vline(xintercept = single_sow_data$time_to_farrow[1] -12)+# geom_smooth(se=FALSE,span=0.2)+theme_minimal() +labs(title =paste("Activity Variance: Sow", unique(single_sow_data$Sow_ID)),subtitle ="24-hour rolling window sampled every 15 minutes",x ="Hours Relative to Farrowing (0 = Start of FD_Gestal)",y ="Variance of Magnitude (m)" )
24 hour 15 minute step plots of sows with greater than 60hrs of data before farrowing date
Plots of all sows
Plots are of the magnitude variance
# 1. Prepare all dataall_sows_unnested <- sows_greater_60 %>%unnest(data)# 2. Get unique IDssow_list <-unique(all_sows_unnested$Sow_ID)# 3. Loop and Plotfor (sow in sow_list) { plot_data <- all_sows_unnested %>%filter(Sow_ID == sow) %>%filter(sensor_ts >= (start_time +hours(12))) p <-ggplot(plot_data, aes(x = time_to_farrow, y = m_var_24h)) +geom_line(color ="firebrick", size =0.8) +geom_vline(xintercept =0, linetype ="dashed", color ="darkgrey") +geom_vline(xintercept = plot_data$time_to_farrow[1] -12)+geom_vline(xintercept = plot_data$time_to_farrow[1]+24)theme_minimal() +labs(title =paste("Activity Variance: Sow", sow),subtitle ="24-hour rolling window (15-min steps)",x ="Hours Relative to Farrowing",y ="Variance of Magnitude" )print(p) # Optional: ggsave(paste0("Sow_", sow, ".png"), p)}
for removing the first 12 hours
# 1. Prepare all dataall_sows_unnested_12 <- training_data %>%unnest(data)# 2. Get unique IDssow_list <-unique(all_sows_unnested_12$Sow_ID)# 3. Loop and Plotfor (sow in sow_list) { plot_data <- all_sows_unnested_12 %>%filter(Sow_ID == sow)%>%filter(sensor_ts >= (start_time +hours(12))) p <-ggplot(plot_data, aes(x = time_to_farrow, y = m_var_24h)) +geom_line(color ="firebrick", size =0.8) +geom_vline(xintercept =0, linetype ="dashed", color ="darkgrey") +geom_vline(xintercept = plot_data$time_to_farrow[1] -12)+theme_minimal() +labs(title =paste("Activity Variance: Sow", sow),subtitle ="24-hour rolling window (15-min steps)",x ="Hours Relative to Farrowing",y ="Variance of Magnitude" )print(p) # Optional: ggsave(paste0("Sow_", sow, ".png"), p)}
Applying the Kalmon filtering
Using the first 48hrs of data as “baseline” for model to compare with
y <- training_data %>%unnest(cols=everything()) %>%filter(Sow_ID==26240) %>%select(m_var_24h)
Warning in as.data.table.list(x, keep.rownames = keep.rownames, check.names =
check.names, : Item 3 has 89 rows but longest item has 344; recycled with
remainder.
ggplot(data, aes(x = x, y = y)) +geom_line() +geom_line(data = data, aes(x = x, y = y_kalman), col ="blue") +expand_limits(y=0)+geom_vline(xintercept =0)+geom_vline(xintercept = data$x[1]-12)+geom_vline(xintercept = data$x[1]+24)+xlab("time relative to farrowing") +ggtitle("24h window w/ 15 min steps with first 12hrs removed and Kalman Filtering") +theme_bw()
y_full <-as.numeric(single_sow_data$m_var_24h)# Manual Test for Smoothingy_fkf_smooth <-fkf(a0 = a0, P0 = P0, dt = dt, ct = ct, Tt = Tt, Zt = Zt,HHt =matrix(0.000001), # System Noise (Lower = Smoother)GGt =matrix(0.001), # Measurement Noise (Higher = Smoother)yt =rbind(y_full))# Plot this versionplot_smooth <-data.table(x = single_sow_data$time_to_farrow,y = y_full,y_kalman =as.numeric(y_fkf_smooth$att[1, ]))ggplot(plot_smooth, aes(x = x)) +geom_line(aes(y = y), color ="black", alpha =0.3) +# Raw data in backgroundgeom_line(aes(y = y_kalman), color ="blue", size =1) +expand_limits(y=0)+geom_vline(xintercept =0)+geom_vline(xintercept = data$x[1]-12)+geom_vline(xintercept = data$x[1]+24)+xlab("time relative to farrowing") +ggtitle("24h window w/ 15 min steps with first 12hrs removed and Kalman Filtering Sow 26240") +theme_bw()
Warning in as.data.table.list(x, keep.rownames = keep.rownames, check.names =
check.names, : Item 3 has 89 rows but longest item has 344; recycled with
remainder.
ggplot(data, aes(x = x, y = y)) +geom_line() +geom_line(data = data, aes(x = x, y = y_kalman), col ="blue") +expand_limits(y=0)+geom_vline(xintercept =0)+geom_vline(xintercept = data$x[1]-12)+geom_vline(xintercept = data$x[1]+24)+xlab("time relative to farrowing") +ggtitle("24h window w/ 15 min steps with first 12hrs removed and Kalman Filtering Sow 28738") +theme_bw()
y_full <-as.numeric(single_sow_data_2$m_var_24h)# Manual Test for Smoothingy_fkf_smooth <-fkf(a0 = a0, P0 = P0, dt = dt, ct = ct, Tt = Tt, Zt = Zt,HHt =matrix(0.000001), # System Noise (Lower = Smoother)GGt =matrix(0.001), # Measurement Noise (Higher = Smoother)yt =rbind(y_full))# Plot this versionplot_smooth <-data.table(x = single_sow_data_2$time_to_farrow,y = y_full,y_kalman =as.numeric(y_fkf_smooth$att[1, ]))ggplot(plot_smooth, aes(x = x)) +geom_line(aes(y = y), color ="black", alpha =0.3) +# Raw data in backgroundgeom_line(aes(y = y_kalman), color ="blue", size =1) +expand_limits(y=0)+geom_vline(xintercept =0)+geom_vline(xintercept = data$x[1]-12)+geom_vline(xintercept = data$x[1]+24)+xlab("time relative to farrowing") +ggtitle("24h window w/ 15 min steps with first 12hrs removed and Kalman Filtering Sow 28738") +theme_bw()
Warning in as.data.table.list(x, keep.rownames = keep.rownames, check.names =
check.names, : Item 3 has 88 rows but longest item has 491; recycled with
remainder.
ggplot(data, aes(x = x, y = y)) +geom_line() +geom_line(data = data, aes(x = x, y = y_kalman), col ="blue") +expand_limits(y=0)+geom_vline(xintercept =0)+geom_vline(xintercept = data$x[1]-12)+geom_vline(xintercept = data$x[1]+24)+xlab("time relative to farrowing") +ggtitle("24h window w/ 15 min steps with first 12hrs removed and Kalman Filtering Sow 34083") +theme_bw()
y_full <-as.numeric(single_sow_data_3$m_var_24h)# Manual Test for Smoothingy_fkf_smooth <-fkf(a0 = a0, P0 = P0, dt = dt, ct = ct, Tt = Tt, Zt = Zt,HHt =matrix(0.000001), # System Noise (Lower = Smoother)GGt =matrix(0.001), # Measurement Noise (Higher = Smoother)yt =rbind(y_full))# Plot this versionplot_smooth <-data.table(x = single_sow_data_3$time_to_farrow,y = y_full,y_kalman =as.numeric(y_fkf_smooth$att[1, ]))ggplot(plot_smooth, aes(x = x)) +geom_line(aes(y = y), color ="black", alpha =0.3) +# Raw data in backgroundgeom_line(aes(y = y_kalman), color ="blue", size =1) +expand_limits(y=0)+geom_vline(xintercept =0)+geom_vline(xintercept = data$x[1]-12)+geom_vline(xintercept = data$x[1]+24)+xlab("time relative to farrowing") +ggtitle("24h window w/ 15 min steps with first 12hrs removed and Kalman Filtering Sow 34083") +theme_bw()
# --- Create the training baseline lookup ---train_lookup <- training_data %>%unnest(data) %>%group_by(Sow_ID) %>%# We store the variance values as a list so they can be passed to the filter functionsummarise(train_y =list(m_var_24h), .groups ="drop")
Adding CI
library(tidyverse)
Warning: package 'tidyverse' was built under R version 4.4.3
Attaching package: 'zoo'
The following objects are masked from 'package:data.table':
yearmon, yearqtr
The following objects are masked from 'package:base':
as.Date, as.Date.numeric
library(ggplot2)# adjust to tasteplot_smooth <- plot_smooth %>%mutate(resid = y - y_kalman,se =rollapply(resid, width =96, FUN = sd, fill =NA, align ="right"),ci_lower = y_kalman -qt(0.975, df =95) * se,ci_upper = y_kalman +qt(0.975, df =95) * se ) %>%select(x,y,y_kalman,ci_lower,ci_upper)ggplot(plot_smooth, aes(x = x)) +geom_line(aes(y = y_kalman), color ="red") +geom_line(aes(y = y), color ="blue") +geom_line(aes(y = ci_upper), color ="orange") +geom_line(aes(y = ci_lower), color ="brown")
Warning: Removed 95 rows containing missing values or values outside the scale range
(`geom_line()`).
Warning: Removed 95 rows containing missing values or values outside the scale range
(`geom_line()`).
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
For a total of 94 sows, the kalman filter was applied with a manualy fixed HHt and GGt matrices for smoothing
Quantitative results
alarm_performance_all95 <- results95 %>%unnest(data) %>%group_by(Sow_ID) %>%summarise(# First Alarm: First time crossing ABOVE Upper CIfirst_alarm =min(time_to_farrow[above_upper ==TRUE], na.rm =TRUE),# Second Alarm: First time crossing BELOW Lower CI (after the first spike)second_alarm =min(time_to_farrow[crossed_lower_after_upper ==TRUE], na.rm =TRUE),.groups ="drop" )
Warning: There were 59 warnings in `summarise()`.
The first warning was:
ℹ In argument: `first_alarm = min(time_to_farrow[above_upper == TRUE], na.rm =
TRUE)`.
ℹ In group 13: `Sow_ID = 28442`.
Caused by warning in `min()`:
! no non-missing arguments to min; returning Inf
ℹ Run `dplyr::last_dplyr_warnings()` to see the 58 remaining warnings.
# View the full listprint(alarm_performance_all95)
Warning: There were 59 warnings in `summarise()`.
The first warning was:
ℹ In argument: `first_alarm = min(time_to_farrow[above_upper == TRUE], na.rm =
TRUE)`.
ℹ In group 13: `Sow_ID = 28442`.
Caused by warning in `min()`:
! no non-missing arguments to min; returning Inf
ℹ Run `dplyr::last_dplyr_warnings()` to see the 58 remaining warnings.
# 2. Build the final results table with lead-time tiersquant_res_final95 <-data.table(# --- OVERALL COUNTS ---n_total_sows =nrow(dt_perf_all95),n_first_alarm =sum(is.finite(dt_perf_all95$first_alarm)),n_no_first_alarm =sum(!is.finite(dt_perf_all95$first_alarm)),n_second_alarm =sum(is.finite(dt_perf_all95$second_alarm)),n_no_second_alarm =sum(!is.finite(dt_perf_all95$second_alarm)),# --- MEANS ---mean_first_alarm =mean(dt_perf_all95$first_alarm[is.finite(dt_perf_all95$first_alarm)], na.rm =TRUE),mean_second_alarm =mean(dt_perf_all95$second_alarm[is.finite(dt_perf_all95$second_alarm)], na.rm =TRUE),# --- FIRST ALARM DETAILED BREAKDOWN (Sums to 78) ---n_first_alarm_gt_48h_before =sum(dt_perf_all95$first_alarm <-48, na.rm =TRUE),n_first_alarm_24_to_48h_pre =sum(dt_perf_all95$first_alarm <-24& dt_perf_all95$first_alarm >=-48, na.rm =TRUE),n_first_alarm_0_to_24h_pre =sum(dt_perf_all95$first_alarm <0& dt_perf_all95$first_alarm >=-24, na.rm =TRUE),n_first_alarm_on_FD =sum(dt_perf_all95$first_alarm >=0& dt_perf_all95$first_alarm <=24, na.rm =TRUE),n_first_alarm_after_FD =sum(dt_perf_all95$first_alarm >24&is.finite(dt_perf_all95$first_alarm), na.rm =TRUE),# --- SECOND ALARM BREAKDOWN (Sums to 51) ---n_second_alarm_before_FD =sum(dt_perf_all95$second_alarm <0, na.rm =TRUE),n_second_alarm_on_FD =sum(dt_perf_all95$second_alarm >=0& dt_perf_all95$second_alarm <=24, na.rm =TRUE),n_second_alarm_after_FD =sum(dt_perf_all95$second_alarm >24&is.finite(dt_perf_all95$second_alarm), na.rm =TRUE))# Transpose for final presentationprint(t(quant_res_final95))
For a 95% confidence interval with a total of 94 sows with greater than 60 hours of data before the date of farrowing. There was 78 sows that raised a first alarm and of those 78 with an average of 21.7 hours before the date of farrowing, 51 then raised a second alarm with an average of 2.2 hours into the farrowing date. There were 65 sows that raised the first alarm before the date of farrowing and 7 sows during the farrowing date and 6 sows after the date of farrowing. There were 22 sows that raised a second alarm before the date of farrowing, 17 that raised a second alarm on the date of farrowing and 12 with a second alarm after the date of farrowing. There is 27 sows that raised the first alarm less than 24hrs before the date of farrowing, 27 sows 24-48hrs before the farrowing date, 11 sows that raised the first alarm greater than 48hrs before the date of farrowing, 7 sows that raised the first alarm on the farrowing date, and 6 sows that raised a first alarm after the date of farrowing
Now to look at a 68% CI interval
# --- apply to all sows ---results68 <- sows_greater_60 %>%unnest(data) %>%filter(sensor_ts >= (start_time +hours(12))) %>%group_by(Sow_ID) %>%nest() %>%left_join(train_lookup, by ="Sow_ID") %>%mutate(data =map2(train_y, data, function(train, df) { df %>%mutate(# 1. Standard Kalman and CI calculationsy_kalman =fit_kalman(train, m_var_24h),resid = m_var_24h - y_kalman,se = zoo::rollapply(resid, width =96, FUN = sd, fill =NA, align ="right"),ci_lower = y_kalman -qt(0.84, df =95) * se,ci_upper = y_kalman +qt(0.84, df =95) * se,# 2. Define the breach flagsabove_upper = m_var_24h > ci_upper,below_lower = m_var_24h < ci_lower,# 3. Create the index for the FIRST spike# We use if_else to handle sows that never spike (returning a very large number)first_spike_idx =if(any(above_upper, na.rm =TRUE)) min(which(above_upper ==TRUE)) elseInf,# 4. Now we can safely reference first_spike_idxis_post_spike =row_number() > first_spike_idx,crossed_lower_after_upper = is_post_spike & below_lower,# 5. Status Columnviolation_type =case_when( m_var_24h > ci_upper ~1, m_var_24h < ci_lower ~-1,TRUE~0 ) ) }) ) %>%select(-train_y)
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
For a total of 94 sows, the kalman filter was applied with a manualy fixed HHt and GGt matrices for smoothing
Quantitative results
alarm_performance_all68 <- results68 %>%unnest(data) %>%group_by(Sow_ID) %>%summarise(# First Alarm: First time crossing ABOVE Upper CIfirst_alarm =min(time_to_farrow[above_upper ==TRUE], na.rm =TRUE),# Second Alarm: First time crossing BELOW Lower CI (after the first spike)second_alarm =min(time_to_farrow[crossed_lower_after_upper ==TRUE], na.rm =TRUE),.groups ="drop" )
Warning: There were 22 warnings in `summarise()`.
The first warning was:
ℹ In argument: `first_alarm = min(time_to_farrow[above_upper == TRUE], na.rm =
TRUE)`.
ℹ In group 21: `Sow_ID = 28225`.
Caused by warning in `min()`:
! no non-missing arguments to min; returning Inf
ℹ Run `dplyr::last_dplyr_warnings()` to see the 21 remaining warnings.
# View the full listprint(alarm_performance_all68)
Warning: There were 22 warnings in `summarise()`.
The first warning was:
ℹ In argument: `first_alarm = min(time_to_farrow[above_upper == TRUE], na.rm =
TRUE)`.
ℹ In group 21: `Sow_ID = 28225`.
Caused by warning in `min()`:
! no non-missing arguments to min; returning Inf
ℹ Run `dplyr::last_dplyr_warnings()` to see the 21 remaining warnings.
# 2. Build the final results table with lead-time tiersquant_res_final68 <-data.table(# --- OVERALL COUNTS ---n_total_sows =nrow(dt_perf_all68),n_first_alarm =sum(is.finite(dt_perf_all68$first_alarm)),n_no_first_alarm =sum(!is.finite(dt_perf_all68$first_alarm)),n_second_alarm =sum(is.finite(dt_perf_all68$second_alarm)),n_no_second_alarm =sum(!is.finite(dt_perf_all68$second_alarm)),# --- MEANS ---mean_first_alarm =mean(dt_perf_all68$first_alarm[is.finite(dt_perf_all68$first_alarm)], na.rm =TRUE),mean_second_alarm =mean(dt_perf_all68$second_alarm[is.finite(dt_perf_all68$second_alarm)], na.rm =TRUE),# --- FIRST ALARM DETAILED BREAKDOWN (Sums to 78) ---n_first_alarm_gt_48h_before =sum(dt_perf_all68$first_alarm <-48, na.rm =TRUE),n_first_alarm_24_to_48h_pre =sum(dt_perf_all68$first_alarm <-24& dt_perf_all68$first_alarm >=-48, na.rm =TRUE),n_first_alarm_0_to_24h_pre =sum(dt_perf_all68$first_alarm <0& dt_perf_all68$first_alarm >=-24, na.rm =TRUE),n_first_alarm_on_FD =sum(dt_perf_all68$first_alarm >=0& dt_perf_all68$first_alarm <=24, na.rm =TRUE),n_first_alarm_after_FD =sum(dt_perf_all68$first_alarm >24&is.finite(dt_perf_all68$first_alarm), na.rm =TRUE),# --- SECOND ALARM BREAKDOWN (Sums to 51) ---n_second_alarm_before_FD =sum(dt_perf_all68$second_alarm <0, na.rm =TRUE),n_second_alarm_on_FD =sum(dt_perf_all68$second_alarm >=0& dt_perf_all68$second_alarm <=24, na.rm =TRUE),n_second_alarm_after_FD =sum(dt_perf_all68$second_alarm >24&is.finite(dt_perf_all68$second_alarm), na.rm =TRUE))# Transpose for final presentationprint(t(quant_res_final68))
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
Warning in max(ids, na.rm = TRUE): no non-missing arguments to max; returning
-Inf
For a total of 94 sows, the kalman filter was applied with a manualy fixed HHt and GGt matrices for smoothing
Quantitative results
alarm_performance_all90 <- results90 %>%unnest(data) %>%group_by(Sow_ID) %>%summarise(# First Alarm: First time crossing ABOVE Upper CIfirst_alarm =min(time_to_farrow[above_upper ==TRUE], na.rm =TRUE),# Second Alarm: First time crossing BELOW Lower CI (after the first spike)second_alarm =min(time_to_farrow[crossed_lower_after_upper ==TRUE], na.rm =TRUE),.groups ="drop" )
Warning: There were 41 warnings in `summarise()`.
The first warning was:
ℹ In argument: `first_alarm = min(time_to_farrow[above_upper == TRUE], na.rm =
TRUE)`.
ℹ In group 21: `Sow_ID = 28225`.
Caused by warning in `min()`:
! no non-missing arguments to min; returning Inf
ℹ Run `dplyr::last_dplyr_warnings()` to see the 40 remaining warnings.
# View the full listprint(alarm_performance_all90)
Warning: There were 41 warnings in `summarise()`.
The first warning was:
ℹ In argument: `first_alarm = min(time_to_farrow[above_upper == TRUE], na.rm =
TRUE)`.
ℹ In group 21: `Sow_ID = 28225`.
Caused by warning in `min()`:
! no non-missing arguments to min; returning Inf
ℹ Run `dplyr::last_dplyr_warnings()` to see the 40 remaining warnings.
# 2. Build the final results table with lead-time tiersquant_res_final90 <-data.table(# --- OVERALL COUNTS ---n_total_sows =nrow(dt_perf_all90),n_first_alarm =sum(is.finite(dt_perf_all90$first_alarm)),n_no_first_alarm =sum(!is.finite(dt_perf_all90$first_alarm)),n_second_alarm =sum(is.finite(dt_perf_all90$second_alarm)),n_no_second_alarm =sum(!is.finite(dt_perf_all90$second_alarm)),# --- MEANS ---mean_first_alarm =mean(dt_perf_all90$first_alarm[is.finite(dt_perf_all90$first_alarm)], na.rm =TRUE),mean_second_alarm =mean(dt_perf_all90$second_alarm[is.finite(dt_perf_all90$second_alarm)], na.rm =TRUE),# --- FIRST ALARM DETAILED BREAKDOWN (Sums to 78) ---n_first_alarm_gt_48h_before =sum(dt_perf_all90$first_alarm <-48, na.rm =TRUE),n_first_alarm_24_to_48h_pre =sum(dt_perf_all90$first_alarm <-24& dt_perf_all90$first_alarm >=-48, na.rm =TRUE),n_first_alarm_0_to_24h_pre =sum(dt_perf_all90$first_alarm <0& dt_perf_all90$first_alarm >=-24, na.rm =TRUE),n_first_alarm_on_FD =sum(dt_perf_all90$first_alarm >=0& dt_perf_all90$first_alarm <=24, na.rm =TRUE),n_first_alarm_after_FD =sum(dt_perf_all90$first_alarm >24&is.finite(dt_perf_all90$first_alarm), na.rm =TRUE),# --- SECOND ALARM BREAKDOWN (Sums to 51) ---n_second_alarm_before_FD =sum(dt_perf_all90$second_alarm <0, na.rm =TRUE),n_second_alarm_on_FD =sum(dt_perf_all90$second_alarm >=0& dt_perf_all90$second_alarm <=24, na.rm =TRUE),n_second_alarm_after_FD =sum(dt_perf_all90$second_alarm >24&is.finite(dt_perf_all90$second_alarm), na.rm =TRUE))# Transpose for final presentationprint(t(quant_res_final90))