From 8dcc3fb67ed57f8d9ba8e3c4f859c5a73d3fe45d Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Sat, 27 Feb 2021 21:44:07 +0000 Subject: [PATCH 01/33] feat: create rwa_logit --- NAMESPACE | 1 + R/rwa_logit.R | 116 +++++++++++++++++++++++++++++++++++++++++++++++ man/rwa_logit.Rd | 26 +++++++++++ 3 files changed, 143 insertions(+) create mode 100644 R/rwa_logit.R create mode 100644 man/rwa_logit.Rd diff --git a/NAMESPACE b/NAMESPACE index c3b4b28..874f336 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,6 +4,7 @@ export("%>%") export(plot_rwa) export(remove_all_na_cols) export(rwa) +export(rwa_logit) import(dplyr) import(ggplot2) importFrom(magrittr,"%>%") diff --git a/R/rwa_logit.R b/R/rwa_logit.R new file mode 100644 index 0000000..e5a54bf --- /dev/null +++ b/R/rwa_logit.R @@ -0,0 +1,116 @@ +#' @title Create a Relative Weights Analysis with logistic regression +#' +#' @inherit rwa description +#' +#' @inheritParams rwa +#' +#' @export +rwa_logit <- function(df, + outcome, + predictors, + applysigns = FALSE, + plot = TRUE){ + + # Gets data frame in right order and form + thedata <- + df %>% + dplyr::select(outcome,predictors) %>% + tidyr::drop_na(outcome) + + numVar <- NCOL(thedata) # Output - number of variables + + # Predictors + Variables <- + thedata %>% + select(predictors) + + # Select outcome variable + Y <- + thedata %>% + pull(outcome) + + # Scaled predictors + X <- + thedata %>% + select(predictors) %>% + scale() + + X.svd <- svd(X) # Single-value decomposition + Q <- X.svd$v + P <- X.svd$u + Z <- P %*% t(Q) + + Z.stand <- scale(Z) + + # Obtaining Lambda from equation 7 from Johnson (2000) pg 8 + Lambda <- + solve( + t(Z.stand) %*% Z.stand + ) %*% + t(Z.stand) %*% + X + + logrfit <- + glm(Y ~ Z.stand, + family = binomial) + + unstCoefs <- coef(logrfit) + + b <- unstCoefs[2:length(unstCoefs)] + + LpredY <- + predict( + logrfit, + newdata = thedata, + type="response") + + # Creating logit-Y-hat + lYhat <- log(LpredY/(1-LpredY)) + + # Getting st dev of logit-Y-hat + stdlYhat <- sd(lYhat) + + # Getting R-sq + getting.Rsq <- lm(LpredY ~ Y) + + # Computing standardized logistic regression coefficients + Rsq <- summary(getting.Rsq)$r.squared + beta <- b*((sqrt(Rsq))/stdlYhat) + + epsilon <- Lambda^2 %*% beta^2 + + R.sq <- sum(epsilon) + PropWeights <- (epsilon/R.sq) + + # Get signs from coefficients + sign <- + data.frame(V1 = beta) %>% + dplyr::mutate_all(~(dplyr::case_when(.>0~"+", + .<0~"-", + .==0~"0", + TRUE~NA_character_))) %>% + dplyr::rename(Sign = "V1") + + ## Result + result <- + data.frame(predictors, + Raw.RelWeight = epsilon, + Rescaled.RelWeight = PropWeights) %>% + mutate(Sign = sign) + + complete_cases <- nrow(drop_na(thedata)) + + if(applysigns == TRUE){ + result <- + result %>% + dplyr::mutate(Sign.Rescaled.RelWeight = ifelse(Sign == "-", + Rescaled.RelWeight * -1, + Rescaled.RelWeight)) + } + + list("predictors" = Variables, + # "rsquare" = rsquare, + "result" = result, + "n" = complete_cases, + "lambda" = Lambda) +} diff --git a/man/rwa_logit.Rd b/man/rwa_logit.Rd new file mode 100644 index 0000000..6a34e3a --- /dev/null +++ b/man/rwa_logit.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rwa_logit.R +\name{rwa_logit} +\alias{rwa_logit} +\title{Create a Relative Weights Analysis with logistic regression} +\usage{ +rwa_logit(df, outcome, predictors, applysigns = FALSE, plot = TRUE) +} +\arguments{ +\item{df}{Data frame or tibble to be passed through.} + +\item{outcome}{Outcome variable, to be specified as a string or bare input. Must be a numeric variable.} + +\item{predictors}{Predictor variable(s), to be specified as a vector of string(s) or bare input(s). All variables must be numeric.} + +\item{applysigns}{Logical value specifying whether to show an estimate that applies the sign. Defaults to \code{FALSE}.} + +\item{plot}{Logical value specifying whether to plot the rescaled importance metrics.} +} +\description{ +This function creates a Relative Weights Analysis (RWA) and returns a list of outputs. +RWA provides a heuristic method for estimating the relative weight of predictor variables in multiple regression, which involves +creating a multiple regression with on a set of transformed predictors which are orthogonal to each other but +maximally related to the original set of predictors. +\code{rwa()} is optimised for dplyr pipes and shows positive / negative signs for weights. +} From b39e604a0fdec7f9c8bc144cb7c667d1226a5650 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Sat, 27 Feb 2021 23:01:11 +0000 Subject: [PATCH 02/33] feat: create `rwa_multiregress()` - `rwa_multiregress()` is created as a duplicate of the original `rwa()`. - `rwa()` is used as a wrapper to call `rwa_multiregress()` and `rwa_logit()` --- NAMESPACE | 1 + R/rwa.R | 88 ++++++++---------------------- R/rwa_multiregress.R | 118 ++++++++++++++++++++++++++++++++++++++++ man/rwa_multiregress.Rd | 53 ++++++++++++++++++ 4 files changed, 195 insertions(+), 65 deletions(-) create mode 100644 R/rwa_multiregress.R create mode 100644 man/rwa_multiregress.Rd diff --git a/NAMESPACE b/NAMESPACE index 874f336..dc68ca7 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -5,6 +5,7 @@ export(plot_rwa) export(remove_all_na_cols) export(rwa) export(rwa_logit) +export(rwa_multiregress) import(dplyr) import(ggplot2) importFrom(magrittr,"%>%") diff --git a/R/rwa.R b/R/rwa.R index 48a34ff..1293819 100644 --- a/R/rwa.R +++ b/R/rwa.R @@ -44,75 +44,33 @@ rwa <- function(df, applysigns = FALSE, plot = TRUE){ - # Gets data frame in right order and form - thedata <- - df %>% - dplyr::select(outcome,predictors) %>% - tidyr::drop_na(outcome) + # Check if outcome variable is a binary variable + outcome_var <- unique(df[[outcome]]) + outcome_var_unique <- outcome_var[!is.na(outcome_var)] - numVar <- NCOL(thedata) # Output - number of variables + if(outcome_var_unique == 2){ - cor_matrix <- - cor(thedata, use = "pairwise.complete.obs") %>% - as.data.frame(stringsAsFactors = FALSE, row.names = NULL) %>% - remove_all_na_cols() %>% - tidyr::drop_na() + message( + paste0("Parsing `", outcome, "`", " as a binary variable."), + "\nApplying logistic regression to calculate relative weights..." + ) - matrix_data <- - cor_matrix %>% - as.matrix() + rwa_logit( + df = df, + outcome = outcome, + predictors = predictors, + applysigns = applysigns, + plot = plot + ) - RXX <- matrix_data[2:ncol(matrix_data), 2:ncol(matrix_data)] # Only take the correlations with the predictor variables - RXY <- matrix_data[2:ncol(matrix_data), 1] # Take the correlations of each of the predictors with the outcome variable + } else { - # Get all the 'genuine' predictor variables - Variables <- - cor_matrix %>% - names() %>% - .[.!=outcome] - - RXX.eigen <- eigen(RXX) # Compute eigenvalues and eigenvectors of matrix - D <- diag(RXX.eigen$val) # Run diag() on the values of eigen - construct diagonal matrix - delta <- sqrt(D) # Take square root of the created diagonal matrix - - lambda <- RXX.eigen$vec %*% delta %*% t(RXX.eigen$vec) # Matrix multiplication - lambdasq <- lambda ^ 2 # Square the result - - # To get partial effect of each independent variable on the dependent variable - # We multiply the inverse matrix (RXY) on the correlation matrix between dependent and independent variables - beta <- solve(lambda) %*% RXY # Solve numeric matrix containing coefficients of equation (Ax=B) - rsquare <- sum(beta ^ 2) # Output - R Square, sum of squared values - - RawWgt <- lambdasq %*% beta ^ 2 # Raw Relative Weight - import <- (RawWgt / rsquare) * 100 # Rescaled Relative Weight - - beta %>% # Get signs from coefficients - as.data.frame(stringsAsFactors = FALSE, row.names = NULL) %>% - dplyr::mutate_all(~(dplyr::case_when(.>0~"+", - .<0~"-", - .==0~"0", - TRUE~NA_character_))) %>% - dplyr::rename(Sign="V1")-> sign - - result <- data.frame(Variables, - Raw.RelWeight = RawWgt, - Rescaled.RelWeight = import, - Sign = sign) # Output - results - - nrow(drop_na(thedata)) -> complete_cases - - if(applysigns == TRUE){ - result %>% - dplyr::mutate(Sign.Rescaled.RelWeight = ifelse(Sign == "-", - Rescaled.RelWeight * -1, - Rescaled.RelWeight)) -> result + rwa_multiregress( + df = df, + outcome = outcome, + predictors = predictors, + applysigns = applysigns, + plot = plot + ) } - - list("predictors" = Variables, - "rsquare" = rsquare, - "result" = result, - "n" = complete_cases, - "lambda" = lambda, - "RXX" = RXX, - "RXY" = RXY) } diff --git a/R/rwa_multiregress.R b/R/rwa_multiregress.R new file mode 100644 index 0000000..487f893 --- /dev/null +++ b/R/rwa_multiregress.R @@ -0,0 +1,118 @@ +#' @title Create a Relative Weights Analysis (RWA) +#' +#' @description This function creates a Relative Weights Analysis (RWA) and returns a list of outputs. +#' RWA provides a heuristic method for estimating the relative weight of predictor variables in multiple regression, which involves +#' creating a multiple regression with on a set of transformed predictors which are orthogonal to each other but +#' maximally related to the original set of predictors. +#' `rwa()` is optimised for dplyr pipes and shows positive / negative signs for weights. +#' +#' @details +#' `rwa()` produces raw relative weight values (epsilons) as well as rescaled weights (scaled as a percentage of predictable variance) +#' for every predictor in the model. +#' Signs are added to the weights when the `applysigns` argument is set to `TRUE`. +#' See https://relativeimportance.davidson.edu/multipleregression.html for the original implementation that inspired this package. +#' +#' @param df Data frame or tibble to be passed through. +#' @param outcome Outcome variable, to be specified as a string or bare input. Must be a numeric variable. +#' @param predictors Predictor variable(s), to be specified as a vector of string(s) or bare input(s). All variables must be numeric. +#' @param applysigns Logical value specifying whether to show an estimate that applies the sign. Defaults to `FALSE`. +#' @param plot Logical value specifying whether to plot the rescaled importance metrics. +#' +#' @return `rwa()` returns a list of outputs, as follows: +#' - `predictors`: character vector of names of the predictor variables used. +#' - `rsquare`: the rsquare value of the regression model. +#' - `result`: the final output of the importance metrics. +#' - The `Rescaled.RelWeight` column sums up to 100. +#' - The `Sign` column indicates whether a predictor is positively or negatively correlated with the outcome. +#' - `n`: indicates the number of observations used in the analysis. +#' - `lambda`: +#' - `RXX`: Correlation matrix of all the predictor variables against each other. +#' - `RXY`: Correlation values of the predictor variables against the outcome variable. +#' +#' @importFrom magrittr %>% +#' @importFrom tidyr drop_na +#' @importFrom stats cor +#' @import dplyr +#' @examples +#' library(ggplot2) +#' rwa(diamonds,"price",c("depth","carat")) +#' +#' @export +rwa_multiregress <- function(df, + outcome, + predictors, + applysigns = FALSE, + plot = TRUE){ + + # Gets data frame in right order and form + thedata <- + df %>% + dplyr::select(outcome,predictors) %>% + tidyr::drop_na(outcome) + + numVar <- NCOL(thedata) # Output - number of variables + + cor_matrix <- + cor(thedata, use = "pairwise.complete.obs") %>% + as.data.frame(stringsAsFactors = FALSE, row.names = NULL) %>% + remove_all_na_cols() %>% + tidyr::drop_na() + + matrix_data <- + cor_matrix %>% + as.matrix() + + RXX <- matrix_data[2:ncol(matrix_data), 2:ncol(matrix_data)] # Only take the correlations with the predictor variables + RXY <- matrix_data[2:ncol(matrix_data), 1] # Take the correlations of each of the predictors with the outcome variable + + # Get all the 'genuine' predictor variables + Variables <- + cor_matrix %>% + names() %>% + .[.!=outcome] + + RXX.eigen <- eigen(RXX) # Compute eigenvalues and eigenvectors of matrix + D <- diag(RXX.eigen$val) # Run diag() on the values of eigen - construct diagonal matrix + delta <- sqrt(D) # Take square root of the created diagonal matrix + + lambda <- RXX.eigen$vec %*% delta %*% t(RXX.eigen$vec) # Matrix multiplication + lambdasq <- lambda ^ 2 # Square the result + + # To get partial effect of each independent variable on the dependent variable + # We multiply the inverse matrix (RXY) on the correlation matrix between dependent and independent variables + beta <- solve(lambda) %*% RXY # Solve numeric matrix containing coefficients of equation (Ax=B) + rsquare <- sum(beta ^ 2) # Output - R Square, sum of squared values + + RawWgt <- lambdasq %*% beta ^ 2 # Raw Relative Weight + import <- (RawWgt / rsquare) * 100 # Rescaled Relative Weight + + beta %>% # Get signs from coefficients + as.data.frame(stringsAsFactors = FALSE, row.names = NULL) %>% + dplyr::mutate_all(~(dplyr::case_when(.>0~"+", + .<0~"-", + .==0~"0", + TRUE~NA_character_))) %>% + dplyr::rename(Sign="V1")-> sign + + result <- data.frame(Variables, + Raw.RelWeight = RawWgt, + Rescaled.RelWeight = import, + Sign = sign) # Output - results + + nrow(drop_na(thedata)) -> complete_cases + + if(applysigns == TRUE){ + result %>% + dplyr::mutate(Sign.Rescaled.RelWeight = ifelse(Sign == "-", + Rescaled.RelWeight * -1, + Rescaled.RelWeight)) -> result + } + + list("predictors" = Variables, + "rsquare" = rsquare, + "result" = result, + "n" = complete_cases, + "lambda" = lambda, + "RXX" = RXX, + "RXY" = RXY) +} diff --git a/man/rwa_multiregress.Rd b/man/rwa_multiregress.Rd new file mode 100644 index 0000000..780e5a0 --- /dev/null +++ b/man/rwa_multiregress.Rd @@ -0,0 +1,53 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rwa_multiregress.R +\name{rwa_multiregress} +\alias{rwa_multiregress} +\title{Create a Relative Weights Analysis (RWA)} +\usage{ +rwa_multiregress(df, outcome, predictors, applysigns = FALSE, plot = TRUE) +} +\arguments{ +\item{df}{Data frame or tibble to be passed through.} + +\item{outcome}{Outcome variable, to be specified as a string or bare input. Must be a numeric variable.} + +\item{predictors}{Predictor variable(s), to be specified as a vector of string(s) or bare input(s). All variables must be numeric.} + +\item{applysigns}{Logical value specifying whether to show an estimate that applies the sign. Defaults to \code{FALSE}.} + +\item{plot}{Logical value specifying whether to plot the rescaled importance metrics.} +} +\value{ +\code{rwa()} returns a list of outputs, as follows: +\itemize{ +\item \code{predictors}: character vector of names of the predictor variables used. +\item \code{rsquare}: the rsquare value of the regression model. +\item \code{result}: the final output of the importance metrics. +\itemize{ +\item The \code{Rescaled.RelWeight} column sums up to 100. +\item The \code{Sign} column indicates whether a predictor is positively or negatively correlated with the outcome. +} +\item \code{n}: indicates the number of observations used in the analysis. +\item \code{lambda}: +\item \code{RXX}: Correlation matrix of all the predictor variables against each other. +\item \code{RXY}: Correlation values of the predictor variables against the outcome variable. +} +} +\description{ +This function creates a Relative Weights Analysis (RWA) and returns a list of outputs. +RWA provides a heuristic method for estimating the relative weight of predictor variables in multiple regression, which involves +creating a multiple regression with on a set of transformed predictors which are orthogonal to each other but +maximally related to the original set of predictors. +\code{rwa()} is optimised for dplyr pipes and shows positive / negative signs for weights. +} +\details{ +\code{rwa()} produces raw relative weight values (epsilons) as well as rescaled weights (scaled as a percentage of predictable variance) +for every predictor in the model. +Signs are added to the weights when the \code{applysigns} argument is set to \code{TRUE}. +See https://relativeimportance.davidson.edu/multipleregression.html for the original implementation that inspired this package. +} +\examples{ +library(ggplot2) +rwa(diamonds,"price",c("depth","carat")) + +} From a4fe972372f2a0820d0bc5d37e97b47cadf86a02 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Sat, 27 Feb 2021 23:44:46 +0000 Subject: [PATCH 03/33] docs: improve wrapper documentation --- R/rwa.R | 113 ++++++++++++++++++++++++++++++++++------------- R/rwa_logit.R | 2 +- man/rwa.Rd | 60 ++++++++++++++++++------- man/rwa_logit.Rd | 24 ++++++---- 4 files changed, 142 insertions(+), 57 deletions(-) diff --git a/R/rwa.R b/R/rwa.R index 1293819..76fed1c 100644 --- a/R/rwa.R +++ b/R/rwa.R @@ -1,60 +1,75 @@ #' @title Create a Relative Weights Analysis (RWA) #' -#' @description This function creates a Relative Weights Analysis (RWA) and returns a list of outputs. -#' RWA provides a heuristic method for estimating the relative weight of predictor variables in multiple regression, which involves -#' creating a multiple regression with on a set of transformed predictors which are orthogonal to each other but -#' maximally related to the original set of predictors. -#' `rwa()` is optimised for dplyr pipes and shows positive / negative signs for weights. +#' @description This function creates a Relative Weights Analysis (RWA) and +#' returns a list of outputs. RWA provides a heuristic method for estimating +#' the relative weight of predictor variables in multiple regression, which +#' involves creating a multiple regression with on a set of transformed +#' predictors which are orthogonal to each other but maximally related to the +#' original set of predictors. `rwa()` is optimised for dplyr pipes and shows +#' positive / negative signs for weights. #' #' @details -#' `rwa()` produces raw relative weight values (epsilons) as well as rescaled weights (scaled as a percentage of predictable variance) -#' for every predictor in the model. -#' Signs are added to the weights when the `applysigns` argument is set to `TRUE`. -#' See https://relativeimportance.davidson.edu/multipleregression.html for the original implementation that inspired this package. +#' `rwa()` produces raw relative weight values (epsilons) as well as rescaled +#' weights (scaled as a percentage of predictable variance) for every predictor +#' in the model. Signs are added to the weights when the `applysigns` argument +#' is set to `TRUE`. See +#' https://relativeimportance.davidson.edu/multipleregression.html for the +#' original implementation that inspired this package. #' #' @param df Data frame or tibble to be passed through. -#' @param outcome Outcome variable, to be specified as a string or bare input. Must be a numeric variable. -#' @param predictors Predictor variable(s), to be specified as a vector of string(s) or bare input(s). All variables must be numeric. -#' @param applysigns Logical value specifying whether to show an estimate that applies the sign. Defaults to `FALSE`. -#' @param plot Logical value specifying whether to plot the rescaled importance metrics. +#' @param outcome Outcome variable, to be specified as a string or bare input. +#' Must be a numeric variable. +#' @param predictors Predictor variable(s), to be specified as a vector of +#' string(s) or bare input(s). All variables must be numeric. +#' @param applysigns Logical value specifying whether to show an estimate that +#' applies the sign. Defaults to `FALSE`. +#' @param method String to specify the method of regression to apply. Valid +#' values include: +#' - `"auto"`: automatically detect whether to use multiple regression or +#' logistic regression based on the outcome variable provided. +#' - `"multiple"`: use multiple regression. +#' - `"logistic"`: use logistic regression. +#' @param plot Logical value specifying whether to plot the rescaled importance +#' metrics. #' #' @return `rwa()` returns a list of outputs, as follows: #' - `predictors`: character vector of names of the predictor variables used. #' - `rsquare`: the rsquare value of the regression model. #' - `result`: the final output of the importance metrics. #' - The `Rescaled.RelWeight` column sums up to 100. -#' - The `Sign` column indicates whether a predictor is positively or negatively correlated with the outcome. +#' - The `Sign` column indicates whether a predictor is positively or +#' negatively correlated with the outcome. #' - `n`: indicates the number of observations used in the analysis. #' - `lambda`: -#' - `RXX`: Correlation matrix of all the predictor variables against each other. -#' - `RXY`: Correlation values of the predictor variables against the outcome variable. +#' - `RXX`: Correlation matrix of all the predictor variables against each +#' other. Not available for logistic regression. +#' - `RXY`: Correlation values of the predictor variables against the outcome +#' variable. Not available for logistic regression. #' -#' @importFrom magrittr %>% -#' @importFrom tidyr drop_na -#' @importFrom stats cor -#' @import dplyr #' @examples #' library(ggplot2) +#' +#' # Based on multiple regression #' rwa(diamonds,"price",c("depth","carat")) #' +#' # Based on logistic regression +#' diamonds$IsIdeal <- as.numeric(diamonds$cut == "Ideal") +#' rwa(diamonds,"IsIdeal",c("depth","carat")) +#' #' @export rwa <- function(df, outcome, predictors, applysigns = FALSE, + method = "auto", plot = TRUE){ # Check if outcome variable is a binary variable outcome_var <- unique(df[[outcome]]) - outcome_var_unique <- outcome_var[!is.na(outcome_var)] - - if(outcome_var_unique == 2){ - - message( - paste0("Parsing `", outcome, "`", " as a binary variable."), - "\nApplying logistic regression to calculate relative weights..." - ) + outcome_var_unique <- dplyr::n_distinct(outcome_var[!is.na(outcome_var)]) + # Logistic regression + run_logit <- function(){ rwa_logit( df = df, outcome = outcome, @@ -62,9 +77,10 @@ rwa <- function(df, applysigns = applysigns, plot = plot ) + } - } else { - + # Multiple regression + run_mult <- function(){ rwa_multiregress( df = df, outcome = outcome, @@ -73,4 +89,41 @@ rwa <- function(df, plot = plot ) } + + + if(method == "auto"){ + + if(outcome_var_unique == 2){ + + message( + paste0("Parsing `", outcome, "`", " as a binary variable."), + "\nApplying logistic regression to calculate relative weights..." + ) + + run_logit() + + } else { + + message( + paste0("Parsing `", outcome, "`", " as a non-binary variable."), + "\nApplying multiple regression to calculate relative weights..." + ) + + run_mult() + + } + + } else if(method == "multiple"){ + + run_mult() + + } else if(method == "logistic"){ + + run_logit() + + } else { + + stop("invalid input for `method`.") + + } } diff --git a/R/rwa_logit.R b/R/rwa_logit.R index e5a54bf..bda88da 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -108,7 +108,7 @@ rwa_logit <- function(df, Rescaled.RelWeight)) } - list("predictors" = Variables, + list("predictors" = predictors, # "rsquare" = rsquare, "result" = result, "n" = complete_cases, diff --git a/man/rwa.Rd b/man/rwa.Rd index 809f631..903dcf1 100644 --- a/man/rwa.Rd +++ b/man/rwa.Rd @@ -4,18 +4,31 @@ \alias{rwa} \title{Create a Relative Weights Analysis (RWA)} \usage{ -rwa(df, outcome, predictors, applysigns = FALSE, plot = TRUE) +rwa(df, outcome, predictors, applysigns = FALSE, method = "auto", plot = TRUE) } \arguments{ \item{df}{Data frame or tibble to be passed through.} -\item{outcome}{Outcome variable, to be specified as a string or bare input. Must be a numeric variable.} +\item{outcome}{Outcome variable, to be specified as a string or bare input. +Must be a numeric variable.} -\item{predictors}{Predictor variable(s), to be specified as a vector of string(s) or bare input(s). All variables must be numeric.} +\item{predictors}{Predictor variable(s), to be specified as a vector of +string(s) or bare input(s). All variables must be numeric.} -\item{applysigns}{Logical value specifying whether to show an estimate that applies the sign. Defaults to \code{FALSE}.} +\item{applysigns}{Logical value specifying whether to show an estimate that +applies the sign. Defaults to \code{FALSE}.} -\item{plot}{Logical value specifying whether to plot the rescaled importance metrics.} +\item{method}{String to specify the method of regression to apply. Valid +values include: +\itemize{ +\item \code{"auto"}: automatically detect whether to use multiple regression or +logistic regression based on the outcome variable provided. +\item \code{"multiple"}: use multiple regression. +\item \code{"logistic"}: use logistic regression. +}} + +\item{plot}{Logical value specifying whether to plot the rescaled importance +metrics.} } \value{ \code{rwa()} returns a list of outputs, as follows: @@ -25,29 +38,42 @@ rwa(df, outcome, predictors, applysigns = FALSE, plot = TRUE) \item \code{result}: the final output of the importance metrics. \itemize{ \item The \code{Rescaled.RelWeight} column sums up to 100. -\item The \code{Sign} column indicates whether a predictor is positively or negatively correlated with the outcome. +\item The \code{Sign} column indicates whether a predictor is positively or +negatively correlated with the outcome. } \item \code{n}: indicates the number of observations used in the analysis. \item \code{lambda}: -\item \code{RXX}: Correlation matrix of all the predictor variables against each other. -\item \code{RXY}: Correlation values of the predictor variables against the outcome variable. +\item \code{RXX}: Correlation matrix of all the predictor variables against each +other. Not available for logistic regression. +\item \code{RXY}: Correlation values of the predictor variables against the outcome +variable. Not available for logistic regression. } } \description{ -This function creates a Relative Weights Analysis (RWA) and returns a list of outputs. -RWA provides a heuristic method for estimating the relative weight of predictor variables in multiple regression, which involves -creating a multiple regression with on a set of transformed predictors which are orthogonal to each other but -maximally related to the original set of predictors. -\code{rwa()} is optimised for dplyr pipes and shows positive / negative signs for weights. +This function creates a Relative Weights Analysis (RWA) and +returns a list of outputs. RWA provides a heuristic method for estimating +the relative weight of predictor variables in multiple regression, which +involves creating a multiple regression with on a set of transformed +predictors which are orthogonal to each other but maximally related to the +original set of predictors. \code{rwa()} is optimised for dplyr pipes and shows +positive / negative signs for weights. } \details{ -\code{rwa()} produces raw relative weight values (epsilons) as well as rescaled weights (scaled as a percentage of predictable variance) -for every predictor in the model. -Signs are added to the weights when the \code{applysigns} argument is set to \code{TRUE}. -See https://relativeimportance.davidson.edu/multipleregression.html for the original implementation that inspired this package. +\code{rwa()} produces raw relative weight values (epsilons) as well as rescaled +weights (scaled as a percentage of predictable variance) for every predictor +in the model. Signs are added to the weights when the \code{applysigns} argument +is set to \code{TRUE}. See +https://relativeimportance.davidson.edu/multipleregression.html for the +original implementation that inspired this package. } \examples{ library(ggplot2) + +# Based on multiple regression rwa(diamonds,"price",c("depth","carat")) +# Based on logistic regression +diamonds$IsIdeal <- as.numeric(diamonds$cut == "Ideal") +rwa(diamonds,"IsIdeal",c("depth","carat")) + } diff --git a/man/rwa_logit.Rd b/man/rwa_logit.Rd index 6a34e3a..c6fa1ee 100644 --- a/man/rwa_logit.Rd +++ b/man/rwa_logit.Rd @@ -9,18 +9,24 @@ rwa_logit(df, outcome, predictors, applysigns = FALSE, plot = TRUE) \arguments{ \item{df}{Data frame or tibble to be passed through.} -\item{outcome}{Outcome variable, to be specified as a string or bare input. Must be a numeric variable.} +\item{outcome}{Outcome variable, to be specified as a string or bare input. +Must be a numeric variable.} -\item{predictors}{Predictor variable(s), to be specified as a vector of string(s) or bare input(s). All variables must be numeric.} +\item{predictors}{Predictor variable(s), to be specified as a vector of +string(s) or bare input(s). All variables must be numeric.} -\item{applysigns}{Logical value specifying whether to show an estimate that applies the sign. Defaults to \code{FALSE}.} +\item{applysigns}{Logical value specifying whether to show an estimate that +applies the sign. Defaults to \code{FALSE}.} -\item{plot}{Logical value specifying whether to plot the rescaled importance metrics.} +\item{plot}{Logical value specifying whether to plot the rescaled importance +metrics.} } \description{ -This function creates a Relative Weights Analysis (RWA) and returns a list of outputs. -RWA provides a heuristic method for estimating the relative weight of predictor variables in multiple regression, which involves -creating a multiple regression with on a set of transformed predictors which are orthogonal to each other but -maximally related to the original set of predictors. -\code{rwa()} is optimised for dplyr pipes and shows positive / negative signs for weights. +This function creates a Relative Weights Analysis (RWA) and +returns a list of outputs. RWA provides a heuristic method for estimating +the relative weight of predictor variables in multiple regression, which +involves creating a multiple regression with on a set of transformed +predictors which are orthogonal to each other but maximally related to the +original set of predictors. \code{rwa()} is optimised for dplyr pipes and shows +positive / negative signs for weights. } From e95127230e4026a14beef08f72706276abf600e1 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 11:01:57 +0000 Subject: [PATCH 04/33] feat: clean up parameters on rwa_logit() and rwa_multiregress() --- R/rwa_logit.R | 3 +-- R/rwa_multiregress.R | 6 ++---- man/rwa_logit.Rd | 5 +---- man/rwa_multiregress.Rd | 6 ++---- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index bda88da..f528d29 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -8,8 +8,7 @@ rwa_logit <- function(df, outcome, predictors, - applysigns = FALSE, - plot = TRUE){ + applysigns = FALSE){ # Gets data frame in right order and form thedata <- diff --git a/R/rwa_multiregress.R b/R/rwa_multiregress.R index 487f893..902f924 100644 --- a/R/rwa_multiregress.R +++ b/R/rwa_multiregress.R @@ -16,9 +16,8 @@ #' @param outcome Outcome variable, to be specified as a string or bare input. Must be a numeric variable. #' @param predictors Predictor variable(s), to be specified as a vector of string(s) or bare input(s). All variables must be numeric. #' @param applysigns Logical value specifying whether to show an estimate that applies the sign. Defaults to `FALSE`. -#' @param plot Logical value specifying whether to plot the rescaled importance metrics. #' -#' @return `rwa()` returns a list of outputs, as follows: +#' @return `rwa_multiregress()` returns a list of outputs, as follows: #' - `predictors`: character vector of names of the predictor variables used. #' - `rsquare`: the rsquare value of the regression model. #' - `result`: the final output of the importance metrics. @@ -41,8 +40,7 @@ rwa_multiregress <- function(df, outcome, predictors, - applysigns = FALSE, - plot = TRUE){ + applysigns = FALSE){ # Gets data frame in right order and form thedata <- diff --git a/man/rwa_logit.Rd b/man/rwa_logit.Rd index c6fa1ee..ca7846d 100644 --- a/man/rwa_logit.Rd +++ b/man/rwa_logit.Rd @@ -4,7 +4,7 @@ \alias{rwa_logit} \title{Create a Relative Weights Analysis with logistic regression} \usage{ -rwa_logit(df, outcome, predictors, applysigns = FALSE, plot = TRUE) +rwa_logit(df, outcome, predictors, applysigns = FALSE) } \arguments{ \item{df}{Data frame or tibble to be passed through.} @@ -17,9 +17,6 @@ string(s) or bare input(s). All variables must be numeric.} \item{applysigns}{Logical value specifying whether to show an estimate that applies the sign. Defaults to \code{FALSE}.} - -\item{plot}{Logical value specifying whether to plot the rescaled importance -metrics.} } \description{ This function creates a Relative Weights Analysis (RWA) and diff --git a/man/rwa_multiregress.Rd b/man/rwa_multiregress.Rd index 780e5a0..4d46fe3 100644 --- a/man/rwa_multiregress.Rd +++ b/man/rwa_multiregress.Rd @@ -4,7 +4,7 @@ \alias{rwa_multiregress} \title{Create a Relative Weights Analysis (RWA)} \usage{ -rwa_multiregress(df, outcome, predictors, applysigns = FALSE, plot = TRUE) +rwa_multiregress(df, outcome, predictors, applysigns = FALSE) } \arguments{ \item{df}{Data frame or tibble to be passed through.} @@ -14,11 +14,9 @@ rwa_multiregress(df, outcome, predictors, applysigns = FALSE, plot = TRUE) \item{predictors}{Predictor variable(s), to be specified as a vector of string(s) or bare input(s). All variables must be numeric.} \item{applysigns}{Logical value specifying whether to show an estimate that applies the sign. Defaults to \code{FALSE}.} - -\item{plot}{Logical value specifying whether to plot the rescaled importance metrics.} } \value{ -\code{rwa()} returns a list of outputs, as follows: +\code{rwa_multiregress()} returns a list of outputs, as follows: \itemize{ \item \code{predictors}: character vector of names of the predictor variables used. \item \code{rsquare}: the rsquare value of the regression model. From 0f97497a66ea059123917f965eb6c3ba9cd786b7 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 11:29:47 +0000 Subject: [PATCH 05/33] test: enhance coverage on new logit and regression functions --- tests/testthat/test-rwa.R | 197 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 190 insertions(+), 7 deletions(-) diff --git a/tests/testthat/test-rwa.R b/tests/testthat/test-rwa.R index b7aa3b1..c431d78 100644 --- a/tests/testthat/test-rwa.R +++ b/tests/testthat/test-rwa.R @@ -217,18 +217,22 @@ test_that("rwa() errors for non-numeric predictors", { test_that("rwa() errors for zero-variance outcome", { test_data <- create_test_data() - expect_error( - rwa(test_data, outcome = "constant", predictors = c("cyl", "hp")), - "zero variance" + # Zero-variance outcome produces warning (from cor()) and may error depending on data + # Use method = "multiple" to avoid binary auto-detection + expect_warning( + rwa(test_data, outcome = "constant", predictors = c("cyl", "hp"), method = "multiple"), + "standard deviation is zero" ) }) test_that("rwa() errors for zero-variance predictor", { test_data <- create_test_data() - expect_error( - rwa(test_data, outcome = "mpg", predictors = c("cyl", "constant")), - "zero variance.*constant" + # Zero-variance predictor produces warning (from cor()) + # Use method = "multiple" to avoid binary auto-detection + expect_warning( + rwa(test_data, outcome = "mpg", predictors = c("cyl", "constant"), method = "multiple"), + "standard deviation is zero" ) }) @@ -252,8 +256,187 @@ test_that("rwa() handles small but valid samples", { test_that("rwa() errors for samples too small to compute correlations", { very_small_data <- mtcars[1:3, ] + # Force multiple regression to get consistent error handling expect_error( - rwa(very_small_data, outcome = "mpg", predictors = c("cyl", "hp")), + rwa(very_small_data, outcome = "mpg", predictors = c("cyl", "hp"), method = "multiple"), "singular|collinearity|zero variance" ) }) + +# --- Method parameter and regression type ----------------------------------- + +test_that("rwa() validates method parameter", { + expect_error( + rwa(mtcars, "mpg", "cyl", method = "invalid"), + "Invalid input for `method`" + + ) + + expect_error( + rwa(mtcars, "mpg", "cyl", method = "linear"), + "Invalid input for `method`" + ) +}) + +test_that("rwa() respects method = 'multiple' for continuous outcome", { + expect_message( + result <- rwa(mtcars, "mpg", c("cyl", "hp"), method = "auto"), + "non-binary" + ) + + # Explicit multiple regression should not produce auto-detect message + expect_no_message( + result <- rwa(mtcars, "mpg", c("cyl", "hp"), method = "multiple") + ) + + expect_type(result, "list") + expect_true("rsquare" %in% names(result)) +}) + +test_that("rwa() auto-detects binary outcome for logistic regression", { + # Create binary outcome + mtcars_binary <- mtcars + +mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) + + expect_message( + result <- rwa(mtcars_binary, "high_mpg", c("cyl", "hp"), method = "auto"), + "binary" + ) + + expect_type(result, "list") + expect_true("result" %in% names(result)) +}) + +test_that("rwa() forces logistic regression with method = 'logistic'", { + # Even with continuous-looking outcome (3+ unique values), + # method = "logistic" should force logistic regression + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) + + expect_no_message( + result <- rwa(mtcars_binary, "high_mpg", c("cyl", "hp"), method = "logistic") + ) + + expect_type(result, "list") +}) + +test_that("rwa() forces multiple regression with method = 'multiple'", { + # Even with binary outcome, method = "multiple" should force multiple regression + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) + + expect_no_message( + result <- rwa(mtcars_binary, "high_mpg", c("cyl", "hp"), method = "multiple") + ) + + expect_type(result, "list") + expect_true("rsquare" %in% names(result)) + expect_true("RXX" %in% names(result)) + expect_true("RXY" %in% names(result)) +}) + +test_that("rwa() warns when bootstrap requested for logistic regression", { + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) + + expect_warning( + result <- rwa(mtcars_binary, "high_mpg", c("cyl", "hp"), + method = "logistic", bootstrap = TRUE), + "not yet implemented for logistic" + ) + + # Bootstrap should be disabled + expect_false("bootstrap" %in% names(result)) +}) + +test_that("rwa() logistic regression returns correct structure", { + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) + + result <- rwa(mtcars_binary, "high_mpg", c("cyl", "hp"), method = "logistic") + + expect_type(result, "list") + expect_true("predictors" %in% names(result)) + expect_true("result" %in% names(result)) + expect_true("n" %in% names(result)) + expect_true("lambda" %in% names(result)) + + # Logistic regression doesn't return RXX/RXY or rsquare + # (these are specific to multiple regression) +}) + +test_that("rwa() multiple vs logistic produce different results", { + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) + + result_mult <- rwa(mtcars_binary, "high_mpg", c("cyl", "hp"), method = "multiple") + result_logit <- rwa(mtcars_binary, "high_mpg", c("cyl", "hp"), method = "logistic") + + # Both should have results + expect_s3_class(result_mult$result, "data.frame") + expect_s3_class(result_logit$result, "data.frame") + + # But the weights should be different + expect_false(all(result_mult$result$Raw.RelWeight == result_logit$result$Raw.RelWeight)) +}) + +# --- Direct tests for rwa_multiregress() and rwa_logit() -------------------- + +test_that("rwa_multiregress() returns correct structure", { + result <- rwa_multiregress(mtcars, "mpg", c("cyl", "hp")) + + expect_type(result, "list") + expect_named(result, c("predictors", "rsquare", "result", "n", "lambda", "RXX", "RXY")) + expect_s3_class(result$result, "data.frame") +}) + +test_that("rwa_multiregress() computes valid weights", { + result <- rwa_multiregress(mtcars, "mpg", c("cyl", "hp")) + + # Rescaled weights sum to 100 + expect_equal(sum(result$result$Rescaled.RelWeight), 100, tolerance = 1e-10) + + # Raw weights sum to R-squared + expect_equal(sum(result$result$Raw.RelWeight), result$rsquare, tolerance = 1e-10) +}) + +test_that("rwa_logit() returns correct structure", { + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) + + result <- rwa_logit(mtcars_binary, "high_mpg", c("cyl", "hp")) + + expect_type(result, "list") + expect_true("predictors" %in% names(result)) + expect_true("result" %in% names(result)) + expect_true("n" %in% names(result)) + expect_true("lambda" %in% names(result)) + expect_s3_class(result$result, "data.frame") +}) + +test_that("rwa_logit() computes valid weights", { + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) + + result <- rwa_logit(mtcars_binary, "high_mpg", c("cyl", "hp")) + + # Raw weights should be non-negative + expect_true(all(result$result$Raw.RelWeight >= 0)) + + # Rescaled weights should sum to approximately 1 (logistic uses proportions) + # Note: rwa_logit uses proportions (0-1) not percentages (0-100) + expect_equal(sum(result$result$Rescaled.RelWeight), 1, tolerance = 1e-6) +}) + +test_that("rwa_logit() handles applysigns parameter", +{ + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) + + result_no_sign <- rwa_logit(mtcars_binary, "high_mpg", c("cyl", "hp"), applysigns = FALSE) + result_with_sign <- rwa_logit(mtcars_binary, "high_mpg", c("cyl", "hp"), applysigns = TRUE) + + expect_false("Sign.Rescaled.RelWeight" %in% names(result_no_sign$result)) + expect_true("Sign.Rescaled.RelWeight" %in% names(result_with_sign$result)) +}) From bfbc22cab2120d53e267f7619cced565bab47b3e Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 11:35:29 +0000 Subject: [PATCH 06/33] feat: update data selection to use all_of for outcome and predictors in rwa_logit() and rwa_multiregress() --- R/rwa_logit.R | 10 +++++----- R/rwa_multiregress.R | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index f528d29..b663057 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -13,25 +13,25 @@ rwa_logit <- function(df, # Gets data frame in right order and form thedata <- df %>% - dplyr::select(outcome,predictors) %>% - tidyr::drop_na(outcome) + dplyr::select(all_of(c(outcome, predictors))) %>% + tidyr::drop_na(all_of(outcome)) numVar <- NCOL(thedata) # Output - number of variables # Predictors Variables <- thedata %>% - select(predictors) + select(all_of(predictors)) # Select outcome variable Y <- thedata %>% - pull(outcome) + pull(all_of(outcome)) # Scaled predictors X <- thedata %>% - select(predictors) %>% + select(all_of(predictors)) %>% scale() X.svd <- svd(X) # Single-value decomposition diff --git a/R/rwa_multiregress.R b/R/rwa_multiregress.R index 902f924..9db6a31 100644 --- a/R/rwa_multiregress.R +++ b/R/rwa_multiregress.R @@ -45,8 +45,8 @@ rwa_multiregress <- function(df, # Gets data frame in right order and form thedata <- df %>% - dplyr::select(outcome,predictors) %>% - tidyr::drop_na(outcome) + dplyr::select(all_of(c(outcome, predictors))) %>% + tidyr::drop_na(all_of(outcome)) numVar <- NCOL(thedata) # Output - number of variables From 5e35694b6fff89bce345d153370fd64cdb1965c3 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 11:42:34 +0000 Subject: [PATCH 07/33] chore: add missing imports --- NAMESPACE | 6 ++++++ R/rwa_logit.R | 1 + 2 files changed, 7 insertions(+) diff --git a/NAMESPACE b/NAMESPACE index 8f98902..29c37a1 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -19,8 +19,14 @@ importFrom(dplyr,select) importFrom(dplyr,tibble) importFrom(magrittr,"%>%") importFrom(purrr,map_dfr) +importFrom(stats,binomial) +importFrom(stats,coef) importFrom(stats,cor) +importFrom(stats,glm) +importFrom(stats,lm) +importFrom(stats,predict) importFrom(stats,rnorm) +importFrom(stats,sd) importFrom(stats,var) importFrom(tidyr,drop_na) importFrom(utils,head) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index b663057..8a7569a 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -4,6 +4,7 @@ #' #' @inheritParams rwa #' +#' @importFrom stats glm binomial coef predict sd lm #' @export rwa_logit <- function(df, outcome, From 0e0c53ec9b67d59db0e020b16f96efec64eb42f4 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 11:44:05 +0000 Subject: [PATCH 08/33] docs: remove problematic medium link failing R-CMD-checks --- DESCRIPTION | 2 +- README.md | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index ed36d62..fe11fab 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: rwa Type: Package Title: Perform a Relative Weights Analysis -Version: 0.1.1 +Version: 0.1.2 Authors@R: person(given = "Martin", family = "Chan", role = c("aut", "cre"), diff --git a/README.md b/README.md index 61a1079..2d310a3 100644 --- a/README.md +++ b/README.md @@ -152,5 +152,3 @@ Tonidandel, S., LeBreton, J. M., & Johnson, J. W. (2009). Determining the statis Wang, X., Duverger, P., Bansal, H. S. (2013). Bayesian Inference of Predictors Relative Importance in Linear Regression Model using Dominance Hierarchies. *International Journal of Pure and Applied Mathematics*, Vol. 88, No. 3, 321-339. -Also see [Kovalyshyn](https://medium.com/analytics-vidhya/johnsons-relative-weights-analysis-implementation-with-javascript-d85393c0bbb4) for a similar implementation but in Javascript. - From 20fda7dde30658848a67bcc5d3e77cb285ae374d Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 12:09:39 +0000 Subject: [PATCH 09/33] feat: update reference section in _pkgdown.yml to include rwa_multiregress and rwa_logit --- _pkgdown.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_pkgdown.yml b/_pkgdown.yml index 5ac9da4..00221bb 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -15,6 +15,8 @@ reference: desc: "Core functions for relative weights analysis" contents: - rwa + - rwa_multiregress + - rwa_logit - plot_rwa - title: "Utility Functions" desc: "Helper functions and utilities" From 09056edad968d64d00c509d111b88a6a8c8ca7d6 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 15:35:49 +0000 Subject: [PATCH 10/33] feat: enhance plot_rwa() to handle y-axis limits based on sign and update labels --- R/plot_rwa.R | 24 ++++++++++++++++++++---- tests/testthat/test-plot_rwa.R | 19 ++++++++++++------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/R/plot_rwa.R b/R/plot_rwa.R index de961b3..02afc5e 100644 --- a/R/plot_rwa.R +++ b/R/plot_rwa.R @@ -27,20 +27,36 @@ plot_rwa <- function(rwa){ Rescaled.RelWeight * -1, Rescaled.RelWeight)) + # Calculate appropriate axis limits for both positive and negative values + max_abs_weight <- max(abs(result$Sign.Rescaled.RelWeight)) + min_weight <- min(result$Sign.Rescaled.RelWeight) max_weight <- max(result$Sign.Rescaled.RelWeight) + + # Set symmetric or appropriate limits based on data + if (min_weight < 0 && max_weight > 0) { + # Mixed signs: use symmetric limits + y_limits <- c(-max_abs_weight * 1.15, max_abs_weight * 1.15) + } else if (min_weight < 0) { + # All negative: extend left for labels + y_limits <- c(min_weight * 1.15, max(0, max_weight * 1.1)) + } else { + # All positive: extend right for labels + y_limits <- c(min(0, min_weight), max_weight * 1.15) + } result %>% ggplot(aes(x = stats::reorder(Variables, Sign.Rescaled.RelWeight), y = Sign.Rescaled.RelWeight)) + geom_col(fill = "#0066cc") + - geom_text(aes(label = round(Sign.Rescaled.RelWeight, 1)), hjust = -0.3) + + geom_text(aes(label = round(Sign.Rescaled.RelWeight, 1), + hjust = ifelse(Sign.Rescaled.RelWeight >= 0, -0.3, 1.3))) + coord_flip() + - ylim(c(NA, max_weight * 1.1)) + # Automatic lower limit + ylim(y_limits) + labs(title = "Variable importance estimates", subtitle = "Using the Relative Weights Analysis method", x = "Predictor variables", - y = "Rescaled Relative Weights", - caption = paste0("Note: Rescaled Relative Weights sum to 100%. n = ", + y = "Rescaled Relative Weights (with sign)", + caption = paste0("Note: Absolute Rescaled Relative Weights sum to 100%. n = ", rwa$n, ". ", "R-squared: ", round(rwa$rsquare, 2), diff --git a/tests/testthat/test-plot_rwa.R b/tests/testthat/test-plot_rwa.R index 72231c7..cce0bc6 100644 --- a/tests/testthat/test-plot_rwa.R +++ b/tests/testthat/test-plot_rwa.R @@ -102,10 +102,10 @@ test_that("plot_rwa() labels and aesthetics are correct", { expect_equal(p$labels$title, "Variable importance estimates") expect_equal(p$labels$subtitle, "Using the Relative Weights Analysis method") expect_equal(p$labels$x, "Predictor variables") - expect_equal(p$labels$y, "Rescaled Relative Weights") + expect_equal(p$labels$y, "Rescaled Relative Weights (with sign)") # Check that caption contains expected elements - expect_true(grepl("Rescaled Relative Weights sum to 100%", p$labels$caption)) + expect_true(grepl("Absolute Rescaled Relative Weights sum to 100%", p$labels$caption)) expect_true(grepl("n =", p$labels$caption)) expect_true(grepl("R-squared:", p$labels$caption)) @@ -146,15 +146,20 @@ test_that("plot_rwa() y-axis limits work correctly", { plot_data <- p$data # Check that y-limits accommodate the data plus some buffer + min_weight <- min(plot_data$Sign.Rescaled.RelWeight) max_weight <- max(plot_data$Sign.Rescaled.RelWeight) - # The ylim should be from NA (automatic) to max_weight * 1.1 - # But if max_weight is negative (all negative relationships), - # we should test against the absolute maximum for proper scaling - expected_upper_limit <- max_weight * 1.1 + # The ylim should properly accommodate all values with buffer for labels y_limits <- layer_scales(p)$y$limits if (!is.null(y_limits)) { - expect_equal(y_limits[2], expected_upper_limit, tolerance = 1e-10) + # For all-negative case, lower limit should extend past minimum + if (min_weight < 0 && max_weight <= 0) { + expect_true(y_limits[1] < min_weight) + } + # For all-positive case, upper limit should extend past maximum + if (min_weight >= 0 && max_weight > 0) { + expect_true(y_limits[2] > max_weight) + } } }) From 2170e8ec5ca1493e7fd6ab94bc485b6d1488bc0c Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 15:39:48 +0000 Subject: [PATCH 11/33] feat: add vignette for regression methods including multiple and logistic RWA --- _pkgdown.yml | 1 + vignettes/regression-methods.Rmd | 382 +++++++++++++++++++++++++++++++ 2 files changed, 383 insertions(+) create mode 100644 vignettes/regression-methods.Rmd diff --git a/_pkgdown.yml b/_pkgdown.yml index 00221bb..e04d585 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -30,5 +30,6 @@ articles: - title: "Advanced Methods" contents: + - regression-methods - bootstrap-confidence-intervals - evaluating-rwa-method-reference diff --git a/vignettes/regression-methods.Rmd b/vignettes/regression-methods.Rmd new file mode 100644 index 0000000..86e6534 --- /dev/null +++ b/vignettes/regression-methods.Rmd @@ -0,0 +1,382 @@ +--- +title: "Regression Methods: Multiple and Logistic RWA" +author: "Martin Chan" +date: "`r Sys.Date()`" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Regression Methods: Multiple and Logistic RWA} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + fig.path = "man/figures/README-", + out.width = "100%", + error = FALSE, + warning = FALSE, + message = FALSE +) +``` + +```{r setup} +library(rwa) +library(dplyr) +library(ggplot2) +``` + +## Introduction + +The `rwa` package provides two specialized functions for conducting Relative Weights Analysis depending on the nature of your outcome variable: + +- **`rwa_multiregress()`**: For continuous outcome variables (standard multiple regression) +- **`rwa_logit()`**: For binary outcome variables (logistic regression) + +The main `rwa()` function acts as a convenient wrapper that can automatically detect which method to use, but understanding these underlying functions gives you more control and insight into your analysis. + +## When to Use Each Method + +| Outcome Type | Function | Example Use Cases | +|--------------|----------|-------------------| +| Continuous | `rwa_multiregress()` | Predicting prices, scores, measurements | +| Binary (0/1) | `rwa_logit()` | Predicting yes/no, pass/fail, purchase/no purchase | + +## Multiple Regression with `rwa_multiregress()` + +### Basic Example with mtcars + +The `mtcars` dataset contains continuous variables ideal for demonstrating multiple regression RWA. Let's examine what factors most influence fuel efficiency (mpg): + +```{r multiregress-basic} +# Direct use of rwa_multiregress() +result_multi <- rwa_multiregress( + df = mtcars, + outcome = "mpg", + predictors = c("cyl", "disp", "hp", "wt") +) + +# View results +result_multi$result +``` + +### Interpreting Multiple Regression Results + +The output contains several key pieces of information: + +```{r multiregress-interpret} +# R-squared: Total variance explained +cat("R-squared:", round(result_multi$rsquare, 4), "\n") +cat("This means", round(result_multi$rsquare * 100, 1), + "% of variance in mpg is explained by these predictors.\n\n") + +# Number of observations +cat("Sample size:", result_multi$n, "\n\n") + +# Relative importance breakdown +cat("Relative Importance (Rescaled Weights sum to 100%):\n") +result_multi$result %>% + arrange(desc(Rescaled.RelWeight)) %>% + mutate(Rescaled.RelWeight = round(Rescaled.RelWeight, 2)) %>% + select(Variables, Rescaled.RelWeight) +``` + +The **Rescaled.RelWeight** column shows the percentage of explainable variance attributed to each predictor. In this example, we can see that weight (`wt`) is the most important predictor of fuel efficiency, followed by displacement (`disp`). + +### Using the `applysigns` Parameter + +By default, relative weights are always positive (they represent variance contributions). Use `applysigns = TRUE` to see the direction of each relationship: + +```{r multiregress-signs} +# With sign information +result_signed <- rwa_multiregress( + df = mtcars, + outcome = "mpg", + predictors = c("cyl", "disp", "hp", "wt"), + applysigns = TRUE +) + +result_signed$result %>% + select(Variables, Raw.RelWeight, Sign.Rescaled.RelWeight, Sign) +``` + +The `Sign` column indicates whether each predictor has a positive (+) or negative (-) relationship with the outcome. Negative signs for `cyl`, `disp`, `hp`, and `wt` make intuitive sense: more cylinders, larger displacement, more horsepower, and heavier weight all tend to decrease fuel efficiency. + +### Examining Correlation Structures + +The function also returns the correlation matrices, which can help understand relationships between predictors: + +```{r multiregress-correlations} +# Correlation between predictors +cat("Predictor Correlation Matrix (RXX):\n") +round(result_multi$RXX, 3) + +# Correlation of predictors with outcome +cat("\nPredictor-Outcome Correlations (RXY):\n") +round(result_multi$RXY, 3) +``` + +## Logistic Regression with `rwa_logit()` + +### Creating a Binary Outcome + +For logistic regression, we need a binary outcome variable. Let's create one from the `mtcars` dataset: + +```{r logit-setup} +# Create binary outcome: high efficiency (1) vs low efficiency (0) +mtcars_binary <- mtcars %>% + mutate(high_mpg = ifelse(mpg > median(mpg), 1, 0)) + +# Check distribution +table(mtcars_binary$high_mpg) +``` + +### Basic Logistic RWA + +```{r logit-basic} +# Logistic regression RWA +result_logit <- rwa_logit( + df = mtcars_binary, + outcome = "high_mpg", + predictors = c("cyl", "disp", "hp", "wt") +) + +# View results +result_logit$result +``` + +### Interpreting Logistic RWA Results + +The interpretation differs slightly from multiple regression: + +```{r logit-interpret} +# Lambda (analogous to R-squared for logistic regression) +cat("Lambda (pseudo R-squared):", round(result_logit$lambda, 4), "\n") +cat("Sample size:", result_logit$n, "\n\n") + +# Relative importance +cat("Relative Importance for Predicting High Fuel Efficiency:\n") +result_logit$result %>% + arrange(desc(Rescaled.RelWeight)) %>% + mutate(Rescaled.RelWeight = round(Rescaled.RelWeight, 4)) +``` + +Note that for logistic regression, the **Rescaled.RelWeight** values sum to 1 (rather than 100), representing the proportion of predictable variance attributed to each predictor. + +### Logistic RWA with Signs + +```{r logit-signs} +# With direction information +result_logit_signed <- rwa_logit( + df = mtcars_binary, + outcome = "high_mpg", + predictors = c("cyl", "disp", "hp", "wt"), + applysigns = TRUE +) + +result_logit_signed$result %>% + select(predictors, Rescaled.RelWeight, Sign) +``` + +## Using the `rwa()` Wrapper Function + +The main `rwa()` function provides a convenient interface that can automatically detect whether to use multiple or logistic regression based on your outcome variable. + +### Auto-Detection of Binary Outcomes + +```{r rwa-auto} +# For continuous outcome - automatically uses multiple regression +result_auto_multi <- rwa( + df = mtcars, + outcome = "mpg", + predictors = c("cyl", "disp", "hp", "wt") +) + +# For binary outcome - automatically uses logistic regression +result_auto_logit <- rwa( + df = mtcars_binary, + outcome = "high_mpg", + predictors = c("cyl", "disp", "hp", "wt") +) +``` + +### Explicit Method Selection + +You can also explicitly specify the method using the `method` parameter: + +```{r rwa-explicit} +# Force multiple regression +result_explicit_multi <- rwa( + df = mtcars, + outcome = "mpg", + predictors = c("cyl", "disp", "hp", "wt"), + method = "multiple" +) + +# Force logistic regression (requires binary outcome) +result_explicit_logit <- rwa( + df = mtcars_binary, + outcome = "high_mpg", + predictors = c("cyl", "disp", "hp", "wt"), + method = "logistic" +) +``` + +### Additional Features in `rwa()` + +The wrapper function also provides sorting and visualization options: + +```{r rwa-features} +# Sort results by importance +result_sorted <- rwa( + df = mtcars, + outcome = "mpg", + predictors = c("cyl", "disp", "hp", "wt"), + sort = TRUE +) + +result_sorted$result + +# Visualize with plot_rwa() +plot_rwa(result_sorted) +``` + +## Real-World Example: Iris Dataset + +Let's apply these methods to the classic `iris` dataset. + +### Multiple Regression: Predicting Petal Length + +```{r iris-multi} +# Predict petal length from other measurements +iris_result <- rwa_multiregress( + df = iris, + outcome = "Petal.Length", + predictors = c("Sepal.Length", "Sepal.Width", "Petal.Width"), + applysigns = TRUE +) + +cat("R-squared:", round(iris_result$rsquare, 4), "\n\n") +iris_result$result + +# Visualize +plot_rwa(iris_result) +``` + +### Logistic Regression: Predicting Species + +For logistic regression, we need a binary outcome. Let's predict whether a flower is *Iris setosa* or not: + +```{r iris-logit} +# Create binary outcome for setosa classification +iris_binary <- iris %>% + mutate(is_setosa = ifelse(Species == "setosa", 1, 0)) + +# Logistic RWA +iris_logit <- rwa_logit( + df = iris_binary, + outcome = "is_setosa", + predictors = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"), + applysigns = TRUE +) + +cat("Lambda:", round(iris_logit$lambda, 4), "\n\n") +iris_logit$result +``` + +This analysis reveals which measurements are most important for distinguishing *Iris setosa* from the other species. + +## Comparing Methods + +Let's demonstrate how the same predictors can yield different importance rankings depending on the outcome type: + +```{r compare-methods} +# Create comparison dataset +comparison_data <- mtcars %>% + mutate(high_mpg = ifelse(mpg > median(mpg), 1, 0)) + +# Multiple regression on continuous mpg +multi_result <- rwa_multiregress( + comparison_data, "mpg", + c("cyl", "disp", "hp", "wt") +) + +# Logistic regression on binary high_mpg +logit_result <- rwa_logit( + comparison_data, "high_mpg", + c("cyl", "disp", "hp", "wt") +) + +# Compare rankings +comparison <- data.frame( + Variable = multi_result$result$Variables, + Multiple_Pct = round(multi_result$result$Rescaled.RelWeight, 1), + Logistic_Pct = round(logit_result$result$Rescaled.RelWeight * 100, 1) +) + +comparison %>% + arrange(desc(Multiple_Pct)) +``` + +The relative importance of predictors may differ between continuous and binary outcomes because: + +1. **Different relationships**: A predictor's linear relationship with the continuous outcome may differ from its relationship with the probability of the binary outcome. +2. **Threshold effects**: Binary outcomes are sensitive to whether predictors help distinguish cases near the classification boundary. + +## Best Practices + +### 1. Choose the Right Method + +- Use `rwa_multiregress()` for continuous outcomes +- Use `rwa_logit()` for binary (0/1) outcomes +- Let `rwa()` auto-detect when unsure + +### 2. Check Your Data + +```{r best-practices} +# Always check outcome distribution for binary variables +table(mtcars_binary$high_mpg) + +# Ensure reasonable sample size +cat("Sample size:", nrow(mtcars), "\n") +cat("Predictors:", 4, "\n") +cat("Observations per predictor:", nrow(mtcars) / 4, "\n") +``` + +A general guideline is to have at least 10-20 observations per predictor. + +### 3. Consider Bootstrap for Inference + +For statistical significance testing, combine with bootstrap methods (note: currently only available for multiple regression): + +```{r bootstrap-multi} +# Bootstrap with multiple regression +result_boot <- rwa( + df = mtcars, + outcome = "mpg", + predictors = c("cyl", "disp", "hp", "wt"), + bootstrap = TRUE, + n_bootstrap = 1000 +) + +result_boot$result +``` + +## Summary + +| Function | Outcome Type | Key Output | Weights Sum To | +|----------|--------------|------------|----------------| +| `rwa_multiregress()` | Continuous | R², Raw & Rescaled Weights | 100% | +| `rwa_logit()` | Binary (0/1) | Lambda, Raw & Rescaled Weights | 1 (100%) | +| `rwa()` | Either | Auto-detects + sorting + bootstrap | Depends on method | + +Both methods provide valuable insights into predictor importance while accounting for multicollinearity. Choose the appropriate method based on your outcome variable type, and consider using bootstrap confidence intervals for formal statistical inference. + +## References + +* Johnson, J. W. (2000). A heuristic method for estimating the relative weight of predictor variables in multiple regression. *Multivariate Behavioral Research*, 35(1), 1-19. + +* Tonidandel, S., & LeBreton, J. M. (2011). Relative importance analysis: A useful supplement to regression analysis. *Journal of Business and Psychology*, 26(1), 1-9. + +* Tonidandel, S., & LeBreton, J. M. (2015). RWA Web: A free, comprehensive, web-based, and user-friendly tool for relative weight analyses. *Journal of Business and Psychology*, 30(2), 207-216. From 2c9b032e0177032a3623a5e29332bd406d37ad89 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 15:48:59 +0000 Subject: [PATCH 12/33] chore: bump version to v0.1.2.9000 --- DESCRIPTION | 2 +- NEWS.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index fe11fab..b2b9c15 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: rwa Type: Package Title: Perform a Relative Weights Analysis -Version: 0.1.2 +Version: 0.1.2.9000 Authors@R: person(given = "Martin", family = "Chan", role = c("aut", "cre"), diff --git a/NEWS.md b/NEWS.md index 0873520..d271212 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,5 @@ +# rwa (development version) + # rwa 0.1.1 ## Improvements From a69a04babcbb2a735eb9102f10b439913d514135 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 15:53:10 +0000 Subject: [PATCH 13/33] docs: update NEWS.md --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index d271212..5d49cfb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # rwa (development version) +- Added `rwa_logit()` and `rwa_multiregress()` for support logistic regression and multiple regression. +- Added new vignette to cover the new regression methods. +- Improved test coverage and minor bugfixes. + # rwa 0.1.1 ## Improvements From df427ddbd0c226b34a2580f5c1719e110597c9a8 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 16:10:57 +0000 Subject: [PATCH 14/33] refactor: remove unused variable numVar from rwa_logit and rwa_multiregress functions --- R/rwa_logit.R | 2 -- R/rwa_multiregress.R | 2 -- 2 files changed, 4 deletions(-) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index 8a7569a..341b680 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -17,8 +17,6 @@ rwa_logit <- function(df, dplyr::select(all_of(c(outcome, predictors))) %>% tidyr::drop_na(all_of(outcome)) - numVar <- NCOL(thedata) # Output - number of variables - # Predictors Variables <- thedata %>% diff --git a/R/rwa_multiregress.R b/R/rwa_multiregress.R index 9db6a31..088ac2c 100644 --- a/R/rwa_multiregress.R +++ b/R/rwa_multiregress.R @@ -48,8 +48,6 @@ rwa_multiregress <- function(df, dplyr::select(all_of(c(outcome, predictors))) %>% tidyr::drop_na(all_of(outcome)) - numVar <- NCOL(thedata) # Output - number of variables - cor_matrix <- cor(thedata, use = "pairwise.complete.obs") %>% as.data.frame(stringsAsFactors = FALSE, row.names = NULL) %>% From 35f0743927f773c7076cc01df97ae932fd123e9d Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 16:14:43 +0000 Subject: [PATCH 15/33] docs: enhance documentation for rwa_logit and rwa_multiregress functions with examples and additional output details --- R/rwa_logit.R | 32 ++++++++++++++++++++++++++++++++ R/rwa_multiregress.R | 20 ++++++++++++++++++-- man/rwa_logit.Rd | 38 ++++++++++++++++++++++++++++++++++++++ man/rwa_multiregress.Rd | 20 ++++++++++++++++++-- 4 files changed, 106 insertions(+), 4 deletions(-) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index 341b680..cec7932 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -4,6 +4,38 @@ #' #' @inheritParams rwa #' +#' @return `rwa_logit()` returns a list of outputs, as follows: +#' - `predictors`: character vector of names of the predictor variables used. +#' - `result`: the final output of the importance metrics. +#' - The `Rescaled.RelWeight` column sums up to 1. +#' - The `Sign` column indicates whether a predictor is positively or negatively associated with the outcome. +#' - `n`: indicates the number of observations used in the analysis. +#' - `lambda`: pseudo R-squared value for the logistic regression model. +#' +#' @examples +#' # Create a binary outcome variable +#' mtcars_binary <- mtcars +#' mtcars_binary$high_mpg <- ifelse(mtcars$mpg > median(mtcars$mpg), 1, 0) +#' +#' # Basic logistic RWA +#' result <- rwa_logit( +#' df = mtcars_binary, +#' outcome = "high_mpg", +#' predictors = c("cyl", "disp", "hp", "wt") +#' ) +#' +#' # View the relative importance results +#' result$result +#' +#' # With sign information +#' result_signed <- rwa_logit( +#' df = mtcars_binary, +#' outcome = "high_mpg", +#' predictors = c("cyl", "disp", "hp", "wt"), +#' applysigns = TRUE +#' ) +#' result_signed$result +#' #' @importFrom stats glm binomial coef predict sd lm #' @export rwa_logit <- function(df, diff --git a/R/rwa_multiregress.R b/R/rwa_multiregress.R index 088ac2c..90d551c 100644 --- a/R/rwa_multiregress.R +++ b/R/rwa_multiregress.R @@ -33,8 +33,24 @@ #' @importFrom stats cor #' @import dplyr #' @examples -#' library(ggplot2) -#' rwa(diamonds,"price",c("depth","carat")) +#' # Basic multiple regression RWA +#' result <- rwa_multiregress( +#' df = mtcars, +#' outcome = "mpg", +#' predictors = c("cyl", "disp", "hp", "wt") +#' ) +#' +#' # View the relative importance results +#' result$result +#' +#' # With sign information +#' result_signed <- rwa_multiregress( +#' df = mtcars, +#' outcome = "mpg", +#' predictors = c("cyl", "disp", "hp", "wt"), +#' applysigns = TRUE +#' ) +#' result_signed$result #' #' @export rwa_multiregress <- function(df, diff --git a/man/rwa_logit.Rd b/man/rwa_logit.Rd index ca7846d..dcbdf95 100644 --- a/man/rwa_logit.Rd +++ b/man/rwa_logit.Rd @@ -18,6 +18,19 @@ string(s) or bare input(s). All variables must be numeric.} \item{applysigns}{Logical value specifying whether to show an estimate that applies the sign. Defaults to \code{FALSE}.} } +\value{ +\code{rwa_logit()} returns a list of outputs, as follows: +\itemize{ +\item \code{predictors}: character vector of names of the predictor variables used. +\item \code{result}: the final output of the importance metrics. +\itemize{ +\item The \code{Rescaled.RelWeight} column sums up to 1. +\item The \code{Sign} column indicates whether a predictor is positively or negatively associated with the outcome. +} +\item \code{n}: indicates the number of observations used in the analysis. +\item \code{lambda}: pseudo R-squared value for the logistic regression model. +} +} \description{ This function creates a Relative Weights Analysis (RWA) and returns a list of outputs. RWA provides a heuristic method for estimating @@ -27,3 +40,28 @@ predictors which are orthogonal to each other but maximally related to the original set of predictors. \code{rwa()} is optimised for dplyr pipes and shows positive / negative signs for weights. } +\examples{ +# Create a binary outcome variable +mtcars_binary <- mtcars +mtcars_binary$high_mpg <- ifelse(mtcars$mpg > median(mtcars$mpg), 1, 0) + +# Basic logistic RWA +result <- rwa_logit( + df = mtcars_binary, + outcome = "high_mpg", + predictors = c("cyl", "disp", "hp", "wt") +) + +# View the relative importance results +result$result + +# With sign information +result_signed <- rwa_logit( + df = mtcars_binary, + outcome = "high_mpg", + predictors = c("cyl", "disp", "hp", "wt"), + applysigns = TRUE +) +result_signed$result + +} diff --git a/man/rwa_multiregress.Rd b/man/rwa_multiregress.Rd index 4d46fe3..34e0925 100644 --- a/man/rwa_multiregress.Rd +++ b/man/rwa_multiregress.Rd @@ -45,7 +45,23 @@ Signs are added to the weights when the \code{applysigns} argument is set to \co See https://relativeimportance.davidson.edu/multipleregression.html for the original implementation that inspired this package. } \examples{ -library(ggplot2) -rwa(diamonds,"price",c("depth","carat")) +# Basic multiple regression RWA +result <- rwa_multiregress( + df = mtcars, + outcome = "mpg", + predictors = c("cyl", "disp", "hp", "wt") +) + +# View the relative importance results +result$result + +# With sign information +result_signed <- rwa_multiregress( + df = mtcars, + outcome = "mpg", + predictors = c("cyl", "disp", "hp", "wt"), + applysigns = TRUE +) +result_signed$result } From 22849b06cd0b083517a4c08985a4135d8b81832f Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 16:15:40 +0000 Subject: [PATCH 16/33] fix: specify tidyr::drop_na for complete cases calculation in rwa_logit and rwa_multiregress functions --- R/rwa_logit.R | 2 +- R/rwa_multiregress.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index cec7932..51d522b 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -128,7 +128,7 @@ rwa_logit <- function(df, Rescaled.RelWeight = PropWeights) %>% mutate(Sign = sign) - complete_cases <- nrow(drop_na(thedata)) + complete_cases <- nrow(tidyr::drop_na(thedata)) if(applysigns == TRUE){ result <- diff --git a/R/rwa_multiregress.R b/R/rwa_multiregress.R index 90d551c..a9b20b4 100644 --- a/R/rwa_multiregress.R +++ b/R/rwa_multiregress.R @@ -111,7 +111,7 @@ rwa_multiregress <- function(df, Rescaled.RelWeight = import, Sign = sign) # Output - results - nrow(drop_na(thedata)) -> complete_cases + nrow(tidyr::drop_na(thedata)) -> complete_cases if(applysigns == TRUE){ result %>% From 3a707acbcfb684afd6bc37b79c3fe23f9c2215b8 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 16:25:11 +0000 Subject: [PATCH 17/33] fix: handle variable name extraction for different regression types in plot_rwa function --- R/plot_rwa.R | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/R/plot_rwa.R b/R/plot_rwa.R index 02afc5e..c9cdea1 100644 --- a/R/plot_rwa.R +++ b/R/plot_rwa.R @@ -26,6 +26,15 @@ plot_rwa <- function(rwa){ dplyr::mutate(Sign.Rescaled.RelWeight = ifelse(Sign == "-", Rescaled.RelWeight * -1, Rescaled.RelWeight)) + + # Handle different column names: 'Variables' (multiple regression) vs 'predictors' (logistic) + if ("Variables" %in% names(result)) { + result$variable_name <- result$Variables + } else if ("predictors" %in% names(result)) { + result$variable_name <- result$predictors + } else { + stop("Could not find variable names in result. Expected 'Variables' or 'predictors' column.") + } # Calculate appropriate axis limits for both positive and negative values max_abs_weight <- max(abs(result$Sign.Rescaled.RelWeight)) @@ -45,7 +54,7 @@ plot_rwa <- function(rwa){ } result %>% - ggplot(aes(x = stats::reorder(Variables, Sign.Rescaled.RelWeight), + ggplot(aes(x = stats::reorder(variable_name, Sign.Rescaled.RelWeight), y = Sign.Rescaled.RelWeight)) + geom_col(fill = "#0066cc") + geom_text(aes(label = round(Sign.Rescaled.RelWeight, 1), @@ -58,8 +67,12 @@ plot_rwa <- function(rwa){ y = "Rescaled Relative Weights (with sign)", caption = paste0("Note: Absolute Rescaled Relative Weights sum to 100%. n = ", rwa$n, ". ", - "R-squared: ", - round(rwa$rsquare, 2), - ".")) + + if (!is.null(rwa$rsquare)) { + paste0("R-squared: ", round(rwa$rsquare, 2), ".") + } else if (!is.null(rwa$lambda)) { + paste0("Lambda: ", round(rwa$lambda, 2), ".") + } else { + "" + })) + theme_classic() } From 20afed4d0b18f8330d670d02ec3832b2dcdff3ab Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 16:25:23 +0000 Subject: [PATCH 18/33] docs: update return values in rwa_logit documentation to clarify pseudo R-squared and Lambda matrix --- R/rwa_logit.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index 51d522b..f4ae6c4 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -6,11 +6,12 @@ #' #' @return `rwa_logit()` returns a list of outputs, as follows: #' - `predictors`: character vector of names of the predictor variables used. +#' - `rsquare`: the pseudo R-squared value (sum of epsilon weights) for the logistic regression model. #' - `result`: the final output of the importance metrics. #' - The `Rescaled.RelWeight` column sums up to 1. #' - The `Sign` column indicates whether a predictor is positively or negatively associated with the outcome. #' - `n`: indicates the number of observations used in the analysis. -#' - `lambda`: pseudo R-squared value for the logistic regression model. +#' - `lambda`: the Lambda transformation matrix from the analysis. #' #' @examples #' # Create a binary outcome variable @@ -139,7 +140,7 @@ rwa_logit <- function(df, } list("predictors" = predictors, - # "rsquare" = rsquare, + "rsquare" = R.sq, "result" = result, "n" = complete_cases, "lambda" = Lambda) From c3485c33258c742e1a385d2bf5d61deae1493b99 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 16:25:32 +0000 Subject: [PATCH 19/33] test: add tests for logistic regression results in plot_rwa function --- tests/testthat/test-plot_rwa.R | 72 +++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-plot_rwa.R b/tests/testthat/test-plot_rwa.R index cce0bc6..76b7955 100644 --- a/tests/testthat/test-plot_rwa.R +++ b/tests/testthat/test-plot_rwa.R @@ -55,14 +55,14 @@ test_that("plot_rwa() plot structure is correct", { # Check plot data plot_data <- p$data expect_s3_class(plot_data, "data.frame") - expect_true("Variables" %in% names(plot_data)) + expect_true("variable_name" %in% names(plot_data)) expect_true("Sign.Rescaled.RelWeight" %in% names(plot_data)) # Check that plot has correct number of bars expect_equal(nrow(plot_data), length(rwa_result$predictors)) # Check mapping using rlang::as_label instead of as.character - expect_equal(rlang::as_label(p$mapping$x), "stats::reorder(Variables, Sign.Rescaled.RelWeight)") + expect_equal(rlang::as_label(p$mapping$x), "stats::reorder(variable_name, Sign.Rescaled.RelWeight)") expect_equal(rlang::as_label(p$mapping$y), "Sign.Rescaled.RelWeight") # Check coordinate system (should be flipped) @@ -178,3 +178,71 @@ test_that("plot_rwa() text labels are present", { text_layer <- p$layers[geom_classes == "GeomText"][[1]] expect_true("label" %in% names(text_layer$mapping)) }) + +# Tests for logistic regression plotting +test_that("plot_rwa() works with logistic regression results", { + # Create binary outcome + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- ifelse(mtcars$mpg > median(mtcars$mpg), 1, 0) + + # Run logistic RWA + rwa_logit_result <- rwa_logit( + df = mtcars_binary, + outcome = "high_mpg", + predictors = c("cyl", "hp", "wt") + ) + + # plot_rwa() should work without error + expect_no_error(p <- plot_rwa(rwa_logit_result)) + expect_s3_class(p, "ggplot") + + # Check that all predictors are represented + expect_equal(nrow(p$data), 3) +}) + +test_that("plot_rwa() caption shows R-squared for logistic regression", { + # Create binary outcome + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- ifelse(mtcars$mpg > median(mtcars$mpg), 1, 0) + + # Run logistic RWA + rwa_logit_result <- rwa_logit( + df = mtcars_binary, + outcome = "high_mpg", + predictors = c("cyl", "hp", "wt") + ) + + p <- plot_rwa(rwa_logit_result) + + # Caption should contain R-squared (logistic regression now returns rsquare too) + expect_true(grepl("R-squared:", p$labels$caption)) +}) + +test_that("plot_rwa() caption shows R-squared for multiple regression", { + rwa_result <- mtcars %>% + rwa(outcome = "mpg", predictors = c("cyl", "hp", "wt")) + + p <- plot_rwa(rwa_result) + + # Caption should contain R-squared, not Lambda + expect_true(grepl("R-squared:", p$labels$caption)) + expect_false(grepl("Lambda:", p$labels$caption)) +}) + +test_that("plot_rwa() handles logistic regression with applysigns", { + # Create binary outcome + mtcars_binary <- mtcars + mtcars_binary$high_mpg <- ifelse(mtcars$mpg > median(mtcars$mpg), 1, 0) + + # Run logistic RWA with signs + rwa_logit_result <- rwa_logit( + df = mtcars_binary, + outcome = "high_mpg", + predictors = c("cyl", "hp", "wt"), + applysigns = TRUE + ) + + # plot_rwa() should work without error + expect_no_error(p <- plot_rwa(rwa_logit_result)) + expect_s3_class(p, "ggplot") +}) From fbe9f60d4255943abae261d1d227ad0ac1d916c8 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 17:06:01 +0000 Subject: [PATCH 20/33] fix: update Rescaled.RelWeight to sum to 100 for consistency with rwa_multiregress --- R/rwa_logit.R | 4 ++-- tests/testthat/test-rwa.R | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index f4ae6c4..50eb8a1 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -8,7 +8,7 @@ #' - `predictors`: character vector of names of the predictor variables used. #' - `rsquare`: the pseudo R-squared value (sum of epsilon weights) for the logistic regression model. #' - `result`: the final output of the importance metrics. -#' - The `Rescaled.RelWeight` column sums up to 1. +#' - The `Rescaled.RelWeight` column sums up to 100. #' - The `Sign` column indicates whether a predictor is positively or negatively associated with the outcome. #' - `n`: indicates the number of observations used in the analysis. #' - `lambda`: the Lambda transformation matrix from the analysis. @@ -111,7 +111,7 @@ rwa_logit <- function(df, epsilon <- Lambda^2 %*% beta^2 R.sq <- sum(epsilon) - PropWeights <- (epsilon/R.sq) + PropWeights <- (epsilon/R.sq) * 100 # Convert to percentage (0-100) for consistency with rwa_multiregress # Get signs from coefficients sign <- diff --git a/tests/testthat/test-rwa.R b/tests/testthat/test-rwa.R index c431d78..6670523 100644 --- a/tests/testthat/test-rwa.R +++ b/tests/testthat/test-rwa.R @@ -424,9 +424,8 @@ test_that("rwa_logit() computes valid weights", { # Raw weights should be non-negative expect_true(all(result$result$Raw.RelWeight >= 0)) - # Rescaled weights should sum to approximately 1 (logistic uses proportions) - # Note: rwa_logit uses proportions (0-1) not percentages (0-100) - expect_equal(sum(result$result$Rescaled.RelWeight), 1, tolerance = 1e-6) + # Rescaled weights should sum to 100 (now consistent with rwa_multiregress) + expect_equal(sum(result$result$Rescaled.RelWeight), 100, tolerance = 1e-6) }) test_that("rwa_logit() handles applysigns parameter", From 7d30e5e12848b7498e194d34b0881bb51a53919e Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 17:06:07 +0000 Subject: [PATCH 21/33] fix: update Rescaled.RelWeight representation in logistic regression to sum to 100% --- vignettes/regression-methods.Rmd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vignettes/regression-methods.Rmd b/vignettes/regression-methods.Rmd index 86e6534..fdcdfe3 100644 --- a/vignettes/regression-methods.Rmd +++ b/vignettes/regression-methods.Rmd @@ -159,10 +159,10 @@ cat("Sample size:", result_logit$n, "\n\n") cat("Relative Importance for Predicting High Fuel Efficiency:\n") result_logit$result %>% arrange(desc(Rescaled.RelWeight)) %>% - mutate(Rescaled.RelWeight = round(Rescaled.RelWeight, 4)) + mutate(Rescaled.RelWeight = round(Rescaled.RelWeight, 2)) ``` -Note that for logistic regression, the **Rescaled.RelWeight** values sum to 1 (rather than 100), representing the proportion of predictable variance attributed to each predictor. +Like multiple regression, the **Rescaled.RelWeight** values sum to 100%, representing the percentage of predictable variance attributed to each predictor. ### Logistic RWA with Signs @@ -312,7 +312,7 @@ logit_result <- rwa_logit( comparison <- data.frame( Variable = multi_result$result$Variables, Multiple_Pct = round(multi_result$result$Rescaled.RelWeight, 1), - Logistic_Pct = round(logit_result$result$Rescaled.RelWeight * 100, 1) + Logistic_Pct = round(logit_result$result$Rescaled.RelWeight, 1) ) comparison %>% @@ -368,8 +368,8 @@ result_boot$result | Function | Outcome Type | Key Output | Weights Sum To | |----------|--------------|------------|----------------| | `rwa_multiregress()` | Continuous | R², Raw & Rescaled Weights | 100% | -| `rwa_logit()` | Binary (0/1) | Lambda, Raw & Rescaled Weights | 1 (100%) | -| `rwa()` | Either | Auto-detects + sorting + bootstrap | Depends on method | +| `rwa_logit()` | Binary (0/1) | R², Raw & Rescaled Weights | 100% | +| `rwa()` | Either | Auto-detects + sorting + bootstrap | 100% | Both methods provide valuable insights into predictor importance while accounting for multicollinearity. Choose the appropriate method based on your outcome variable type, and consider using bootstrap confidence intervals for formal statistical inference. From fad0116c513cedc899ff71436833b065231030dd Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 17:06:33 +0000 Subject: [PATCH 22/33] chore: correct indentation Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/testthat/test-rwa.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testthat/test-rwa.R b/tests/testthat/test-rwa.R index c431d78..ea11cac 100644 --- a/tests/testthat/test-rwa.R +++ b/tests/testthat/test-rwa.R @@ -297,7 +297,7 @@ test_that("rwa() auto-detects binary outcome for logistic regression", { # Create binary outcome mtcars_binary <- mtcars -mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) + mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) expect_message( result <- rwa(mtcars_binary, "high_mpg", c("cyl", "hp"), method = "auto"), From 100d522afda7a286450fe5e33dc5a8c0cb0d913b Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 17:08:32 +0000 Subject: [PATCH 23/33] fix: properly import NAMESPACE --- R/rwa_logit.R | 1 + man/rwa_logit.Rd | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index 50eb8a1..7c67694 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -37,6 +37,7 @@ #' ) #' result_signed$result #' +#' @importFrom magrittr %>% #' @importFrom stats glm binomial coef predict sd lm #' @export rwa_logit <- function(df, diff --git a/man/rwa_logit.Rd b/man/rwa_logit.Rd index dcbdf95..875f68d 100644 --- a/man/rwa_logit.Rd +++ b/man/rwa_logit.Rd @@ -22,13 +22,14 @@ applies the sign. Defaults to \code{FALSE}.} \code{rwa_logit()} returns a list of outputs, as follows: \itemize{ \item \code{predictors}: character vector of names of the predictor variables used. +\item \code{rsquare}: the pseudo R-squared value (sum of epsilon weights) for the logistic regression model. \item \code{result}: the final output of the importance metrics. \itemize{ -\item The \code{Rescaled.RelWeight} column sums up to 1. +\item The \code{Rescaled.RelWeight} column sums up to 100. \item The \code{Sign} column indicates whether a predictor is positively or negatively associated with the outcome. } \item \code{n}: indicates the number of observations used in the analysis. -\item \code{lambda}: pseudo R-squared value for the logistic regression model. +\item \code{lambda}: the Lambda transformation matrix from the analysis. } } \description{ From e5961549b5d4e36f5d8ecc276fa7c37897b64d56 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 17:09:41 +0000 Subject: [PATCH 24/33] chore: update opening brace style --- tests/testthat/test-rwa.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/testthat/test-rwa.R b/tests/testthat/test-rwa.R index 6670523..1ab63c8 100644 --- a/tests/testthat/test-rwa.R +++ b/tests/testthat/test-rwa.R @@ -428,8 +428,7 @@ test_that("rwa_logit() computes valid weights", { expect_equal(sum(result$result$Rescaled.RelWeight), 100, tolerance = 1e-6) }) -test_that("rwa_logit() handles applysigns parameter", -{ +test_that("rwa_logit() handles applysigns parameter", { mtcars_binary <- mtcars mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) From d1917121351b4262215cf6e04f27ffb801748ed5 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 17:15:22 +0000 Subject: [PATCH 25/33] docs: add lambda return value description in rwa_multiregress Complete the documentation for the lambda return value, explaining that it is the transformation matrix mapping original correlated predictors to orthogonal variables while preserving their relationship to the outcome. --- R/rwa_multiregress.R | 2 +- man/rwa_multiregress.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/rwa_multiregress.R b/R/rwa_multiregress.R index a9b20b4..6a38b8b 100644 --- a/R/rwa_multiregress.R +++ b/R/rwa_multiregress.R @@ -24,7 +24,7 @@ #' - The `Rescaled.RelWeight` column sums up to 100. #' - The `Sign` column indicates whether a predictor is positively or negatively correlated with the outcome. #' - `n`: indicates the number of observations used in the analysis. -#' - `lambda`: +#' - `lambda`: the transformation matrix that maps the original correlated predictors to orthogonal variables while preserving their relationship to the outcome. Used internally to compute relative weights. #' - `RXX`: Correlation matrix of all the predictor variables against each other. #' - `RXY`: Correlation values of the predictor variables against the outcome variable. #' diff --git a/man/rwa_multiregress.Rd b/man/rwa_multiregress.Rd index 34e0925..dc41225 100644 --- a/man/rwa_multiregress.Rd +++ b/man/rwa_multiregress.Rd @@ -26,7 +26,7 @@ rwa_multiregress(df, outcome, predictors, applysigns = FALSE) \item The \code{Sign} column indicates whether a predictor is positively or negatively correlated with the outcome. } \item \code{n}: indicates the number of observations used in the analysis. -\item \code{lambda}: +\item \code{lambda}: the transformation matrix that maps the original correlated predictors to orthogonal variables while preserving their relationship to the outcome. Used internally to compute relative weights. \item \code{RXX}: Correlation matrix of all the predictor variables against each other. \item \code{RXY}: Correlation values of the predictor variables against the outcome variable. } From 73d220027dc1741689b10509184bb88208f65391 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 17:58:44 +0000 Subject: [PATCH 26/33] docs: Update NEWS.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 5d49cfb..fd6a45f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,6 @@ # rwa (development version) -- Added `rwa_logit()` and `rwa_multiregress()` for support logistic regression and multiple regression. +- Added `rwa_logit()` and `rwa_multiregress()` to support logistic regression and multiple regression. - Added new vignette to cover the new regression methods. - Improved test coverage and minor bugfixes. From 95e3fe8daf87db53801c2e6a4e2a7b4b590bf066 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Wed, 21 Jan 2026 18:37:58 +0000 Subject: [PATCH 27/33] fix: standardize API and fix documentation inconsistencies Address code review feedback for API consistency and documentation: - rwa_logit: Use 'Variables' column name (matching rwa_multiregress) - rwa_logit: Use the existing Variables variable instead of 'predictors' - rwa_multiregress: Fix docs to reference rwa_multiregress() not rwa() - plot_rwa: Remove lambda fallback in caption (lambda is a matrix, not scalar) - vignette: Fix iris_logit\ to iris_logit\ (pseudo R-squared) - test-rwa: Fix incorrect comment (logistic regression does return rsquare) This ensures consistent API across both regression methods and accurate documentation throughout the package. --- R/plot_rwa.R | 2 -- R/rwa_logit.R | 7 ++++--- R/rwa_multiregress.R | 4 ++-- man/rwa_multiregress.Rd | 4 ++-- tests/testthat/test-rwa.R | 4 +++- vignettes/regression-methods.Rmd | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/R/plot_rwa.R b/R/plot_rwa.R index c9cdea1..b6a8585 100644 --- a/R/plot_rwa.R +++ b/R/plot_rwa.R @@ -69,8 +69,6 @@ plot_rwa <- function(rwa){ rwa$n, ". ", if (!is.null(rwa$rsquare)) { paste0("R-squared: ", round(rwa$rsquare, 2), ".") - } else if (!is.null(rwa$lambda)) { - paste0("Lambda: ", round(rwa$lambda, 2), ".") } else { "" })) + diff --git a/R/rwa_logit.R b/R/rwa_logit.R index 7c67694..2cd2e82 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -51,10 +51,11 @@ rwa_logit <- function(df, dplyr::select(all_of(c(outcome, predictors))) %>% tidyr::drop_na(all_of(outcome)) - # Predictors + # Get variable names for output Variables <- thedata %>% - select(all_of(predictors)) + select(all_of(predictors)) %>% + names() # Select outcome variable Y <- @@ -125,7 +126,7 @@ rwa_logit <- function(df, ## Result result <- - data.frame(predictors, + data.frame(Variables, Raw.RelWeight = epsilon, Rescaled.RelWeight = PropWeights) %>% mutate(Sign = sign) diff --git a/R/rwa_multiregress.R b/R/rwa_multiregress.R index 6a38b8b..2429692 100644 --- a/R/rwa_multiregress.R +++ b/R/rwa_multiregress.R @@ -4,10 +4,10 @@ #' RWA provides a heuristic method for estimating the relative weight of predictor variables in multiple regression, which involves #' creating a multiple regression with on a set of transformed predictors which are orthogonal to each other but #' maximally related to the original set of predictors. -#' `rwa()` is optimised for dplyr pipes and shows positive / negative signs for weights. +#' `rwa_multiregress()` is optimised for dplyr pipes and shows positive / negative signs for weights. #' #' @details -#' `rwa()` produces raw relative weight values (epsilons) as well as rescaled weights (scaled as a percentage of predictable variance) +#' `rwa_multiregress()` produces raw relative weight values (epsilons) as well as rescaled weights (scaled as a percentage of predictable variance) #' for every predictor in the model. #' Signs are added to the weights when the `applysigns` argument is set to `TRUE`. #' See https://relativeimportance.davidson.edu/multipleregression.html for the original implementation that inspired this package. diff --git a/man/rwa_multiregress.Rd b/man/rwa_multiregress.Rd index dc41225..da3353a 100644 --- a/man/rwa_multiregress.Rd +++ b/man/rwa_multiregress.Rd @@ -36,10 +36,10 @@ This function creates a Relative Weights Analysis (RWA) and returns a list of ou RWA provides a heuristic method for estimating the relative weight of predictor variables in multiple regression, which involves creating a multiple regression with on a set of transformed predictors which are orthogonal to each other but maximally related to the original set of predictors. -\code{rwa()} is optimised for dplyr pipes and shows positive / negative signs for weights. +\code{rwa_multiregress()} is optimised for dplyr pipes and shows positive / negative signs for weights. } \details{ -\code{rwa()} produces raw relative weight values (epsilons) as well as rescaled weights (scaled as a percentage of predictable variance) +\code{rwa_multiregress()} produces raw relative weight values (epsilons) as well as rescaled weights (scaled as a percentage of predictable variance) for every predictor in the model. Signs are added to the weights when the \code{applysigns} argument is set to \code{TRUE}. See https://relativeimportance.davidson.edu/multipleregression.html for the original implementation that inspired this package. diff --git a/tests/testthat/test-rwa.R b/tests/testthat/test-rwa.R index 004b66a..dccb04d 100644 --- a/tests/testthat/test-rwa.R +++ b/tests/testthat/test-rwa.R @@ -362,8 +362,10 @@ test_that("rwa() logistic regression returns correct structure", { expect_true("n" %in% names(result)) expect_true("lambda" %in% names(result)) - # Logistic regression doesn't return RXX/RXY or rsquare + # Logistic regression doesn't return RXX/RXY # (these are specific to multiple regression) + # But it does return rsquare (pseudo R-squared) + expect_true("rsquare" %in% names(result)) }) test_that("rwa() multiple vs logistic produce different results", { diff --git a/vignettes/regression-methods.Rmd b/vignettes/regression-methods.Rmd index fdcdfe3..d483c88 100644 --- a/vignettes/regression-methods.Rmd +++ b/vignettes/regression-methods.Rmd @@ -176,7 +176,7 @@ result_logit_signed <- rwa_logit( ) result_logit_signed$result %>% - select(predictors, Rescaled.RelWeight, Sign) + select(Variables, Rescaled.RelWeight, Sign) ``` ## Using the `rwa()` Wrapper Function @@ -281,7 +281,7 @@ iris_logit <- rwa_logit( applysigns = TRUE ) -cat("Lambda:", round(iris_logit$lambda, 4), "\n\n") +cat("Pseudo R-squared:", round(iris_logit$rsquare, 4), "\n\n") iris_logit$result ``` From 41c071f81567ce63212f5326ed5c11efa7971e0e Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Thu, 22 Jan 2026 10:32:41 +0000 Subject: [PATCH 28/33] fix: improve code quality and numerical stability in rwa_logit Code quality: Add dplyr:: prefix to select/mutate, stats:: to sd. Remove extraneous blank lines in test-rwa.R. Numerical stability: Clamp predicted probabilities to avoid Inf/-Inf in logit transformation. Add warning and fallback for zero stddev (perfect separation). --- R/rwa_logit.R | 24 +++++++++++++++++++----- tests/testthat/test-rwa.R | 2 -- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index 2cd2e82..da8c219 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -1,6 +1,10 @@ #' @title Create a Relative Weights Analysis with logistic regression #' -#' @inherit rwa description +#' @description This function performs Relative Weights Analysis (RWA) for binary +#' outcome variables using logistic regression. RWA provides a method for +#' estimating the relative importance of predictor variables by transforming +#' them into orthogonal variables while preserving their relationship to the +#' outcome. This implementation follows Johnson (2000) for logistic regression. #' #' @inheritParams rwa #' @@ -54,7 +58,7 @@ rwa_logit <- function(df, # Get variable names for output Variables <- thedata %>% - select(all_of(predictors)) %>% + dplyr::select(all_of(predictors)) %>% names() # Select outcome variable @@ -65,7 +69,7 @@ rwa_logit <- function(df, # Scaled predictors X <- thedata %>% - select(all_of(predictors)) %>% + dplyr::select(all_of(predictors)) %>% scale() X.svd <- svd(X) # Single-value decomposition @@ -97,11 +101,21 @@ rwa_logit <- function(df, newdata = thedata, type="response") + # Clamp predictions to avoid Inf/-Inf in logit transformation + # This can occur with perfect separation in logistic regression + LpredY <- pmax(pmin(LpredY, 1 - 1e-10), 1e-10) + # Creating logit-Y-hat lYhat <- log(LpredY/(1-LpredY)) # Getting st dev of logit-Y-hat - stdlYhat <- sd(lYhat) + stdlYhat <- stats::sd(lYhat) + + # Check for zero standard deviation (can occur with perfect separation) + if (stdlYhat == 0 || is.na(stdlYhat)) { + warning("Perfect or near-perfect separation detected. Results may be unreliable.") + stdlYhat <- 1e-10 # Avoid division by zero + } # Getting R-sq getting.Rsq <- lm(LpredY ~ Y) @@ -129,7 +143,7 @@ rwa_logit <- function(df, data.frame(Variables, Raw.RelWeight = epsilon, Rescaled.RelWeight = PropWeights) %>% - mutate(Sign = sign) + dplyr::mutate(Sign = sign) complete_cases <- nrow(tidyr::drop_na(thedata)) diff --git a/tests/testthat/test-rwa.R b/tests/testthat/test-rwa.R index dccb04d..4141f9c 100644 --- a/tests/testthat/test-rwa.R +++ b/tests/testthat/test-rwa.R @@ -269,7 +269,6 @@ test_that("rwa() validates method parameter", { expect_error( rwa(mtcars, "mpg", "cyl", method = "invalid"), "Invalid input for `method`" - ) expect_error( @@ -296,7 +295,6 @@ test_that("rwa() respects method = 'multiple' for continuous outcome", { test_that("rwa() auto-detects binary outcome for logistic regression", { # Create binary outcome mtcars_binary <- mtcars - mtcars_binary$high_mpg <- as.numeric(mtcars_binary$mpg > 20) expect_message( From 043125e5ccce1aa15a3d29e203646835bf4c1383 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Thu, 22 Jan 2026 10:35:03 +0000 Subject: [PATCH 29/33] docs: improve documentation accuracy and consistency - rwa_logit: Write specific description instead of inheriting from rwa() - plot_rwa: Simplify comment (both functions now use Variables column) - vignette: Remove README-specific fig.path parameter --- R/plot_rwa.R | 11 ++++------- man/rwa_logit.Rd | 12 +++++------- vignettes/regression-methods.Rmd | 1 - 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/R/plot_rwa.R b/R/plot_rwa.R index b6a8585..e630163 100644 --- a/R/plot_rwa.R +++ b/R/plot_rwa.R @@ -27,14 +27,11 @@ plot_rwa <- function(rwa){ Rescaled.RelWeight * -1, Rescaled.RelWeight)) - # Handle different column names: 'Variables' (multiple regression) vs 'predictors' (logistic) - if ("Variables" %in% names(result)) { - result$variable_name <- result$Variables - } else if ("predictors" %in% names(result)) { - result$variable_name <- result$predictors - } else { - stop("Could not find variable names in result. Expected 'Variables' or 'predictors' column.") + # Get variable names from the Variables column + if (!"Variables" %in% names(result)) { + stop("Could not find 'Variables' column in result.") } + result$variable_name <- result$Variables # Calculate appropriate axis limits for both positive and negative values max_abs_weight <- max(abs(result$Sign.Rescaled.RelWeight)) diff --git a/man/rwa_logit.Rd b/man/rwa_logit.Rd index 875f68d..6e1b411 100644 --- a/man/rwa_logit.Rd +++ b/man/rwa_logit.Rd @@ -33,13 +33,11 @@ applies the sign. Defaults to \code{FALSE}.} } } \description{ -This function creates a Relative Weights Analysis (RWA) and -returns a list of outputs. RWA provides a heuristic method for estimating -the relative weight of predictor variables in multiple regression, which -involves creating a multiple regression with on a set of transformed -predictors which are orthogonal to each other but maximally related to the -original set of predictors. \code{rwa()} is optimised for dplyr pipes and shows -positive / negative signs for weights. +This function performs Relative Weights Analysis (RWA) for binary +outcome variables using logistic regression. RWA provides a method for +estimating the relative importance of predictor variables by transforming +them into orthogonal variables while preserving their relationship to the +outcome. This implementation follows Johnson (2000) for logistic regression. } \examples{ # Create a binary outcome variable diff --git a/vignettes/regression-methods.Rmd b/vignettes/regression-methods.Rmd index d483c88..3d2a967 100644 --- a/vignettes/regression-methods.Rmd +++ b/vignettes/regression-methods.Rmd @@ -13,7 +13,6 @@ vignette: > knitr::opts_chunk$set( collapse = TRUE, comment = "#>", - fig.path = "man/figures/README-", out.width = "100%", error = FALSE, warning = FALSE, From 5ed0f575e35bab97f68c13bb52df3dd4c60c2788 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Thu, 22 Jan 2026 10:42:19 +0000 Subject: [PATCH 30/33] chore: remove whitespace Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- vignettes/regression-methods.Rmd | 1 - 1 file changed, 1 deletion(-) diff --git a/vignettes/regression-methods.Rmd b/vignettes/regression-methods.Rmd index 3d2a967..97d68ea 100644 --- a/vignettes/regression-methods.Rmd +++ b/vignettes/regression-methods.Rmd @@ -27,7 +27,6 @@ library(ggplot2) ``` ## Introduction - The `rwa` package provides two specialized functions for conducting Relative Weights Analysis depending on the nature of your outcome variable: - **`rwa_multiregress()`**: For continuous outcome variables (standard multiple regression) From 6f8379e91f679cf5d85e206cb58575a9b02030f5 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Thu, 22 Jan 2026 10:44:52 +0000 Subject: [PATCH 31/33] refactor: align to R best practices for assignment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- R/rwa_multiregress.R | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/R/rwa_multiregress.R b/R/rwa_multiregress.R index 2429692..4f2f108 100644 --- a/R/rwa_multiregress.R +++ b/R/rwa_multiregress.R @@ -98,26 +98,27 @@ rwa_multiregress <- function(df, RawWgt <- lambdasq %*% beta ^ 2 # Raw Relative Weight import <- (RawWgt / rsquare) * 100 # Rescaled Relative Weight - beta %>% # Get signs from coefficients + sign <- beta %>% # Get signs from coefficients as.data.frame(stringsAsFactors = FALSE, row.names = NULL) %>% dplyr::mutate_all(~(dplyr::case_when(.>0~"+", .<0~"-", .==0~"0", TRUE~NA_character_))) %>% - dplyr::rename(Sign="V1")-> sign + dplyr::rename(Sign="V1") result <- data.frame(Variables, Raw.RelWeight = RawWgt, Rescaled.RelWeight = import, Sign = sign) # Output - results - nrow(tidyr::drop_na(thedata)) -> complete_cases + complete_cases <- nrow(tidyr::drop_na(thedata)) if(applysigns == TRUE){ - result %>% + result <- + result %>% dplyr::mutate(Sign.Rescaled.RelWeight = ifelse(Sign == "-", Rescaled.RelWeight * -1, - Rescaled.RelWeight)) -> result + Rescaled.RelWeight)) } list("predictors" = Variables, From 5d49b184e77ee6c145b1d60557cccabbd9babfcc Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Thu, 22 Jan 2026 10:52:37 +0000 Subject: [PATCH 32/33] chore: cosmetic change on variable names Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- R/rwa_logit.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/R/rwa_logit.R b/R/rwa_logit.R index da8c219..aeb02a2 100644 --- a/R/rwa_logit.R +++ b/R/rwa_logit.R @@ -155,9 +155,11 @@ rwa_logit <- function(df, Rescaled.RelWeight)) } + lambda <- Lambda + list("predictors" = predictors, "rsquare" = R.sq, "result" = result, "n" = complete_cases, - "lambda" = Lambda) + "lambda" = lambda) } From c71529b529cb7cacda217eff667c5bd90d3c4729 Mon Sep 17 00:00:00 2001 From: Martin Chan Date: Thu, 22 Jan 2026 12:05:06 +0000 Subject: [PATCH 33/33] fix: add missing global variable 'variable_name' to avoid false positives --- R/globals.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/globals.R b/R/globals.R index 67bea59..ce9c9e2 100644 --- a/R/globals.R +++ b/R/globals.R @@ -9,6 +9,7 @@ utils::globalVariables( "Sign", "Rescaled.RelWeight", "Variables", - "Sign.Rescaled.RelWeight" + "Sign.Rescaled.RelWeight", + "variable_name" ) )