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)
#> $events_long_df
#> # A tibble: 40 × 6
#>    id        type  level    event_count avg_ep_per_day avg_episode_duration_be…¹
#>    <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_episode_duration_below_54
#> 
#> $summary_df
#> # 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…  91.8 74.0  0.156 0        8.08  0.375 0.267  33.0         123.  6.26
#> 2 Subject…  25.8  3.28 0     0       74.2  26.5   0.241  52.7         219.  8.54
#> 3 Subject…  81.3 49.8  0.316 0       18.4   5.44  0.290  44.5         154.  6.98
#> 4 Subject…  94.9 67.4  0.326 0.0271   4.75  0     0.224  29.0         130.  6.41
#> 5 Subject…  62.0 29.6  0.102 0       37.9  11.5   0.335  58.4         175.  7.49
#> # ℹ 11 more variables: uGMI <dbl>, GRI <dbl>, sensor_wear <dbl>,
#> #   hypo_lv1_event_count <int>, hypo_lv2_event_count <int>,
#> #   hypo_extended_event_count <int>, hypo_lv1_excl_event_count <int>,
#> #   hyper_lv1_event_count <int>, hyper_lv2_event_count <int>,
#> #   hyper_extended_event_count <int>, hyper_lv1_excl_event_count <int>
all_events_hall <- detect_all_events(example_data_hall)
print(all_events_hall)
#> $events_long_df
#> # A tibble: 152 × 6
#>    id          type  level    event_count avg_ep_per_day avg_episode_duration_…¹
#>    <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  extended           0           0                          0
#>  4 1636-69-001 hypo  lv1_excl           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 extended           0           0                          0
#>  8 1636-69-001 hyper lv1_excl           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_episode_duration_below_54
#> 
#> $summary_df
#> # 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-6…  96.8  87.4 0.703 0       2.54    0    0.252  27.2        108.   5.90
#>  2 1636-6…  99.6  86.4 0.110 0       0.329   0    0.173  19.9        115.   6.06
#>  3 1636-6…  99.7  96.9 0.112 0       0.168   0    0.140  15.1        108.   5.90
#>  4 1636-6…  97.8  89.4 0.901 0       1.27    0    0.222  24.3        109.   5.92
#>  5 1636-6… 100    96.6 0     0       0       0    0.141  14.6        103.   5.78
#>  6 1636-6… 100    94.4 0     0       0       0    0.148  16.7        113.   6.02
#>  7 1636-7…  97.2  89.4 1.50  0.214   1.34    0    0.196  22.1        113.   6.01
#>  8 1636-7…  96.9  85.3 2.82  0       0.325   0    0.197  22.5        114.   6.03
#>  9 2133-0…  94.0  73.8 0.898 0       5.11    0    0.226  28.6        127.   6.34
#> 10 2133-0…  97.7  94.0 1.17  0       1.17    0    0.176  19.2        109.   5.92
#> 11 2133-0…  99.8  91.3 0     0       0.164   0    0.187  20.4        110.   5.93
#> 12 2133-0…  88.3  80.2 0     0      11.7     1.85 0.311  39.3        127.   6.34
#> 13 2133-0…  98.5  89.5 1.42  0.0548  0.110   0    0.210  22.4        107.   5.86
#> 14 2133-0…  91.1  70.5 0.665 0       8.26    0    0.247  32.1        130.   6.42
#> 15 2133-0…  93.3  90.5 6.68  0.657   0       0    0.202  20.0         99.3  5.69
#> 16 2133-0…  94.6  93.7 5.42  0       0       0    0.146  13.3         91.1  5.49
#> 17 2133-0…  99.3  95.0 0.421 0.0527  0.316   0    0.165  16.8        102.   5.74
#> 18 2133-0…  92.9  81.0 5.70  0       1.39    0    0.249  26.8        108.   5.89
#> 19 2133-0…  94.7  86.9 4.56  0.138   0.738   0    0.229  23.9        104.   5.81
#> # ℹ 11 more variables: uGMI <dbl>, GRI <dbl>, sensor_wear <dbl>,
#> #   hypo_lv1_event_count <int>, hypo_lv2_event_count <int>,
#> #   hypo_extended_event_count <int>, hypo_lv1_excl_event_count <int>,
#> #   hyper_lv1_event_count <int>, hyper_lv2_event_count <int>,
#> #   hyper_extended_event_count <int>, hyper_lv1_excl_event_count <int>

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 288.468743 294.080659 299.54513 296.002329 299.337023
#>    detect_all_events   3.086931   3.112187   3.25153   3.228586   3.386518
#>         max neval cld
#>  333.061901    10  a 
#>    3.497997    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 811.18824 843.066190 861.301133 863.023698 882.685638
#>    detect_all_events   8.85887   8.902699   9.163725   8.966065   9.091832
#>        max neval cld
#>  891.88222    10  a 
#>   10.53282    10   b
cat("Note: Installed 'iglu' version has a different 'episode_calculation' API; iglu examples are skipped.\n")

References