From d9618932166c5ee4958b8b4b329bedda04843167 Mon Sep 17 00:00:00 2001 From: bbuchsbaum Date: Fri, 20 Dec 2024 14:40:23 -0500 Subject: [PATCH] feature_rsa --- NAMESPACE | 8 ++-- R/feature_rsa_model.R | 62 +++++++++++++++++++++++++ R/mvpa_model.R | 1 + man/evaluate_model.feature_rsa_model.Rd | 4 +- man/feature_rsa_design.Rd | 50 +++++++------------- man/feature_rsa_iterate.Rd | 18 ------- man/feature_rsa_model.Rd | 57 +++++------------------ man/merge_results.feature_rsa_model.Rd | 25 ++++++++++ man/predict_model.feature_rsa_model.Rd | 6 +-- man/print.feature_rsa_model.Rd | 2 +- man/run_regional.feature_rsa_model.Rd | 34 ++++++++++++++ man/summary.feature_rsa_model.Rd | 2 +- man/train_model.feature_rsa_model.Rd | 23 --------- 13 files changed, 162 insertions(+), 130 deletions(-) delete mode 100644 man/feature_rsa_iterate.Rd create mode 100644 man/merge_results.feature_rsa_model.Rd create mode 100644 man/run_regional.feature_rsa_model.Rd delete mode 100644 man/train_model.feature_rsa_model.Rd diff --git a/NAMESPACE b/NAMESPACE index b9d0640..b9ff4f6 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -8,6 +8,7 @@ S3method(crossval_samples,mvpa_model) S3method(crossval_samples,sequential_blocked_cross_validation) S3method(crossval_samples,twofold_blocked_cross_validation) S3method(data_sample,mvpa_dataset) +S3method(format_result,feature_rsa_model) S3method(get_samples,mvpa_dataset) S3method(get_samples,mvpa_surface_dataset) S3method(get_searchlight,mvpa_image_dataset) @@ -20,6 +21,7 @@ S3method(has_test_set,mvpa_model) S3method(merge_predictions,classification_prediction) S3method(merge_predictions,regression_prediction) S3method(merge_results,binary_classification_result) +S3method(merge_results,feature_rsa_model) S3method(merge_results,multiway_classification_result) S3method(merge_results,regional_mvpa_result) S3method(merge_results,regression_result) @@ -58,6 +60,7 @@ S3method(print,searchlight_result) S3method(print,twofold_blocked_cross_validation) S3method(prob_observed,binary_classification_result) S3method(prob_observed,multiway_classification_result) +S3method(run_regional,feature_rsa_model) S3method(run_regional,mvpa_model) S3method(run_regional,rsa_model) S3method(run_searchlight,model_spec) @@ -69,11 +72,13 @@ S3method(sub_result,binary_classification_result) S3method(sub_result,multiway_classification_result) S3method(summary,feature_rsa_model) S3method(test_design,mvpa_design) +S3method(train_model,feature_rsa_model) S3method(train_model,rsa_model) S3method(train_model,vector_rsa_model) S3method(tune_grid,mvpa_model) S3method(y_test,mvpa_design) S3method(y_test,mvpa_model) +S3method(y_train,feature_rsa_model) S3method(y_train,mvpa_design) S3method(y_train,mvpa_model) export(MVPAModels) @@ -150,9 +155,7 @@ importFrom(Rfit,rfit) importFrom(assertthat,assert_that) importFrom(corpcor,invcov.shrink) importFrom(dplyr,bind_rows) -importFrom(dplyr,do) importFrom(dplyr,filter) -importFrom(dplyr,rowwise) importFrom(ffmanova,ffmanova) importFrom(furrr,future_map) importFrom(furrr,future_pmap) @@ -167,7 +170,6 @@ importFrom(neuroim2,NeuroVol) importFrom(neuroim2,ROIVec) importFrom(neuroim2,SparseNeuroVec) importFrom(neuroim2,coords) -importFrom(neuroim2,indices) importFrom(neuroim2,map_values) importFrom(neuroim2,read_vec) importFrom(neuroim2,read_vol) diff --git a/R/feature_rsa_model.R b/R/feature_rsa_model.R index 42cfe83..b9bbf3f 100644 --- a/R/feature_rsa_model.R +++ b/R/feature_rsa_model.R @@ -230,6 +230,7 @@ y_train.feature_rsa_model <- function(object) { object$F } +#' @export format_result.feature_rsa_model <- function(obj, result, error_message=NULL, context, ...) { if (!is.null(error_message)) { return(tibble::tibble( @@ -261,6 +262,67 @@ format_result.feature_rsa_model <- function(obj, result, error_message=NULL, con } } +#' Merge Multiple Results for Feature RSA Model +#' +#' @param obj A \code{feature_rsa_model} object +#' @param result_set A data frame of results from cross-validation folds +#' @param indices The voxel indices used (may not be relevant for feature_rsa_model) +#' @param id An identifier for the merged result (e.g., ROI id) +#' @param ... Additional arguments +#' @return A tibble with merged results +#' @export +merge_results.feature_rsa_model <- function(obj, result_set, indices, id, ...) { + # If any errors occurred, return an error tibble + if (any(result_set$error)) { + emessage <- result_set$error_message[which(result_set$error)[1]] + return(tibble::tibble( + result=list(NULL), + indices=list(indices), + performance=list(NULL), + id=id, + error=TRUE, + error_message=emessage, + warning=any(result_set$warning), + warning_message=if(any(result_set$warning)) result_set$warning_message[which(result_set$warning)[1]] else "~" + )) + } + + # If no errors, combine all fold predictions and observed values + # Each fold should have columns: observed, predicted, performance, etc. + # result_set might have multiple rows (one per fold) + + # Extract observed and predicted from each fold + # They are stored as lists, each element a matrix + observed_list <- result_set$observed + predicted_list <- result_set$predicted + + # Combine rows (observations) across folds + combined_observed <- do.call(rbind, observed_list) + combined_predicted <- do.call(rbind, predicted_list) + + # Compute performance on the combined set + perf <- evaluate_model(obj, combined_predicted, combined_observed) + + # Create a single combined result. We can store the combined predictions and observed as well. + # 'result' typically is some kind of result object; here we can store the combined predictions. + # For consistency, let's mimic mvpa_model: store combined predictions/observed in 'result' as well. + combined_result <- list( + observed = combined_observed, + predicted = combined_predicted + ) + + tibble::tibble( + result = list(combined_result), + indices = list(indices), + performance = list(perf), + id = id, + error = FALSE, + error_message = "~", + warning = any(result_set$warning), + warning_message = if(any(result_set$warning)) result_set$warning_message[which(result_set$warning)[1]] else "~" + ) +} + #' Print Method for Feature RSA Model #' #' @param x The feature RSA model diff --git a/R/mvpa_model.R b/R/mvpa_model.R index 04fc443..ff6d551 100644 --- a/R/mvpa_model.R +++ b/R/mvpa_model.R @@ -92,6 +92,7 @@ format_result.mvpa_model <- function(obj, result, error_message=NULL, context, . } + #' @keywords internal get_multiclass_perf <- function(split_list=NULL, class_metrics=TRUE) { function(result) { diff --git a/man/evaluate_model.feature_rsa_model.Rd b/man/evaluate_model.feature_rsa_model.Rd index bfb6546..f14bc1f 100644 --- a/man/evaluate_model.feature_rsa_model.Rd +++ b/man/evaluate_model.feature_rsa_model.Rd @@ -13,11 +13,11 @@ evaluate_model.feature_rsa_model(object, predicted, observed, ...) \item{observed}{Observed values} -\item{...}{Additional arguments} +\item{...}{Additional args} } \value{ Performance metrics } \description{ -Evaluates performance of a feature RSA model +Evaluate Method for Feature RSA Model } diff --git a/man/feature_rsa_design.Rd b/man/feature_rsa_design.Rd index 611f880..850c787 100644 --- a/man/feature_rsa_design.Rd +++ b/man/feature_rsa_design.Rd @@ -4,52 +4,34 @@ \alias{feature_rsa_design} \title{Create a Feature-Based RSA Design} \usage{ -feature_rsa_design(S, labels, k = 0) +feature_rsa_design(S = NULL, F = NULL, labels, k = 0) } \arguments{ -\item{S}{A symmetric similarity matrix representing the feature space relationships} +\item{S}{A symmetric similarity matrix representing the feature space relationships. +If NULL, you must supply F.} -\item{labels}{Vector of labels corresponding to the rows/columns of S} +\item{F}{A feature space matrix (observations by features). If supplied, this overrides S and k.} -\item{k}{Integer specifying the number of feature dimensions to retain. If 0 (default), -automatically determines dimensions using eigenvalue threshold > 1} +\item{labels}{Vector of labels corresponding to the rows/columns of S or observations of F.} + +\item{k}{Integer specifying the number of feature dimensions to retain when using S. If 0 (default), +automatically determines dimensions using eigenvalue threshold > 1.} } \value{ A \code{feature_rsa_design} object (S3 class) containing: \describe{ - \item{S}{The input similarity matrix} - \item{F}{Feature space projection matrix (eigenvectors)} + \item{S}{The input similarity matrix (if used)} + \item{F}{Feature space projection matrix} \item{labels}{Vector of observation labels} } } \description{ -Creates a design for feature-based Representational Similarity Analysis (RSA) that maps neural patterns -to a predefined feature space using dimensionality reduction techniques. +Creates a design for feature-based Representational Similarity Analysis (RSA). +You can either supply a similarity matrix S (and optionally select dimensions) +or directly supply a feature matrix F. } \details{ -Unlike standard RSA which compares dissimilarity matrices directly, feature RSA projects neural patterns -into a lower-dimensional feature space defined by the eigenvectors of the similarity matrix S. -The number of dimensions k can be specified explicitly or determined automatically based on -eigenvalues > 1. The resulting design is used with methods like sparse CCA or PLS to relate -neural patterns to this feature space. -} -\examples{ -# Create similarity matrix from feature vectors -features <- matrix(rnorm(100*10), 100, 10) # 100 observations, 10 features -S <- tcrossprod(scale(features)) # similarity matrix -labels <- paste0("obs", 1:100) - -# Create design with automatic dimension selection -design <- feature_rsa_design(S, labels) - -# Create design with fixed number of dimensions -design_k5 <- feature_rsa_design(S, labels, k=5) - -} -\seealso{ -\code{\link{feature_rsa_model}} for creating the full model - -\code{\link{rsa_design}} for standard RSA designs - -\code{\link{vector_rsa_design}} for vector-based RSA designs +If F is supplied directly, it is used as is. +If only S is supplied, the design computes eigen decomposition of S to find a suitable +feature space (F). } diff --git a/man/feature_rsa_iterate.Rd b/man/feature_rsa_iterate.Rd deleted file mode 100644 index f3c99e5..0000000 --- a/man/feature_rsa_iterate.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/feature_rsa_model.R -\name{feature_rsa_iterate} -\alias{feature_rsa_iterate} -\title{feature_rsa_iterate} -\usage{ -feature_rsa_iterate(mod_spec, vox_list, ids = 1:length(vox_list)) -} -\arguments{ -\item{mod_spec}{An object of class \code{rsa_model} specifying the RSA model.} - -\item{vox_list}{A \code{list} of voxel indices or coordinates for each voxel set.} - -\item{ids}{A \code{vector} of IDs for each voxel set (defaults to 1:length(vox_list)).} -} -\description{ -Runs feature-based representational similarity analysis (RSA) for each voxel set in a list. -} diff --git a/man/feature_rsa_model.Rd b/man/feature_rsa_model.Rd index 7556291..db00b07 100644 --- a/man/feature_rsa_model.Rd +++ b/man/feature_rsa_model.Rd @@ -12,63 +12,30 @@ feature_rsa_model( ) } \arguments{ -\item{dataset}{An \code{mvpa_dataset} object containing the neural data} +\item{dataset}{An \code{mvpa_dataset} object containing the neural data (X).} -\item{design}{A \code{feature_rsa_design} object specifying the feature space and its structure} +\item{design}{A \code{feature_rsa_design} object specifying the feature space (F).} \item{method}{Character string specifying the analysis method. One of: \describe{ - \item{scca}{Sparse Canonical Correlation Analysis (default)} + \item{scca}{Sparse Canonical Correlation Analysis} \item{pls}{Partial Least Squares} - \item{pca}{Principal Component Analysis} + \item{pca}{Principal Component Analysis + linear regression on F} }} -\item{crossval}{Optional cross-validation specification. If NULL and design contains block_var, -creates blocked cross-validation using that variable} +\item{crossval}{Optional cross-validation specification.} } \value{ -A \code{feature_rsa_model} object (S3 class) containing: - \describe{ - \item{dataset}{The input \code{mvpa_dataset}} - \item{design}{The input \code{feature_rsa_design}} - \item{crossval}{Cross-validation specification} - } +A \code{feature_rsa_model} object (S3 class). } \description{ Creates a model for feature-based Representational Similarity Analysis (RSA) that relates neural patterns -to a predefined feature space using dimensionality reduction and multivariate techniques. +(X) to a predefined feature space (F). } \details{ -Feature RSA models analyze the relationship between neural patterns and a predefined feature space -using multivariate techniques. Unlike traditional RSA which compares dissimilarity matrices, -this approach directly relates neural patterns to feature space dimensions through methods like -sparse CCA or PLS. Cross-validation can be specified explicitly or derived from the design's -block structure. -} -\examples{ -# Create feature space and design -features <- matrix(rnorm(100*10), 100, 10) -S <- tcrossprod(scale(features)) -labels <- paste0("obs", 1:100) -design <- feature_rsa_design(S, labels) - -# Create dataset (assuming you have neural data) -dataset <- mvpa_dataset(train_data, mask=mask_vol) - -# Create model with sparse CCA -model <- feature_rsa_model(dataset, design, method="scca") - -# Create model with PLS and explicit cross-validation -cv <- blocked_cross_validation(block_var) -model_pls <- feature_rsa_model(dataset, design, - method="pls", - crossval=cv) - -} -\seealso{ -\code{\link{feature_rsa_design}} for creating the feature space design - -\code{\link{rsa_model}} for traditional RSA models - -\code{\link{vector_rsa_model}} for vector-based RSA models +Feature RSA models analyze the relationship between neural patterns X and a predefined feature space F. +Methods: + - scca: Finds canonical correlations between X and F and reconstructs F from X via these canonical directions. + - pls: Uses partial least squares regression to predict F from X. + - pca: PCA on X, then regress F_sc ~ PC(X_sc) for prediction. } diff --git a/man/merge_results.feature_rsa_model.Rd b/man/merge_results.feature_rsa_model.Rd new file mode 100644 index 0000000..2f538d3 --- /dev/null +++ b/man/merge_results.feature_rsa_model.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/feature_rsa_model.R +\name{merge_results.feature_rsa_model} +\alias{merge_results.feature_rsa_model} +\title{Merge Multiple Results for Feature RSA Model} +\usage{ +\method{merge_results}{feature_rsa_model}(obj, result_set, indices, id, ...) +} +\arguments{ +\item{obj}{A \code{feature_rsa_model} object} + +\item{result_set}{A data frame of results from cross-validation folds} + +\item{indices}{The voxel indices used (may not be relevant for feature_rsa_model)} + +\item{id}{An identifier for the merged result (e.g., ROI id)} + +\item{...}{Additional arguments} +} +\value{ +A tibble with merged results +} +\description{ +Merge Multiple Results for Feature RSA Model +} diff --git a/man/predict_model.feature_rsa_model.Rd b/man/predict_model.feature_rsa_model.Rd index 09b7916..2d3a2bd 100644 --- a/man/predict_model.feature_rsa_model.Rd +++ b/man/predict_model.feature_rsa_model.Rd @@ -9,13 +9,13 @@ predict_model.feature_rsa_model(object, newdata, ...) \arguments{ \item{object}{The trained feature RSA model} -\item{newdata}{New data to make predictions on} +\item{newdata}{New data} -\item{...}{Additional arguments passed to prediction method} +\item{...}{Additional args} } \value{ Predicted values in the feature space } \description{ -Makes predictions using a trained feature RSA model +Predict Method for Feature RSA Model } diff --git a/man/print.feature_rsa_model.Rd b/man/print.feature_rsa_model.Rd index 96e1c39..3febeea 100644 --- a/man/print.feature_rsa_model.Rd +++ b/man/print.feature_rsa_model.Rd @@ -9,7 +9,7 @@ \arguments{ \item{x}{The feature RSA model} -\item{...}{Additional arguments} +\item{...}{Additional args} } \description{ Print Method for Feature RSA Model diff --git a/man/run_regional.feature_rsa_model.Rd b/man/run_regional.feature_rsa_model.Rd new file mode 100644 index 0000000..8f527ac --- /dev/null +++ b/man/run_regional.feature_rsa_model.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/feature_rsa_model.R +\name{run_regional.feature_rsa_model} +\alias{run_regional.feature_rsa_model} +\title{Run regional RSA analysis on a specified Feature RSA model} +\usage{ +\method{run_regional}{feature_rsa_model}( + model_spec, + region_mask, + coalesce_design_vars = FALSE, + processor = NULL, + verbose = FALSE, + ... +) +} +\arguments{ +\item{model_spec}{A \code{feature_rsa_model} object.} + +\item{region_mask}{A mask representing different brain regions.} + +\item{coalesce_design_vars}{If TRUE, merges design variables into prediction table.} + +\item{processor}{A custom processor function for ROIs. If NULL, uses defaults.} + +\item{verbose}{Print progress messages.} + +\item{...}{Additional arguments} +} +\description{ +This function runs a regional analysis using a feature RSA model and region mask. +} +\details{ +This integrates `feature_rsa_model` with the MVPA framework, similar to `run_regional.mvpa_model`. +} diff --git a/man/summary.feature_rsa_model.Rd b/man/summary.feature_rsa_model.Rd index b183155..e4ccabf 100644 --- a/man/summary.feature_rsa_model.Rd +++ b/man/summary.feature_rsa_model.Rd @@ -9,7 +9,7 @@ \arguments{ \item{object}{The feature RSA model} -\item{...}{Additional arguments} +\item{...}{Additional args} } \description{ Summary Method for Feature RSA Model diff --git a/man/train_model.feature_rsa_model.Rd b/man/train_model.feature_rsa_model.Rd deleted file mode 100644 index 0144e5e..0000000 --- a/man/train_model.feature_rsa_model.Rd +++ /dev/null @@ -1,23 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/feature_rsa_model.R -\name{train_model.feature_rsa_model} -\alias{train_model.feature_rsa_model} -\title{Train an RSA Model} -\usage{ -\method{train_model}{feature_rsa_model}(obj, train_dat, indices, ...) -} -\arguments{ -\item{obj}{An object of class \code{feature_rsa_model}} - -\item{train_dat}{The training data} - -\item{indices}{The indices of the training data} - -\item{...}{Additional arguments passed to the training method} -} -\value{ -The trained model with updated components -} -\description{ -This function trains an RSA (representational similarity analysis) model using the specified method. -}