diff --git a/R/checks.R b/R/checks.R index 14335c64..8d5bbdb7 100644 --- a/R/checks.R +++ b/R/checks.R @@ -117,7 +117,7 @@ check_attr <- function(object, attr = "type", check = NULL, stop = TRUE) { #' are_constant(1:10) #' #' are_binary(c("A", "B", "A")) -#' +#' #' is_even(1:5) #' is_odd(1:5) #' is_odd(c(0, 1.5, 2.5, NA, Inf, NULL)) diff --git a/R/crossbrand.R b/R/crossbrand.R index ea605d0c..05ac4f72 100644 --- a/R/crossbrand.R +++ b/R/crossbrand.R @@ -3,12 +3,12 @@ #' #' Given a list of recreated Robyn models, this function optimizes budget #' allocation across MMM with respective constraints by maximizing -#' incremental revenue/conversions. This method assumes each model is -#' independent, that can be compared given its spends were cleanly and -#' properly split, they modeled the same metric (revenue or conversion) -#' and units (currency or type of conversion), and date granularity. -#' Recommended to have same channels granularity across markets -#' to simplify results readings and application. +#' incremental revenue/conversions. This method assumes each model is +#' independent, that can be compared given its spends were cleanly and +#' properly split, they modeled the same metric (revenue or conversion) +#' and units (currency or type of conversion), and date granularity. +#' For best results, ensure channels have similar granularity across +#' markets to simplify interpretation and application of the outputs. #' #' @param budget_constr_low,budget_constr_up Numeric vector. Relative minimum #' and maximum budgets to consider based on \code{initial_budgets}. @@ -28,7 +28,7 @@ #' files <- c("BrandA.json", "BrandB.json", "BrandC.json", "BrandN.json") #' models <- lapply(files, function(x) Robyn::robyn_recreate(x)) #' names(models) <- gsub("\\.json", "", files) -#' +#' #' # Calculate cross-brand optimal allocation #' res <- robyn_xmodels( #' models, @@ -78,7 +78,7 @@ robyn_xmodels <- function( } start_dates <- extract_dates(start_dates, perfs, "start_date", quiet) end_dates <- extract_dates(end_dates, perfs, "end_date", quiet) - + # Extract initial budgets for the date range if (is.null(initial_budgets)) { for (i in seq_along(models)) { @@ -99,7 +99,7 @@ robyn_xmodels <- function( } else { if (length(initial_budgets) == 1) initial_budgets <- rep(initial_budgets, length(models)) } - + # Total budget across brands total_budget <- sum(initial_budgets) @@ -109,14 +109,13 @@ robyn_xmodels <- function( stopifnot(length(models) == length(initial_budgets)) # Function to calculate total incremental sales given a budget distribution - calculate_isales <- function( - models, budgets, isales = TRUE, - start_dates = NULL, end_dates = NULL, - budget_constr_low = 0.5, - budget_constr_up = 1.5, - channel_constr_low = budget_constr_low, - channel_constr_up = budget_constr_up, - quiet = FALSE, ...) { + calculate_isales <- function(models, budgets, isales = TRUE, + start_dates = NULL, end_dates = NULL, + budget_constr_low = 0.5, + budget_constr_up = 1.5, + channel_constr_low = budget_constr_low, + channel_constr_up = budget_constr_up, + quiet = FALSE, ...) { try_require("Robyn") stopifnot(length(models) == length(budgets)) bas <- list() @@ -145,15 +144,14 @@ robyn_xmodels <- function( } # Function to be optimized (minimized) - objective_function <- function( - budgets, total_budget, models, - start_dates = NULL, end_dates = NULL, - budget_constr_low = 0.5, - budget_constr_up = 1.5, - channel_constr_low = budget_constr_low, - channel_constr_up = budget_constr_up, - cores = 10, quiet = FALSE, - ...) { + objective_function <- function(budgets, total_budget, models, + start_dates = NULL, end_dates = NULL, + budget_constr_low = 0.5, + budget_constr_up = 1.5, + channel_constr_low = budget_constr_low, + channel_constr_up = budget_constr_up, + cores = 10, quiet = FALSE, + ...) { # Value to minimize: penalty (tends to zero) - incremental total sales (max) isales <- calculate_isales( models, budgets, diff --git a/R/crossbrand2.R b/R/crossbrand2.R index cca98282..46bcd59e 100644 --- a/R/crossbrand2.R +++ b/R/crossbrand2.R @@ -1,15 +1,15 @@ #################################################################### #' Cross-MMM Budget Optimization across Channels (fast) -#' +#' #' Given a list of recreated Robyn models, this function optimizes budget #' allocation across MMM with respective constraints by maximizing -#' response across all channels. This method assumes each model is -#' independent, that can be compared given its spends were cleanly and -#' properly split, they modeled the same metric (revenue or conversion) -#' and units (currency or type of conversion), and date granularity. -#' Recommended to have same channels granularity across markets +#' response across all channels. This method assumes each model is +#' independent, that can be compared given its spends were cleanly and +#' properly split, they modeled the same metric (revenue or conversion) +#' and units (currency or type of conversion), and date granularity. +#' Recommended to have same channels granularity across markets #' to simplify results readings and application. -#' +#' #' This approach is faster and cleaner compared with previous proposal #' using \code{robyn_xmodels()}. #' @@ -21,12 +21,12 @@ #' specific model. You can specify a single date and will be used in all models. #' Default empty value will assume you want all available data and date range. #' Must be length 1 or same as \code{models}. -#' @param channel_constr_low,channel_constr_up Numeric vector. +#' @param channel_constr_low,channel_constr_up Numeric vector. #' Relative lower and upper constraints per channel compared with mean -#' spend during the time period defined. +#' spend during the time period defined. #' If mean was zero for date range, historical mean spend value will be used. -#' Must have length 1 to replicate for all channels or same length -#' (and order )as \code{paid_media_spends}. +#' Must have length 1 to replicate for all channels or same length +#' (and order )as \code{paid_media_spends}. #' @return List. Contains optimized allocation results and plots. #' @examples #' \dontrun{ @@ -50,7 +50,7 @@ robyn_xchannels <- function( ...) { try_require("Robyn") try_require("nloptr") - + # Check all models are same type: metric and interval type stopifnot(length(unique(unlist(lapply(models, function(x) x$InputCollect$dep_var_type)))) == 1) stopifnot(length(unique(unlist(lapply(models, function(x) x$InputCollect$intervalType)))) == 1) diff --git a/R/family.R b/R/family.R index 7f450032..a1f91745 100644 --- a/R/family.R +++ b/R/family.R @@ -1,12 +1,12 @@ #################################################################### #' Surnames Order Sequence -#' -#' Generate a sequence of numbers that determines the order in which -#' surnames should be listed based on the number of generations of -#' ancestors you wish to include. This sequence follows the traditional -#' Latin custom of assigning the father's surname first, followed by -#' the mother's surname. The same logic extends systematically to higher -#' generations, ensuring that the order of surnames remains consistent +#' +#' Generate a sequence of numbers that determines the order in which +#' surnames should be listed based on the number of generations of +#' ancestors you wish to include. This sequence follows the traditional +#' Latin custom of assigning the father's surname first, followed by +#' the mother's surname. The same logic extends systematically to higher +#' generations, ensuring that the order of surnames remains consistent #' as you move upward through the family tree. #' #' @param n Integer. Number of generations to include in the sequence. diff --git a/R/onehotencoding.R b/R/onehotencoding.R index 1324fd73..0724de73 100644 --- a/R/onehotencoding.R +++ b/R/onehotencoding.R @@ -471,7 +471,7 @@ holidays <- function(countries = "Venezuela", } else { c("Date", "Holiday", "Holiday.Type") } - + # the table might contain comment about interstate holidays like # '* Observed only in some communities of this state. # Hover your mouse over the region or click on the holiday for details.' @@ -491,7 +491,7 @@ holidays <- function(countries = "Venezuela", ) } ) - + result <- data.frame( holiday = holidays$Date, holiday_name = holidays$Holiday, @@ -520,7 +520,7 @@ holidays <- function(countries = "Venezuela", results <- results %>% filter(!is.na(.data$holiday)) %>% cleanNames() %>% - as_tibble() - } + as_tibble() + } return(results) } diff --git a/R/wrangling.R b/R/wrangling.R index d1a2372f..8473ebe7 100644 --- a/R/wrangling.R +++ b/R/wrangling.R @@ -393,7 +393,7 @@ v2t <- vector2text #' formatNum(c(-3:3), sign = TRUE) #' @export #' @rdname format_string -formatNum <- function(x, decimals = 2, signif = NULL, +formatNum <- function(x, decimals = 2, signif = NULL, type = Sys.getenv("LARES_NUMFORMAT"), pre = "", pos = "", sign = FALSE, abbr = FALSE, @@ -401,7 +401,7 @@ formatNum <- function(x, decimals = 2, signif = NULL, if (is.null(x) || !is.numeric(x)) { return(x) } - + # Auxiliary function to save signs if (sign) signs <- ifelse(x > 0, "+", "") @@ -418,7 +418,9 @@ formatNum <- function(x, decimals = 2, signif = NULL, x <- unlist(lapply(x, function(y) if (is.na(y)) y else num_abbr(y, n = decimals + 1))) } else { x <- unlist(lapply(x, function(y) { - if (is.na(y)) y else { + if (is.na(y)) { + y + } else { if (type == 1) { y <- format(as.numeric(y), big.mark = ".", decimal.mark = ",", ...) } else { diff --git a/man/robyn_crossmmm.Rd b/man/robyn_crossmmm.Rd index cd1c7a3e..c47176be 100644 --- a/man/robyn_crossmmm.Rd +++ b/man/robyn_crossmmm.Rd @@ -50,11 +50,11 @@ and maximum budgets to consider based on \code{initial_budgets}. By default it'll consider 50% and 150% budget constraints. Must be length 1 or same as \code{models}.} -\item{channel_constr_low, channel_constr_up}{Numeric vector. +\item{channel_constr_low, channel_constr_up}{Numeric vector. Relative lower and upper constraints per channel compared with mean -spend during the time period defined. +spend during the time period defined. If mean was zero for date range, historical mean spend value will be used. -Must have length 1 to replicate for all channels or same length +Must have length 1 to replicate for all channels or same length (and order )as \code{paid_media_spends}.} \item{cores}{Integer. How many cores to use for parallel computations? @@ -76,20 +76,20 @@ List. Contains optimized allocation results and plots. \description{ Given a list of recreated Robyn models, this function optimizes budget allocation across MMM with respective constraints by maximizing -incremental revenue/conversions. This method assumes each model is -independent, that can be compared given its spends were cleanly and -properly split, they modeled the same metric (revenue or conversion) -and units (currency or type of conversion), and date granularity. -Recommended to have same channels granularity across markets -to simplify results readings and application. +incremental revenue/conversions. This method assumes each model is +independent, that can be compared given its spends were cleanly and +properly split, they modeled the same metric (revenue or conversion) +and units (currency or type of conversion), and date granularity. +For best results, ensure channels have similar granularity across +markets to simplify interpretation and application of the outputs. Given a list of recreated Robyn models, this function optimizes budget allocation across MMM with respective constraints by maximizing -response across all channels. This method assumes each model is -independent, that can be compared given its spends were cleanly and -properly split, they modeled the same metric (revenue or conversion) -and units (currency or type of conversion), and date granularity. -Recommended to have same channels granularity across markets +response across all channels. This method assumes each model is +independent, that can be compared given its spends were cleanly and +properly split, they modeled the same metric (revenue or conversion) +and units (currency or type of conversion), and date granularity. +Recommended to have same channels granularity across markets to simplify results readings and application. } \details{ diff --git a/man/seq_surnames.Rd b/man/seq_surnames.Rd index 8d30aeb3..6ee6bf93 100644 --- a/man/seq_surnames.Rd +++ b/man/seq_surnames.Rd @@ -14,12 +14,12 @@ Notice it will generate a vector with 2^(n-1) values.} Integer vector. } \description{ -Generate a sequence of numbers that determines the order in which -surnames should be listed based on the number of generations of -ancestors you wish to include. This sequence follows the traditional -Latin custom of assigning the father's surname first, followed by -the mother's surname. The same logic extends systematically to higher -generations, ensuring that the order of surnames remains consistent +Generate a sequence of numbers that determines the order in which +surnames should be listed based on the number of generations of +ancestors you wish to include. This sequence follows the traditional +Latin custom of assigning the father's surname first, followed by +the mother's surname. The same logic extends systematically to higher +generations, ensuring that the order of surnames remains consistent as you move upward through the family tree. } \examples{