Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
ddf2683
feat: add functions to remove and add impute
Gero1999 Feb 4, 2025
b8eb907
testing: add tests for interval_remove_impute
Gero1999 Feb 4, 2025
9d48e88
feat: allow PKNCAdata$intervals as a data input
Gero1999 Feb 7, 2025
7bd6bb8
fix: interval_remove_impute; remove library & return, warn if no $imp…
Gero1999 Feb 8, 2025
cad3882
refactor: interval_remove_impute / target_groups as a data.frame input
Gero1999 Feb 8, 2025
1a4b4d2
feat: interval_add_impute takes df inputs (data, targe_groups) & crea…
Gero1999 Feb 8, 2025
75f7cf1
feat: include arg allow_duplication to interval_add_impute
Gero1999 Feb 8, 2025
bee905a
fix: target_params only params changed for impute. Also keep interval…
Gero1999 Feb 9, 2025
67f7d8b
tests: refine tests for the changes in the function and add new ones
Gero1999 Feb 9, 2025
b210bfe
fix: new_rows_after_original in intervals_add_impute
Gero1999 Feb 9, 2025
d7411a1
tests: add missing test for new_rows_after_original in intervals_add_…
Gero1999 Feb 9, 2025
e0d54a4
move: test-intervals_support_funs.R to tests/testthat
Gero1999 Feb 9, 2025
c490275
style: namespace all dplyr functions
Gero1999 Feb 9, 2025
a85d816
style: remove PKNCA namespacing
Gero1999 Feb 9, 2025
51bfe48
refactor: make functions S3 methods. adjust tests for warnings/errors
Gero1999 Feb 9, 2025
dec1962
refactor: order functions in the script alphabetically
Gero1999 Feb 9, 2025
c56b61a
fix: file duplicate from previous commit
Gero1999 Feb 9, 2025
5e7ddf0
style: clean code based on code factor feedback
Gero1999 Feb 9, 2025
3e736cd
documentation: roxygenise new functions
Gero1999 Feb 9, 2025
c17ce48
documentation: add a news message in new features
Gero1999 Feb 9, 2025
dd149dc
fix: column name in intervals/PKNCAconc for tests
Gero1999 Feb 9, 2025
751a926
fix: add namespacing to dplyr functions in tests
Gero1999 Feb 9, 2025
f49e066
fix: add namespacing to all dplyr functions
Gero1999 Feb 9, 2025
d9cb492
fix: prevent a expected warning to produce an issue in tests
Gero1999 Feb 9, 2025
4feab5a
fix: example in documentation for interval_add_impute
Gero1999 Feb 9, 2025
673745e
refactor: substitute dynamic calls with dplyr & limit documentation l…
Gero1999 Feb 9, 2025
0124aa0
fix: simplify general S3 fun, remove checking tests, update news
Gero1999 Feb 10, 2025
4343e6f
refactor: interval_add_impute / substitute dplyr, removed unwanted args
Gero1999 Feb 11, 2025
26d2e74
tests: interval_add_impute adapted to new error messages and defaults
Gero1999 Feb 11, 2025
8db55b2
fix, refactor: consider NA params, change PKNCAdata$impute strategy, …
Gero1999 Feb 12, 2025
7c6077b
refactor: substitute Vectorize fun with Bill's fun (test: returns "" …
Gero1999 Feb 12, 2025
cfd2bad
fix: typpo in substituted fun add_impute_method
Gero1999 Feb 12, 2025
84e1dd4
documentation: update manuals interval_add_impute & interval_remove_i…
Gero1999 Feb 12, 2025
29d9a6e
documentation: create manuals for add_impute_method & remove_impute_m…
Gero1999 Feb 12, 2025
9217ac6
fix: solve example typpo/args, refactor class evaluation, update manuals
Gero1999 Feb 12, 2025
a89ee52
fix, tests: no matching interval & add_impute when method is already …
Gero1999 Feb 15, 2025
56bebd9
documentation: roxygenise
Gero1999 Feb 15, 2025
f012d74
fix: remove redundant conditional in the function
Gero1999 Feb 15, 2025
d3d13f8
test: add helper functions tests for code coverage
Gero1999 Feb 15, 2025
b9747e5
documentation: solve news warning-issue in subtitle
Gero1999 Feb 15, 2025
23ba77d
documentation, fix: document ... argument & improve missing impute case
Gero1999 Feb 15, 2025
6d27838
fix: consider test also for data.frame with missing impute column
Gero1999 Feb 15, 2025
e952d6a
update: new developed funs
Gero1999 Mar 29, 2025
a1c91fe
refactor: remove PKNCA namespace
Gero1999 Mar 29, 2025
672a199
fix: use NA instead of FALSE for intervals parameter columns
Gero1999 Mar 29, 2025
8b876d2
update: improved tests using describe and it
Gero1999 Mar 29, 2025
3a58074
documentation: roxygenise
Gero1999 Mar 29, 2025
c16ebaf
lintr: remove trailing whitespaces
Gero1999 Mar 29, 2025
6174adf
rename: intervals_support_funs > intervals_support
Gero1999 Mar 29, 2025
7df5761
Merge branch 'main' into 379-interval_support_functions
Gero1999 Mar 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 244 additions & 0 deletions R/intervals_support_funs.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
# Load necessary library
library(dplyr)
Comment thread
Gero1999 marked this conversation as resolved.
Outdated

#' Remove specified imputation methods from the intervals in a PKNCAdata object.
#'
#' @param data A PKNCAdata object containing the intervals and data components.
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
#' @param target_impute A character string specifying the imputation method to be removed.
#' @param target_params A character vector specifying the parameters to be targeted (optional). If missing, all TRUE in the intervals are taken.
#' @param target_groups A named list specifying the intervals to be targeted (optional). If missing, all relevant groups are considered.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the concept of how you've implemented this. Please make this into a data.frame so that it can work more simply with the way people are accustomed to working with intervals.

Copy link
Copy Markdown
Contributor Author

@Gero1999 Gero1999 Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey data will also be the intervals dataframe. I guess in this case we cannot guess the impute column always, sobwould need another arg

Indeed I think using a dataframe as an input would make a lot of sense also to match the intervals for the target_groups arg, which we can call instead something like target_intervals. Here is then an example:

If this is my initial interval table:

USUBJID ANALYTE cmax tmax aucinf.pred impute
001 Analyte1 TRUE TRUE TRUE start_predose

I would then like to remove only for cmax and tmax the imputation, while keeping it for the other parameters:

interval_remove_impute(PKNCAdata$intervals,
                       target_impute = "start_predose",
                       target_params = c("cmax", "tmax"),
                       target_intervals = data.frame(ANALYTE="Analyte1") )

This produces:

USUBJID ANALYTE cmax tmax aucinf.pred impute
001 Analyte1 FALSE FALSE TRUE start_predose
001 Analyte1 TRUE TRUE FALSE NA

That way we keep it intuitive: target_intervals indicates the rows to be considered (even if it can also contain parameter or impute specifications) while target_params the columns for which the removal applies.

#' @return A modified PKNCAdata object with the specified imputation methods removed from the targeted intervals.
#' @examples
#' d_conc <- data.frame(
#' conc = c(1, 0.6, 0.2, 0.1, 0.9, 0.4, 1.2, 0.8, 0.3, 0.2, 1.1, 0.5),
#' time = rep(0:5, 2),
#' analyte = rep(c("Analyte1", "Analyte2"), each = 6),
#' include_hl = c(FALSE, NA, TRUE, TRUE, TRUE, TRUE, FALSE, NA, TRUE, TRUE, TRUE, TRUE)
#' )
#'
#' d_dose <- data.frame(
#' dose = c(100, 200),
#' time = c(0, 0),
#' treatment = c("A", "B"),
#' ID = c(1, 2)
#' )
#'
#' o_conc <- PKNCAconc(d_conc, conc ~ time | analyte, include_half.life = "include_hl")
#' o_dose <- PKNCAdose(d_dose, dose ~ time | treatment + ID)
#'
#' intervals <- data.frame(
#' start = c(0, 0, 0),
#' end = c(24, 48, Inf),
#' half.life = c(TRUE, FALSE, TRUE),
#' impute = c("start_conc0,start_predose", "start_predose", "start_conc0"),
#' ANALYTE = c("Analyte1", "Analyte2", "Analyte1"),
#' ROUTE = c("intravascular", "oral", "intravascular")
#' )
#'
#' o_data <- PKNCAdata(o_conc, o_dose, intervals = intervals)
#'
#' # Apply interval_remove_impute function
#' o_data <- interval_remove_impute(o_data, target_impute = "start_conc0", target_params = c("half.life"), target_groups = list(ANALYTE = "Analyte1", ROUTE = "intravascular"))
#'
#' # Print updated intervals
#' print("Updated intervals:")
#' print(o_data$intervals)
#'
#' @export
interval_remove_impute <- function(data, target_impute, target_params = NULL, target_groups = NULL) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make the function S3 generic with methods for PKNCAdata and data.frame. Then, please make the PKNCAdata method use the data.frame method.

# Validate the input
if (missing(data) || missing(target_impute)) {
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
stop("Both 'data' and 'target_impute' must be provided.")
}

if (!("intervals" %in% names(data)) || !("PKNCAdata" %in% class(data))) {
stop("'data' object must be a PKNCAdata object with 'intervals' and 'data' components.")
}

if (!is.character(target_impute)) {
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
stop("'target_impute' must be a character string.")
}

# Get all parameter column names in the PKNCAdata object
all_param_options <- names(sapply(PKNCA.options()$single.dose.aucs, is.logical))
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
logical_cols <- names(which(colSums(data$intervals[sapply(data$intervals, is.logical)]) > 1))
param_cols <- intersect(logical_cols, all_param_options)

# Handle target_params
if (is.null(target_params)) {
# Take all logical columns in data$intervals that are known parameters
target_params <- param_cols
} else {
# Check that all target_params are logical columns in data$intervals and known parameters
missing_params <- setdiff(target_params, param_cols)
if (length(missing_params) > 0) {
stop("The following target_params are not interval columns and/or known PKNCA parameters: ", paste(missing_params, collapse = ", "))
target_params <- intersect(target_params, param_cols)
}
}

# Determine the name of the impute column
impute_col <- if (!is.na(data$impute)) {
data$impute
} else if ("impute" %in% colnames(data$intervals)) {
"impute"
} else {
stop("The 'data$intervals' object must contain an impute column either defined in the PKNCAdata object or called `impute`.")
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
}

# Identify the targeted intervals to which the action is applied
mask_target_rows <- data$intervals %>%
mutate(
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
is.in.groups = if (!is.null(target_groups)) rowSums(across(all_of(names(target_groups)), ~ . %in% target_groups)) == length(target_groups) else TRUE,
is.in.params = rowSums(across(any_of(target_params), ~ . == TRUE)) > 0,
is.in.impute = grepl(
pattern = paste0(".*(", paste0(target_impute, collapse = ")|("), ").*"),
.data[[impute_col]]
),
target_rows = is.in.groups & is.in.params & is.in.impute
) %>%
pull(target_rows)

# Create the new version intervals for the target parameters
new_intervals_without_impute <- data$intervals %>%
filter(mask_target_rows) %>%
mutate(across(any_of(param_cols), ~FALSE)) %>%
mutate(across(any_of(target_params), ~TRUE)) %>%
rowwise() %>%
mutate(!!impute_col := paste0(setdiff(unlist(strsplit(.data[[impute_col]], ",")), target_impute),
collapse = ","
)) %>%
mutate(!!impute_col := ifelse(.data[[impute_col]] == "", NA_character_, .data[[impute_col]])) %>%
ungroup() %>%
as.data.frame()

# Make parameters FALSE in target intervals
data$intervals[mask_target_rows, target_params] <- FALSE

# Combine and remove intervals where all logical parameter columns are FALSE
data$intervals <- rbind(data$intervals, new_intervals_without_impute) %>%
filter(rowSums(across(any_of(param_cols), as.numeric)) > 0)

return(data)
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
}



# Now create an alternative function that adds imputations to the intervals
#' Add specified imputation methods to the intervals in a PKNCAdata object.
#'
#' @param data A PKNCAdata object containing the intervals and data components.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use @inheritParams where possible.

#' @param target_impute A character string specifying the imputation method to be added.
#' @param after Numeric value specifying the position after which the imputation method should be added (optional). First is 0, last Inf. If missing, the imputation method is added at the end (Inf).
#' @param target_params A character vector specifying the parameters to be targeted (optional). If missing, all TRUE in the intervals are taken.
#' @param target_groups A named list specifying the intervals to be targeted (optional). If missing, all relevant groups are considered.
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
#' @return A modified PKNCAdata object with the specified imputation methods added to the targeted intervals.
#' @examples
#' d_conc <- data.frame(
#' conc = c(1, 0.6, 0.2, 0.1, 0.9, 0.4, 1.2, 0.8, 0.3, 0.2, 1.1, 0.5),
#' time = rep(0:5, 2),
#' analyte = rep(c("Analyte1", "Analyte2"), each = 6),
#' include_hl = c(FALSE, NA, TRUE, TRUE, TRUE, TRUE, FALSE, NA, TRUE, TRUE, TRUE, TRUE)
#' )
#'
#' d_dose <- data.frame(
#' dose = c(100, 200),
#' time = c(0, 0),
#' treatment = c("A", "B"),
#' ID = c(1, 2)
#' )
#'
#' o_conc <- PKNCAconc(d_conc, conc ~ time | analyte, include_half.life = "include_hl")
#' o_dose <- PKNCAdose(d_dose, dose ~ time | treatment + ID)
#'
#' intervals <- data.frame(
#' start = c(0, 0, 0),
#' end = c(24, 48, Inf),
#' half.life = c(TRUE, FALSE, TRUE),
#' impute = c("start_conc0,start_predose", "start_predose", "start_conc0"),
#' ANALYTE = c("Analyte1", "Analyte2", "Analyte1"),
#' ROUTE = c("intravascular", "oral", "intravascular")
#' )
#'
#' o_data <- PKNCAdata(o_conc, o_dose, intervals = intervals)
#'
#' # Apply interval_add_impute function
#' o_data <- interval_add_impute(o_data, target_impute = "start_conc0", target_params = c("half.life"), target_groups = list(ANALYTE = "Analyte1", ROUTE = "intravascular"))
#'
#' # Print updated intervals
#' print("Updated intervals:")
#' print(o_data$intervals)
#'
#' @export
interval_add_impute <- function(data, target_impute, after = Inf, target_params = NULL, target_groups = NULL) {
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
# Validate the input
if (missing(data) || missing(target_impute)) {
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
stop("Both 'data' and 'target_impute' must be provided.")
}

if (!("intervals" %in% names(data)) || !("PKNCAdata" %in% class(data))) {
stop("'data' object must be a PKNCAdata object with 'intervals' and 'data' components.")
}

if (!is.character(target_impute)) {
stop("'target_impute' must be a character string.")
}

# Get all parameter column names in the PKNCAdata object
all_param_options <- names(sapply(PKNCA.options()$single.dose.aucs, is.logical))
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
logical_cols <- names(which(colSums(data$intervals[sapply(data$intervals, is.logical)]) > 1))
param_cols <- intersect(logical_cols, all_param_options)

# Handle target_params
if (is.null(target_params)) {
# Take all logical columns in data$intervals that are known parameters
target_params <- param_cols
} else {
# Check that all target_params are logical columns in data$intervals and known parameters
missing_params <- setdiff(target_params, param_cols)
if (length(missing_params) > 0) {
stop("The following target_params are not interval columns and/or known PKNCA parameters: ", paste(missing_params, collapse = ", "))
target_params <- intersect(target_params, param_cols)
}
}

# Determine the name of the impute column
impute_col <- if (!is.na(data$impute)) {
data$impute
} else if ("impute" %in% colnames(data$intervals)) {
"impute"
} else {
stop("The 'data$intervals' object must contain an impute column either defined in the PKNCAdata object or called `impute`.")
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
}

# Identify the targeted intervals to which the action is applied
mask_target_rows <- data$intervals %>%
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
mutate(
is.in.groups = if (!is.null(target_groups)) rowSums(across(all_of(names(target_groups)), ~ . %in% target_groups)) == length(target_groups) else TRUE,
is.in.params = rowSums(across(any_of(target_params), ~ . == TRUE)) > 0,
target_rows = is.in.groups & is.in.params
) %>%
pull(target_rows)

# Add the imputation method to the targeted intervals
new_intervals_with_impute <- data$intervals %>%
filter(mask_target_rows) %>%
mutate(across(any_of(param_cols), ~FALSE)) %>%
mutate(across(any_of(target_params), ~TRUE)) %>%
rowwise() %>%
mutate(!!impute_col := {
impute_methods <- unlist(strsplit(ifelse(is.na(.data[[impute_col]]), "", .data[[impute_col]]), ","))
impute_methods <- append(impute_methods, target_impute, after)
paste(unique(impute_methods[impute_methods != ""]), collapse = ",")
}) %>%
as.data.frame()

# Set to FALSE all target parameters in the target intervals
data$intervals[mask_target_rows, target_params] <- FALSE

# Combine and remove intervals where all logical parameter columns are FALSE
data$intervals <- rbind(data$intervals, new_intervals_with_impute) %>%
filter(rowSums(across(any_of(param_cols), as.numeric)) > 0)

return(data)
}
140 changes: 140 additions & 0 deletions R/test-intervals_support_funs.R
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
library(testthat)
Comment thread
Gero1999 marked this conversation as resolved.
Outdated
library(PKNCA)

# Source the function file if it's not already in the environment
# source("path/to/your/function_file.R")

# Create sample data for testing
d_conc <- data.frame(
conc = c(1, 0.6, 0.2, 0.1, 0.9, 0.4, 1.2, 0.8, 0.3, 0.2, 1.1, 0.5),
time = rep(0:5, 2),
analyte = rep(c("Analyte1", "Analyte2"), each = 6),
id = 1,
include_hl = c(FALSE, NA, TRUE, TRUE, TRUE, TRUE, FALSE, NA, TRUE, TRUE, TRUE, TRUE)
)

d_dose <- data.frame(
dose = c(100, 200),
time = c(0, 2.5),
id = 1
)

intervals <- data.frame(
start = c(0, 0, 0),
end = c(24, 48, Inf),
half.life = c(TRUE, TRUE, TRUE),
cmax = c(TRUE, TRUE, TRUE),
impute = c("start_conc0,start_predose", "start_predose", "start_conc0"),
id = 1,
analyte = c("Analyte1", "Analyte2", "Analyte1")
)

o_conc <- PKNCAconc(d_conc, conc ~ time | id / analyte, include_half.life = "include_hl")
o_dose <- PKNCAdose(d_dose, dose ~ time | id)
o_data <- PKNCAdata(o_conc, o_dose, intervals = intervals)

# Test cases with unexpected inputs

test_that("interval_remove_impute throws an error if either data or target_impute is missing", {
expect_error(interval_remove_impute(), "Both 'data' and 'target_impute' must be provided.")
expect_error(interval_remove_impute(o_data), "Both 'data' and 'target_impute' must be provided.")
expect_error(interval_remove_impute(target_impute = "start_conc0"), "Both 'data' and 'target_impute' must be provided.")
})

test_that("interval_remove_impute throws an error for non-character target_impute", {
expect_error(interval_remove_impute(o_data, target_impute = 123), "'target_impute' must be a character string.")
})

test_that("interval_remove_impute throws an error when input data is a non PKNCAdata object or has no intervals", {
expect_error(interval_remove_impute(o_data$conc, target_impute = "start_conc0"), "'data' object must be a PKNCAdata object with 'intervals' and 'data' components.")
o_data_no_intervals <- PKNCAdata(o_conc, o_dose)
o_data_no_intervals$intervals <- NULL
expect_error(interval_remove_impute(o_data_no_intervals, target_impute = "start_conc0"), "'data' object must be a PKNCAdata object with 'intervals' and 'data' components.")
})

test_that("interval_remove_impute throws an error for unknown target_params", {
expect_error(interval_remove_impute(o_data, target_impute = "start_conc0", target_params = c("unknown_param")),
"The following target_params are not interval columns and/or known PKNCA parameters: unknown_param")
})

test_that("interval_remove_impute handles impute column with different names", {
o_data_changed_impute_name <- o_data
o_data_changed_impute_name$impute <- "impute_col"
o_data_changed_impute_name$intervals <- o_data_changed_impute_name$intervals %>% rename(impute_col = impute)
result <- interval_remove_impute(o_data_changed_impute_name, target_impute = "start_conc0")
expect_equal(result$intervals %>% select(analyte, half.life, cmax, impute_col),
data.frame(analyte = c("Analyte2", "Analyte1", "Analyte1"),
half.life = c(TRUE, TRUE, TRUE),
cmax = c(TRUE, TRUE, TRUE),
impute_col = c("start_predose", "start_predose", NA)))
})

test_that("interval_remove_impute handles impute column with NA values correctly", {
o_data_with_na_impute <- o_data
o_data_with_na_impute$intervals <- o_data_with_na_impute$intervals %>% mutate(impute = NA_character_)
result <- interval_remove_impute(o_data_with_na_impute, target_impute = "start_conc0")
expect_equal(result$intervals %>% select(analyte, half.life, cmax, impute),
data.frame(analyte = c("Analyte1", "Analyte2", "Analyte1"),
half.life = c(TRUE, TRUE, TRUE),
cmax = c(TRUE, TRUE, TRUE),
impute = c(NA_character_, NA_character_, NA_character_)))
})


# Test intervals for expected outputs with different inputs

test_that("interval_remove_impute with no optional parameters uses all relevant cases, with new intervals below", {
result <- interval_remove_impute(o_data, target_impute = "start_conc0")
expect_equal(result$intervals %>% select(analyte, half.life, cmax, impute),
data.frame(analyte = c("Analyte2", "Analyte1", "Analyte1"),
half.life = c(TRUE, TRUE, TRUE),
cmax = c(TRUE, TRUE, TRUE),
impute = c("start_predose", "start_predose", NA)))
})

test_that("interval_remove_impute handles specified target_params correctly", {
result <- interval_remove_impute(o_data, target_impute = "start_conc0", target_params = c("half.life"))
# half.life has no start_conc0 imputations
expect_equal(result$intervals %>% filter(half.life) %>% select(analyte, half.life, impute),
data.frame(analyte = c("Analyte2", "Analyte1", "Analyte1"),
half.life = c(TRUE, TRUE, TRUE),
impute = c("start_predose", "start_predose", NA)))
# cmax has the same exact imputations as before
expect_equal(result$intervals %>% filter(cmax) %>% select(analyte, cmax, impute),
o_data$intervals %>% filter(cmax) %>% select(analyte, cmax, impute))
})

test_that("interval_remove_impute handles target_groups correctly", {
result <- interval_remove_impute(o_data, target_impute = "start_conc0", target_groups = list(analyte = "Analyte1"))
# Analyte1 has no start_conc0 imputations
expect_equal(result$intervals %>% filter(analyte == "Analyte1") %>% select(analyte, half.life, cmax, impute),
data.frame(analyte = c("Analyte1", "Analyte1"),
half.life = c(TRUE, TRUE),
cmax = c(TRUE, TRUE),
impute = c("start_predose", NA_character_)))

# Analyte2 has the same exact imputations as before
expect_equal(result$intervals %>% filter(analyte == "Analyte2") %>% select(analyte, half.life, cmax, impute),
o_data$intervals %>% filter(analyte == "Analyte2") %>% select(analyte, half.life, cmax, impute))
})

test_that("interval_remove_impute handles multiple target_params correctly", {
result <- interval_remove_impute(o_data, target_impute = "start_conc0", target_params = c("half.life", "cmax"))
expect_equal(result$intervals %>% select(analyte, half.life, cmax, impute),
data.frame(analyte = c("Analyte2", "Analyte1", "Analyte1"),
half.life = c(TRUE, TRUE, TRUE),
cmax = c(TRUE, TRUE, TRUE),
impute = c("start_predose", "start_predose", NA)))
})

test_that("interval_remove_impute handles with specifity impute character metod with multiple imputes", {
o_data_multiple_imputes <- o_data
o_data_multiple_imputes$intervals <- o_data_multiple_imputes$intervals %>% mutate(impute = "start_conc0,start_predose")
result <- interval_remove_impute(o_data_multiple_imputes, target_impute = "start_conc0")
expect_equal(result$intervals %>% select(analyte, half.life, cmax, impute),
data.frame(analyte = c("Analyte1", "Analyte2", "Analyte1"),
half.life = c(TRUE, TRUE, TRUE),
cmax = c(TRUE, TRUE, TRUE),
impute = c("start_predose", "start_predose", "start_predose")))
})