From 6a5646bbcdb7eab6431b31609afa227d0c00bb8c Mon Sep 17 00:00:00 2001 From: neokok Date: Tue, 17 Jun 2025 11:13:02 -0400 Subject: [PATCH 1/3] Update MAG function --- DESCRIPTION | 2 +- NEWS.md | 3 +++ R/mag.R | 13 ++++++------- man/mag.Rd | 5 ++--- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 79e267e3..edfc4804 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: iglu Type: Package Title: Interpreting Glucose Data from Continuous Glucose Monitors -Version: 4.2.3 +Version: 4.3.0 Authors@R: c(person("Elizabeth", "Chun", role = c("aut")), person("Steve", "Broll", diff --git a/NEWS.md b/NEWS.md index bfdf0c8f..84b1a2d2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,6 @@ +# iglu 4.3.0 +* Updated MAG computation in the presence of large missing data + # iglu 4.2.3 * Fixed GVP output for iglu::all_metrics diff --git a/R/mag.R b/R/mag.R index 2bbe8548..7882b312 100644 --- a/R/mag.R +++ b/R/mag.R @@ -22,9 +22,8 @@ #' The glucose values are linearly interpolated over a time grid starting at the #' beginning of the first day of data and ending on the last day of data. Then, MAG #' is calculated as \eqn{\frac{|\Delta G|}{\Delta t}} where \eqn{|\Delta G|} is -#' the sum of the absolute change in glucose calculated for each interval as specified -#' by n, default n = 60 for hourly change in glucose. The sum is then divided by -#' \eqn{\Delta t} which is the total time in hours. +#' the sum of the absolute change in glucose. The sum is then divided by \eqn{\Delta t}, +#' the total number of n-minute intervals (default n = 60 for hourly change). #' #' @author Elizabeth Chun #' @@ -54,10 +53,10 @@ mag <- function (data, n = 60L, dt0 = NULL, inter_gap = 45, tz = "") { n <- dt0 } - idx = seq(1, ncol(data_ip[[1]]), by = round(n/data_ip[[3]])) - idx_gl = as.vector(t(data_ip[[1]][, idx])) - mag = sum(abs(diff(idx_gl)), na.rm = TRUE)/ - (length(na.omit(idx_gl))*n/60) + diffs = diff(as.vector(t(data_ip[[1]]))) + total_time = (length(na.omit(diffs))*dt0)/n + mag = sum(abs(diffs), na.rm = TRUE)/total_time + return(mag) } diff --git a/man/mag.Rd b/man/mag.Rd index 45df5bec..41299493 100644 --- a/man/mag.Rd +++ b/man/mag.Rd @@ -31,9 +31,8 @@ returned. The glucose values are linearly interpolated over a time grid starting at the beginning of the first day of data and ending on the last day of data. Then, MAG is calculated as \eqn{\frac{|\Delta G|}{\Delta t}} where \eqn{|\Delta G|} is -the sum of the absolute change in glucose calculated for each interval as specified -by n, default n = 60 for hourly change in glucose. The sum is then divided by -\eqn{\Delta t} which is the total time in hours. +the sum of the absolute change in glucose. The sum is then divided by \eqn{\Delta t}, +the total number of n-minute intervals (default n = 60 for hourly change). } \examples{ From 04f71625eb5a789e91fe55276e63e7a192b1796b Mon Sep 17 00:00:00 2001 From: neokok Date: Thu, 3 Jul 2025 17:03:44 -0400 Subject: [PATCH 2/3] Updated MAG computation in the presence of large missing data --- DESCRIPTION | 2 ++ R/mag.R | 46 ++++++++++++++++++++++++++++++++++------------ man/mag.Rd | 19 +++++++++++++------ 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 486bb88c..1d52f5d2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -34,6 +34,8 @@ Authors@R: c(person("Elizabeth", "Chun", role = c("ctb")), person("Nhan", "Nguyen", role = c("ctb")), + person("Neo", "Kok", + role = c("ctb")), person("Irina", "Gaynanova", email = "irinagn@umich.edu",role = c("aut", "cre"), comment = c(ORCID = "0000-0002-4116-0268"))) diff --git a/R/mag.R b/R/mag.R index 7882b312..79f5fe7a 100644 --- a/R/mag.R +++ b/R/mag.R @@ -4,10 +4,11 @@ #' The function mag calculates the mean absolute glucose or MAG. #' #' @usage -#' mag(data, n = 60, dt0 = NULL, inter_gap = 45, tz = "") +#' mag(data, n = NULL, dt0 = NULL, inter_gap = 45, tz = "") #' #' @param n Integer giving the desired interval in minutes over which to calculate -#' the change in glucose. Default is 60 to have hourly (60 minutes) intervals. +#' the change in glucose. Default is the CGM meter's frequency (dt0) +#' to measure change in every reading. #' #' @inheritParams roc #' @@ -22,17 +23,24 @@ #' The glucose values are linearly interpolated over a time grid starting at the #' beginning of the first day of data and ending on the last day of data. Then, MAG #' is calculated as \eqn{\frac{|\Delta G|}{\Delta t}} where \eqn{|\Delta G|} is -#' the sum of the absolute change in glucose. The sum is then divided by \eqn{\Delta t}, -#' the total number of n-minute intervals (default n = 60 for hourly change). +#' the sum of the absolute change in glucose per n-minute interval (default n = dt0). +#' The sum is then divided by \eqn{\Delta t}, the total elapsed time (in hours), +#' yieldng the Mean Absolute change in Glucose (mg/dL per hour). #' -#' @author Elizabeth Chun +#' @author Elizabeth Chun, Neo Kok #' #' @references #' Hermanides et al. (2010) Glucose Variability is Associated with Intensive Care Unit -#' Mortaility, +#' Mortality, #' \emph{Critical Care Medicine} \strong{38(3)} 838-842, #' \doi{10.1097/CCM.0b013e3181cc4be9} #' +#' Kohnert et al. (2013) Evaluation of the Mean Absolute Glucose Change as a Measure +#' of Glycemic Variability Using Continuous Glucose Monitoring Data, +#' \emph{Diabetes Technol Ther.} \strong{15(6)} 448-454, +#' \doi{10.1089/dia.2012.0303} +#' +#' #' @examples #' #' data(example_data_1_subject) @@ -42,20 +50,34 @@ #' mag(example_data_5_subject) #' -mag <- function (data, n = 60L, dt0 = NULL, inter_gap = 45, tz = "") { +mag <- function (data, n = NULL, dt0 = NULL, inter_gap = 45, tz = "") { mag_single <- function (data) { data_ip = CGMS2DayByDay(data, dt0 = dt0, inter_gap = inter_gap, tz = tz) dt0 <- data_ip[[3]] - if (n < dt0) { + + if(is.null(n)) { + n <- dt0 + } else if (n < dt0) { message(paste("Parameter n cannot be less than the data collection frequency: " , dt0, " , function will be evaluated with n = ", dt0, sep = "")) n <- dt0 + } else if (n %% dt0 != 0){ + new_n <- round(n/dt0) * dt0 + message(paste("Parameter n must be a multiple of the data collection frequency: ", + dt0, " , function will be evaluated with n = ", new_n, sep = "")) + n <- new_n } - diffs = diff(as.vector(t(data_ip[[1]]))) - total_time = (length(na.omit(diffs))*dt0)/n - mag = sum(abs(diffs), na.rm = TRUE)/total_time + step_cols <- n / dt0 + + flat_gl = as.vector(t(data_ip[[1]])) + idx <- seq(1, length(flat_gl), by = step_cols) + idx_gl = flat_gl[idx] + diffs = na.omit(diff(idx_gl)) + + mag = sum(abs(diffs)) / + (length(diffs) * (n/60)) return(mag) } @@ -64,7 +86,7 @@ mag <- function (data, n = 60L, dt0 = NULL, inter_gap = 45, tz = "") { rm(list = c("id", "mag")) data = check_data_columns(data) - if (!is.integer(n)) { + if (!is.integer(n) && !is.null(n)) { n <- round(n) message("Parameter n must be an integer, input has been rounded to nearest integer") diff --git a/man/mag.Rd b/man/mag.Rd index 41299493..8b65b8a8 100644 --- a/man/mag.Rd +++ b/man/mag.Rd @@ -4,13 +4,14 @@ \alias{mag} \title{Calculate the Mean Absolute Glucose (MAG)} \usage{ -mag(data, n = 60, dt0 = NULL, inter_gap = 45, tz = "") +mag(data, n = NULL, dt0 = NULL, inter_gap = 45, tz = "") } \arguments{ \item{data}{DataFrame object with column names "id", "time", and "gl".} \item{n}{Integer giving the desired interval in minutes over which to calculate -the change in glucose. Default is 60 to have hourly (60 minutes) intervals.} +the change in glucose. Default is the CGM meter's frequency (dt0) +to measure change in every reading.} \item{dt0}{The time frequency for interpolation in minutes, the default will match the CGM meter's frequency (e.g. 5 min for Dexcom).} @@ -31,8 +32,9 @@ returned. The glucose values are linearly interpolated over a time grid starting at the beginning of the first day of data and ending on the last day of data. Then, MAG is calculated as \eqn{\frac{|\Delta G|}{\Delta t}} where \eqn{|\Delta G|} is -the sum of the absolute change in glucose. The sum is then divided by \eqn{\Delta t}, -the total number of n-minute intervals (default n = 60 for hourly change). +the sum of the absolute change in glucose per n-minute interval (default n = dt0). +The sum is then divided by \eqn{\Delta t}, the total elapsed time (in hours), +yieldng the Mean Absolute change in Glucose (mg/dL per hour). } \examples{ @@ -45,10 +47,15 @@ mag(example_data_5_subject) } \references{ Hermanides et al. (2010) Glucose Variability is Associated with Intensive Care Unit -Mortaility, +Mortality, \emph{Critical Care Medicine} \strong{38(3)} 838-842, \doi{10.1097/CCM.0b013e3181cc4be9} + +Kohnert et al. (2013) Evaluation of the Mean Absolute Glucose Change as a Measure +of Glycemic Variability Using Continuous Glucose Monitoring Data, +\emph{Diabetes Technol Ther.} \strong{15(6)} 448-454, +\doi{10.1089/dia.2012.0303} } \author{ -Elizabeth Chun +Elizabeth Chun, Neo Kok } From 0f1b5090d643b7ec782ff71444210aa59e4bc28c Mon Sep 17 00:00:00 2001 From: neokok Date: Fri, 11 Jul 2025 00:23:48 -0400 Subject: [PATCH 3/3] Updated MAG computation in the presence of large missing data --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index 84b1a2d2..d45be991 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # iglu 4.3.0 * Updated MAG computation in the presence of large missing data +* Default MAG now calculates differences at the CGM frequency rather than hourly # iglu 4.2.3 * Fixed GVP output for iglu::all_metrics