diff --git a/R/acro_tables.R b/R/acro_tables.R index 6093ed4..a926791 100644 --- a/R/acro_tables.R +++ b/R/acro_tables.R @@ -20,12 +20,42 @@ acro_crosstab <- function(index, columns, values = NULL, rownames = NULL, colnam stop("ACRO has not been initialised. Please first call acro_init()") } - py_table <- acroEnv$ac$crosstab(index, columns, values = values, rownames = rownames, colnames = colnames, aggfunc = aggfunc, margins = margins, margins_name = margins_name, dropna = dropna, normalize = normalize, show_suppressed = show_suppressed) + # Convert the values into a NumPy array so that the Python ACRO crosstab function accepts them + np <- reticulate::import("numpy", convert = TRUE) + py_values <- if (!is.null(values)) np$array(values) else NULL + + py_table <- tryCatch( + { + acroEnv$ac$crosstab(index, columns, values = py_values, rownames = rownames, colnames = colnames, aggfunc = aggfunc, margins = margins, margins_name = margins_name, dropna = dropna, normalize = normalize, show_suppressed = show_suppressed) + }, + error = function(e) { + # Check if Python threw the ValueError about an unsupported aggfunc + if (grepl("ValueError: aggfunc", e$message)) { + stop( + sprintf("Unsupported aggregation function provided: '%s'. Allowed functions are: mean, median, sum, std, count, mode.", aggfunc), + call. = FALSE + ) + } + # 2. Check if Python threw the missing values column error + else if (grepl("If you pass an aggregation function to crosstab", e$message)) { + stop( + "If you pass an aggregation function to crosstab, you must also specify a single values column to aggregate over.", + call. = FALSE + ) + } + # any other unexpected errors + else { + stop(e) # nocov + } + } + ) + table <- reticulate::py_to_r(py_table) return(table) } + #' Compute a simple cross tabulation of two (or more) factors. #' #' @param index Values to group by in the rows. @@ -152,7 +182,23 @@ acro_pivot_table <- function(data, values = NULL, index = NULL, columns = NULL, if (is.null(acroEnv$ac)) { stop("ACRO has not been initialised. Please first call acro_init()") } - py_table <- acroEnv$ac$pivot_table(data, values = values, index = index, columns = columns, aggfunc = aggfunc) + + py_table <- tryCatch( + { + acroEnv$ac$pivot_table(data, values = values, index = index, columns = columns, aggfunc = aggfunc) + }, + error = function(e) { + if (grepl("aggfunc", e$message, ignore.case = TRUE)) { + stop( + sprintf("Unsupported aggregation function provided: '%s'. Allowed functions are: mean, median, sum, std, count, mode.", aggfunc), + call. = FALSE + ) + } else { + stop(e) # nocov + } + } + ) + table <- reticulate::py_to_r(py_table) return(table) } diff --git a/tests/testthat/test-acro_crosstab.R b/tests/testthat/test-acro_crosstab.R index 30e5002..3bd1ee7 100644 --- a/tests/testthat/test-acro_crosstab.R +++ b/tests/testthat/test-acro_crosstab.R @@ -28,3 +28,44 @@ test_that("acro_crosstab works with margins", { expect_equal(unname(as.matrix(r_table)), unname(as.matrix(p_table))) }) + +test_that("acro_crosstab works with aggregation function", { + # Creating the data frame with the specified values and row names + testthat::skip_on_cran() + expected_table <- data.frame( + convenient = c(3.25, 3.23, 3.25), + inconv = c(3.26, 3.26, 3.24) + ) + + # Assigning row names to the data frame + row.names(expected_table) <- c("not_recom", "priority", "recommended") + + acro_init() + table <- acro_crosstab(index = nursery_data[, c("health")], columns = nursery_data[, c("finance")], values = nursery_data[, c("children")], aggfunc = "mean") + expect_equal(table[, -1, drop = FALSE], expected_table[, -1, drop = FALSE], tolerance = 0.01) +}) + +test_that("acro_crosstab throws an error for unsupported aggregation functions", { + acro_init() + expect_error( + acro_crosstab( + index = nursery_data$health, + columns = nursery_data$finance, + values = nursery_data$children, + aggfunc = "max" + ), + "Unsupported aggregation function provided" + ) +}) + +test_that("acro_crosstab throws an error for missing values", { + acro_init() + expect_error( + acro_crosstab( + index = nursery_data$health, + columns = nursery_data$finance, + aggfunc = "mean" + ), + "If you pass an aggregation function to crosstab" + ) +}) diff --git a/tests/testthat/test-acro_pivot_table.R b/tests/testthat/test-acro_pivot_table.R index ea43e11..fffc7ad 100644 --- a/tests/testthat/test-acro_pivot_table.R +++ b/tests/testthat/test-acro_pivot_table.R @@ -19,3 +19,16 @@ test_that("acro_pivot_table works", { table <- acro_pivot_table(data = nursery_data, index = "parents", values = "children", aggfunc = list("mean", "std")) expect_equal(table[, -1, drop = FALSE], expected_table[, -1, drop = FALSE]) }) + +test_that("acro_pivot_table throws an error for unsupported aggregation functions", { + acro_init() + expect_error( + acro_pivot_table( + data = nursery_data, + index = nursery_data$parents, + values = nursery_data$children, + aggfunc = "max" + ), + "Unsupported aggregation function provided" + ) +})