如何为twoway包编写长表转宽表的公式方法
Fixing the
twoway.formula Method for Long-Form Data Got it, let's get that formula method working for your twoway package! The main hurdle here is dynamically translating the formula components into a reshape operation that converts your long-form data into the wide format expected by twoway.default(). Here's a complete, working implementation with explanations:
Key Fixes & Explanation
- Correctly extract formula components: We'll pull the response variable, row variable, and column variable directly from the parsed terms object to avoid confusion.
- Dynamically build the reshape formula: Since we can't pass raw variable names directly to reshape functions in the function environment, we'll construct a formula string and convert it to a formula object.
- Clean up the wide data: Ensure row names match the row variable values, and drop any extra ID columns before passing to the default method.
Complete Working Code
#' Formula method for twoway analysis of long-form data #' #' Analyze a two-way table from long-form data using a formula of the form #' \code{response ~ row + column} #' #' @param formula A formula of the form \code{response ~ rowvar + colvar} #' @param data The data frame containing the variables in the formula #' @param subset An expression to subset the data (unused) #' @param na.action What to do with NAs? (unused) #' @param ... other arguments, passed down to twoway.default() #' @importFrom stats terms #' @importFrom reshape2 dcast #' twoway.formula <- function(formula, data, subset, na.action, ...) { # Validate formula input if (missing(formula) || !inherits(formula, "formula")) stop("'formula' is missing or not a valid formula object") if (length(formula) != 3L) stop("Formula must have both a left-hand (response) and right-hand (row + column) side") # Parse terms to extract variables tt <- terms(formula, data = data) term_labels <- attr(tt, "term.labels") # Ensure no interactions and exactly two RHS variables if (any(attr(tt, "order") > 1)) stop("Interactions are not allowed in the formula") if (length(term_labels) != 2) stop("Formula must include exactly two right-hand side variables (row + column)") # Extract variable names response_var <- as.character(formula[[2]]) row_var <- term_labels[1] col_var <- term_labels[2] # Get the data (handle subset/na.action if needed later) edata <- eval(match.call()$data, parent.frame()) # Dynamically build the dcast formula: row_var ~ col_var reshape_formula <- as.formula(paste(row_var, "~", col_var)) # Reshape long to wide wide_data <- dcast(data = edata, formula = reshape_formula, value.var = response_var) # Set row names to the row variable values, drop the ID column rownames(wide_data) <- wide_data[[row_var]] wide_matrix <- as.matrix(wide_data[, -1, drop = FALSE]) # Call the default method with the wide matrix twoway.default(wide_matrix, ...) }
How to Test It
Using your example data:
# Create the long-form data as you did library(reshape2) data(taskRT) long <- melt(as.matrix(taskRT)) colnames(long) <- c("task", "topic", "RT") # Now call the formula method twoway(RT ~ task + topic, data = long)
This should produce the exact same output as twoway(taskRT).
Alternative: Using tidyr::pivot_wider (Modern Approach)
If you prefer using tidyr over reshape2, replace the dcast section with:
library(tidyr) wide_data <- pivot_wider(edata, id_cols = all_of(row_var), names_from = all_of(col_var), values_from = all_of(response_var))
Just make sure to add @importFrom tidyr pivot_wider to the function's roxygen comments.
内容的提问来源于stack exchange,提问作者user101089
相关产品推荐
相关产品推荐

