Nothing
#' Prefilter tracers and clean raw or summary source datasets
#'
#' Evaluates source samples and removes rows that exceed user-defined thresholds for missing isotopic ratios or missing/zero elemental contents. Absolute zeros
#' in content columns are treated as analytically missing data and are actively converted to NAs to prevent downstream statistical bias. The mixture row
#' (assumed to be the last row) is always preserved.
#'
#' @param data Data frame containing source and mixture samples. Supports raw and averaged formats.
#' @param max_na_ratio Numeric. Maximum allowable proportion of missing ratio values per row (0 to 1). Default 0.30.
#' @param max_zero_content Numeric. Maximum allowable proportion of missing or zero content values per row (0 to 1). Default 0.30.
#'
#' @return A cleaned data frame with failing source rows removed and zeros in content columns converted to NAs.
#' @export
prefilter_tracers <- function(data, max_na_ratio = 0.30, max_zero_content = 0.30) {
if (!is.data.frame(data)) {
stop("'data' must be a data frame.")
}
col_names <- colnames(data)
mix_row_idx <- nrow(data)
if (mix_row_idx <= 1L) {
stop("Data frame must contain at least one source row and one mixture row.")
}
# --- 1. Dynamically identify Ratio and Content columns ---
c_cols <- grep("[Cc]onc|[Cc]ont", col_names, value = TRUE)
r_cols <- setdiff(col_names[-c(1, 2)], c(c_cols, "n"))
if (length(c_cols) == 0 || length(r_cols) == 0) {
stop("Could not identify Ratio or Content columns to filter. Ensure content columns contain 'Conc' or 'Cont'.")
}
# --- 2. Convert absolute zeros in Content to NAs ---
for (col in c_cols) {
zero_mask <- !is.na(data[[col]]) & data[[col]] == 0
if (any(zero_mask)) {
data[zero_mask, col] <- NA
}
}
# --- 3. Evaluate Sources ONLY (rows 1 to mix_row_idx - 1) ---
source_idx <- seq_len(mix_row_idx - 1L)
# Calculate % NAs in Ratios per row
pct_na_ratios <- rowSums(is.na(data[source_idx, r_cols, drop = FALSE])) / length(r_cols)
# Calculate % NAs in Content per row
pct_na_content <- rowSums(is.na(data[source_idx, c_cols, drop = FALSE])) / length(c_cols)
# --- 4. Identify which rows fail the thresholds ---
bad_ratio_idx <- source_idx[pct_na_ratios > max_na_ratio]
bad_content_idx <- source_idx[pct_na_content > max_zero_content]
rows_to_remove <- unique(c(bad_ratio_idx, bad_content_idx))
sample_ids <- as.character(data[[1]])
# --- 5. Print detailed messages and filter ---
if (length(rows_to_remove) > 0) {
if (length(rows_to_remove) == length(source_idx)) {
stop("Filter threshold removed ALL source samples. Lower the threshold or inspect your dataset for excessive NAs.")
}
message(sprintf("\n--- FILTERING COMPLETE: Discarded %d source sample(s) out of %d ---",
length(rows_to_remove), length(source_idx)))
if (length(bad_ratio_idx) > 0) {
message(sprintf(" > Removed %d row(s) due to >%.0f%% NAs in Ratios.\n Sample IDs: %s",
length(bad_ratio_idx),
max_na_ratio * 100,
paste(sample_ids[bad_ratio_idx], collapse = ", ")))
}
if (length(bad_content_idx) > 0) {
message(sprintf(" > Removed %d row(s) due to >%.0f%% Zeros/NAs in Content.\n Sample IDs: %s",
length(bad_content_idx),
max_zero_content * 100,
paste(sample_ids[bad_content_idx], collapse = ", ")))
}
data_clean <- data[-rows_to_remove, , drop = FALSE]
} else {
message("\n--- FILTERING COMPLETE: All source samples passed the thresholds. Zeros converted to NAs. ---")
data_clean <- data
}
return(data_clean)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.