detect_all_events function: cgmguru and iglu-compatible event preprocessing

Relationship to iglu

cgmguru::detect_all_events() is an independent C++/Rcpp implementation of event calculation and CGM summary output. Its preprocessing is designed to be compatible with the event grid semantics used by iglu: subject-specific reading intervals, a midnight-aligned full-day grid, interpolation up to inter_gap, removal of larger gap-masked rows, and segment-wise event classification.

When reading_minutes is omitted or NULL, cgmguru calculates it automatically per subject from the median positive timestamp spacing in the input data.

The iglu package is used here as a formal reference, source of public example datasets, and comparison target. cgmguru does not call iglu at runtime for its core algorithms.

Datasets

We use two CGM example datasets shipped with iglu:

data(example_data_5_subject, package = "iglu")
data(example_data_hall, package = "iglu")

# Base-R summaries (no external dependencies)
summary_5 <- data.frame(
  rows = nrow(example_data_5_subject),
  subjects = length(unique(example_data_5_subject$id)),
  time_min = min(example_data_5_subject$time),
  time_max = max(example_data_5_subject$time),
  gl_min = min(example_data_5_subject$gl, na.rm = TRUE),
  gl_max = max(example_data_5_subject$gl, na.rm = TRUE)
)

summary_5
#>    rows subjects            time_min            time_max gl_min gl_max
#> 1 13866        5 2015-02-24 17:31:29 2015-06-19 08:59:36     50    400
cat("Note: The 'iglu' package is not available; vignette examples are skipped.\n")

iglu: episode_calculation

iglu::episode_calculation() identifies hypo/hyperglycemia episodes.

iglu_episodes_5 <- iglu::episode_calculation(
  data = example_data_5_subject
)
print(iglu_episodes_5)
#> # A tibble: 35 × 7
#>    id        type  level avg_ep_per_day avg_ep_duration avg_ep_gl total_episodes
#>    <fct>     <chr> <chr>          <dbl>           <dbl>     <dbl>          <dbl>
#>  1 Subject 1 hypo  lv1           0.0899            35        68.6              1
#>  2 Subject 1 hypo  lv2           0                  0        NA                0
#>  3 Subject 1 hypo  exte…         0                  0        NA                0
#>  4 Subject 1 hyper lv1           1.44              80.3     200.              16
#>  5 Subject 1 hyper lv2           0.180             30       264.               2
#>  6 Subject 1 hypo  lv1_…         0.0899            35        68.6              1
#>  7 Subject 1 hyper lv1_…         1.26              79.6     195.              14
#>  8 Subject 2 hypo  lv1           0                  0        NA                0
#>  9 Subject 2 hypo  lv2           0                  0        NA                0
#> 10 Subject 2 hypo  exte…         0                  0        NA                0
#> # ℹ 25 more rows
iglu_episodes_hall <- iglu::episode_calculation(
  data = example_data_hall
)
print(iglu_episodes_hall)
#> # A tibble: 133 × 7
#>    id        type  level avg_ep_per_day avg_ep_duration avg_ep_gl total_episodes
#>    <chr>     <chr> <chr>          <dbl>           <dbl>     <dbl>          <dbl>
#>  1 1636-69-… hypo  lv1            0.468            15        68.1              3
#>  2 1636-69-… hypo  lv2            0                 0        NA                0
#>  3 1636-69-… hypo  exte…          0                 0        NA                0
#>  4 1636-69-… hyper lv1            0.623            57.5     201.               4
#>  5 1636-69-… hyper lv2            0                 0        NA                0
#>  6 1636-69-… hypo  lv1_…          0.468            15        68.1              3
#>  7 1636-69-… hyper lv1_…          0.623            57.5     201.               4
#>  8 1636-69-… hypo  lv1            0                 0        NA                0
#>  9 1636-69-… hypo  lv2            0                 0        NA                0
#> 10 1636-69-… hypo  exte…          0                 0        NA                0
#> # ℹ 123 more rows

cgmguru: detect_all_events

all_events_5 <- detect_all_events(example_data_5_subject)
print(all_events_5)
#> $subject_summary
#> # A tibble: 5 × 22
#>   id          TIR  TITR TBR70 TBR54 TAR180 TAR250    CV    SD mean_glucose   GMI
#>   <chr>     <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl> <dbl> <dbl>        <dbl> <dbl>
#> 1 Subject 1  91.7 73.7   0.14  0      8.2    0.38  26.9  33.3         124.  6.27
#> 2 Subject 2  26.4  3.36  0     0     73.6   26.1   24.0  52.4         218.  8.54
#> 3 Subject 3  81.3 49.8   0.33  0     18.3    5.68  29.1  44.8         154.  6.99
#> 4 Subject 4  95.1 67.7   0.27  0.05   4.61   0     22.4  29.1         130.  6.41
#> 5 Subject 5  62.1 30.1   0.1   0     37.8   11.3   33.6  58.6         175.  7.49
#> # ℹ 11 more variables: uGMI <dbl>, GRI <dbl>, sensor_wear_percent <dbl>,
#> #   hypo_lv1_total_episodes <int>, hypo_lv2_total_episodes <int>,
#> #   hypo_extended_total_episodes <int>, hypo_lv1_excl_total_episodes <int>,
#> #   hyper_lv1_total_episodes <int>, hyper_lv2_total_episodes <int>,
#> #   hyper_extended_total_episodes <int>, hyper_lv1_excl_total_episodes <int>
#> 
#> $glycemic_event_summary
#> # A tibble: 40 × 6
#>    id        type  level    total_episodes avg_ep_per_day avg_minutes_below_54…¹
#>    <chr>     <chr> <chr>             <int>          <dbl>                  <dbl>
#>  1 Subject 1 hypo  lv1                   1           0.09                      0
#>  2 Subject 1 hypo  lv2                   0           0                         0
#>  3 Subject 1 hypo  extended              0           0                         0
#>  4 Subject 1 hypo  lv1_excl              1           0.09                      0
#>  5 Subject 1 hyper lv1                  16           1.44                      0
#>  6 Subject 1 hyper lv2                   2           0.18                      0
#>  7 Subject 1 hyper extended              0           0                         0
#>  8 Subject 1 hyper lv1_excl             14           1.26                      0
#>  9 Subject 2 hypo  lv1                   0           0                         0
#> 10 Subject 2 hypo  lv2                   0           0                         0
#> # ℹ 30 more rows
#> # ℹ abbreviated name: ¹​avg_minutes_below_54_per_episode
all_events_hall <- detect_all_events(example_data_hall)
print(all_events_hall)
#> $subject_summary
#> # A tibble: 19 × 22
#>    id         TIR  TITR TBR70 TBR54 TAR180 TAR250    CV    SD mean_glucose   GMI
#>    <chr>    <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl> <dbl> <dbl>        <dbl> <dbl>
#>  1 1636-69…  96.9  88.0  0.54  0      2.55   0     25.2  27.3        108.   5.9 
#>  2 1636-69…  99.6  86.5  0.17  0      0.28   0     17.5  20.1        115.   6.06
#>  3 1636-69…  99.8  97.0  0.06  0      0.17   0     14.1  15.2        108.   5.9 
#>  4 1636-69…  98.1  89.8  0.91  0      1.02   0     22.0  24.0        109.   5.91
#>  5 1636-69… 100    96.6  0     0      0      0     14.3  14.7        103.   5.78
#>  6 1636-69… 100    94.3  0     0      0      0     14.9  16.8        113.   6.02
#>  7 1636-70…  97.1  89.8  1.46  0.22   1.41   0     19.7  22.3        113.   6.01
#>  8 1636-70…  97.1  85.8  2.64  0      0.27   0     19.7  22.5        114.   6.04
#>  9 2133-004  94.3  74.7  0.73  0      5.01   0     22.6  28.7        127.   6.34
#> 10 2133-015  97.8  94.3  1.2   0      0.98   0     17.4  18.9        109.   5.91
#> 11 2133-017  99.8  91.3  0.06  0      0.11   0     18.8  20.6        110.   5.93
#> 12 2133-018  88.3  80.4  0     0     11.7    1.86  31.1  39.4        127.   6.34
#> 13 2133-019  98.4  89.7  1.44  0.06   0.11   0     21.1  22.5        107.   5.86
#> 14 2133-021  91.3  70.7  0.61  0      8.07   0     24.7  32.1        130.   6.42
#> 15 2133-024  93.8  91.0  6.15  0.55   0      0     20.1  20.0         99.4  5.69
#> 16 2133-027  94.5  93.6  5.48  0      0      0     14.7  13.4         91.1  5.49
#> 17 2133-035  99.2  95.0  0.55  0.05   0.27   0     16.6  16.9        102.   5.74
#> 18 2133-036  93.5  82.6  5.07  0      1.43   0     24.7  26.6        108.   5.88
#> 19 2133-039  95.1  87.3  4.22  0.15   0.7    0     22.8  23.7        104.   5.8 
#> # ℹ 11 more variables: uGMI <dbl>, GRI <dbl>, sensor_wear_percent <dbl>,
#> #   hypo_lv1_total_episodes <int>, hypo_lv2_total_episodes <int>,
#> #   hypo_extended_total_episodes <int>, hypo_lv1_excl_total_episodes <int>,
#> #   hyper_lv1_total_episodes <int>, hyper_lv2_total_episodes <int>,
#> #   hyper_extended_total_episodes <int>, hyper_lv1_excl_total_episodes <int>
#> 
#> $glycemic_event_summary
#> # A tibble: 152 × 6
#>    id          type  level  total_episodes avg_ep_per_day avg_minutes_below_54…¹
#>    <chr>       <chr> <chr>           <int>          <dbl>                  <dbl>
#>  1 1636-69-001 hypo  lv1                 3           0.47                      0
#>  2 1636-69-001 hypo  lv2                 0           0                         0
#>  3 1636-69-001 hypo  exten…              0           0                         0
#>  4 1636-69-001 hypo  lv1_e…              3           0.47                      0
#>  5 1636-69-001 hyper lv1                 4           0.62                      0
#>  6 1636-69-001 hyper lv2                 0           0                         0
#>  7 1636-69-001 hyper exten…              0           0                         0
#>  8 1636-69-001 hyper lv1_e…              4           0.62                      0
#>  9 1636-69-026 hypo  lv1                 0           0                         0
#> 10 1636-69-026 hypo  lv2                 0           0                         0
#> # ℹ 142 more rows
#> # ℹ abbreviated name: ¹​avg_minutes_below_54_per_episode

Speed comparison

We compare performance using microbenchmark on both datasets. Each benchmark contrasts iglu::episode_calculation() with cgmguru::detect_all_events().

library(microbenchmark)
library(iglu)

# example_data_5_subject
bench_5 <- microbenchmark(
  episode_calculation = iglu::episode_calculation(example_data_5_subject),
  detect_all_events   = cgmguru::detect_all_events(example_data_5_subject),
  times = 10,
  unit = "ms"
)
print(bench_5)
#> Unit: milliseconds
#>                 expr        min         lq       mean     median         uq
#>  episode_calculation 289.443600 292.735490 298.193008 295.067980 297.059637
#>    detect_all_events   2.922398   3.017805   3.084721   3.106119   3.162248
#>         max neval cld
#>  330.980003    10  a 
#>    3.166963    10   b

# example_data_hall (all subjects)
bench_hall <- microbenchmark(
  episode_calculation = iglu::episode_calculation(example_data_hall),
  detect_all_events   = cgmguru::detect_all_events(example_data_hall),
  times = 10,
  unit = "ms"
)
print(bench_hall)
#> Unit: milliseconds
#>                 expr        min         lq       mean     median         uq
#>  episode_calculation 827.426330 831.417106 863.768660 849.863929 900.149629
#>    detect_all_events   8.522957   8.650426   8.963736   8.834106   8.960755
#>        max neval cld
#>  902.00562    10  a 
#>   10.34889    10   b
cat("Note: Installed 'iglu' version has a different 'episode_calculation' API; iglu examples are skipped.\n")

References