├── .Rbuildignore ├── .gitignore ├── cleanup ├── NAMESPACE ├── util ├── document.R └── RcppPackageSkeleton.R ├── permFDP.Rproj ├── DESCRIPTION ├── R ├── RcppExports.R └── permFDP.R ├── man ├── RcppPackage-package.Rd └── permFDP.adjust.threshold.Rd ├── README.md └── src ├── RcppExports.cpp └── permFDP.cpp /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^util/.*.R$ 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## remove compilation artifacts 4 | rm -f src/*.o src/*.so -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | useDynLib(permFDP, .registration=TRUE) 2 | importFrom(Rcpp, evalCpp) 3 | exportPattern("^[[:alpha:]]+") 4 | -------------------------------------------------------------------------------- /util/document.R: -------------------------------------------------------------------------------- 1 | library(devtools) 2 | setwd("/Users/stevenshuken/Documents/Research/P-value correction project/SIMPLYCORRECT Supplementary Code/permFDP/") 3 | list.files() 4 | document() 5 | -------------------------------------------------------------------------------- /permFDP.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: permFDP 2 | Type: Package 3 | Title: Rejection Threshold Correction Using Permutation-Based FDP Estimation 4 | Version: 0.1.0 5 | Date: 2022-07-11 6 | Author: Steven R. Shuken 7 | Maintainer: Steven R. Shuken 8 | Description: One paragraph description of what the package does 9 | as one or more full sentences. 10 | License: GPL (>= 2) 11 | Imports: Rcpp (>= 1.0.9) 12 | LinkingTo: Rcpp, BH 13 | RoxygenNote: 7.2.1 14 | -------------------------------------------------------------------------------- /util/RcppPackageSkeleton.R: -------------------------------------------------------------------------------- 1 | # This is all the code needed to add boilerplate files to your RStudio project (not created as a package!) To make it into a package. 2 | # Note: This makes the package in a directory inside the RStudio project. You must then move the files up into the main directory of the project. 3 | library(Rcpp) 4 | setwd("/Users/stevenshuken/Documents/Research/P-value correction project/SIMPLYCORRECT Supplementary Code/permFDP/") 5 | Rcpp.package.skeleton("RcppPackage") 6 | -------------------------------------------------------------------------------- /R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | designTTest <- function(ints, design) { 5 | .Call(`_permFDP_designTTest`, ints, design) 6 | } 7 | 8 | permFDRAdjust <- function(expPs, threshold, design, intOnly, nPerms, nc, nt) { 9 | .Call(`_permFDP_permFDRAdjust`, expPs, threshold, design, intOnly, nPerms, nc, nt) 10 | } 11 | 12 | permFDRAdjustCpp <- function(expPs, threshold, design, intMatrix, nPerms, nc, nt) { 13 | .Call(`_permFDP_permFDRAdjustCpp`, expPs, threshold, design, intMatrix, nPerms, nc, nt) 14 | } 15 | 16 | -------------------------------------------------------------------------------- /man/RcppPackage-package.Rd: -------------------------------------------------------------------------------- 1 | \name{permFDP-package} 2 | \alias{permFDP-package} 3 | \alias{permFDP} 4 | \docType{package} 5 | \title{ 6 | Rejection threshold correction using permutation-based FDP estimation. 7 | } 8 | \description{ 9 | 10 | } 11 | \details{ 12 |
13 | } 14 | \author{ 15 | Steven R. Shuken 16 | 17 | Maintainer: Steven R. Shuken 18 | } 19 | \references{ 20 | Shuken and McNerney 2023 21 | } 22 | \keyword{ package } 23 | \seealso{ 24 | 25 | } 26 | \examples{ 27 | \dontrun{ 28 | ## Optional simple examples of the most important functions 29 | ## These can be in \dontrun{} and \donttest{} blocks. 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # permFDP 2 | An R package for correcting p-values for multiple hypothesis testing in comparative quantitative omics experiments using permutation-based FDP estimation. 3 | 4 | ## Installation 5 | 6 | Once you have the `devtools` package installed, you can install `permFDP` by using the `install_github()` command: 7 | 8 | ``` 9 | install_github('steven-shuken/permFDP') 10 | ``` 11 | 12 | Expect to see two warnings. 13 | 14 | ## Usage 15 | 16 | The only function currently intended for use is `permFDP.adjust.threshold()`. Use `?permFDP::permFDP.adjust.threshold()` for instructions. Briefly, you need: 17 | 1. A vector of p-values 18 | 2. The uncorrected rejection threshold 19 | 3. A data frame of quantities (for generating the permutated hit counts). Note: the row order does not have to match the p-value order, i.e., the first p-value does not have to correspond to the first analyte/row, etc. 20 | 4. A vector of 1s and 2s specifying which columns in the data frame are in which group 21 | 5. The number of permutations to perform (at least 100 is recommended). 22 | 23 | The function will return the corrected rejection threshold to control the FDR according to the rejection threshold you supplied. E.g., if you supply an uncorrected rejection threshold of 0.05, the estimated FDR will now be 5% using the new corrected rejection threshold. 24 | -------------------------------------------------------------------------------- /man/permFDP.adjust.threshold.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/permFDP.R 3 | \name{permFDP.adjust.threshold} 4 | \alias{permFDP.adjust.threshold} 5 | \title{Permutation-Based FDP Method for Rejection Threshold Correction} 6 | \usage{ 7 | permFDP.adjust.threshold(pVals, threshold, myDesign, intOnly, nPerms) 8 | } 9 | \arguments{ 10 | \item{pVals}{Vector of p-values. The length of this vector must be the same as the number of rows in the intOnly data frame} 11 | 12 | \item{threshold}{Original threshold that will be adjusted.} 13 | 14 | \item{myDesign}{Vector of 1s and 2s specifying which columns in intOnly belong to the control group (1) and which belong to the test group (2).} 15 | 16 | \item{intOnly}{A data frame. Each column is a sample, each row is an analyte.} 17 | 18 | \item{nPerms}{The number of permutations to perform. At least 100 is recommended.} 19 | } 20 | \description{ 21 | This function controls FDR using the permutation method described in our manuscript. Like the BH method above, it corrects the rejection threshold rather than the p-values themselves. 22 | It returns the new threshold for P-value rejection. 23 | It uses the Rcpp and BH packages to leverage fast C++ code. 24 | } 25 | \examples{ 26 | controlVals = matrix(rnorm(300), ncol = 3, nrow = 100) 27 | testVals = matrix(rnorm(300, mean = 3), ncol = 3, nrow = 100) 28 | intOnly = data.frame(cbind(controlVals, testVals)) 29 | myDesign = c(1,1,1,2,2,2) 30 | pVals = c() 31 | for (row in 1:nrow(intOnly)) { 32 | pVals = c(pVals, t.test(intOnly[row, 1:3], intOnly[row, 4:6])$p.value) 33 | } 34 | threshold = 0.05 35 | corrThreshold = permFDP::permFDP.adjust.threshold(pVals, threshold, myDesign, intOnly, 100) 36 | corrThreshold 37 | } 38 | \keyword{FDP} 39 | \keyword{FDR} 40 | \keyword{p-values} 41 | \keyword{permutation} 42 | -------------------------------------------------------------------------------- /R/permFDP.R: -------------------------------------------------------------------------------- 1 | library(Rcpp) 2 | library(BH) 3 | Sys.setenv("PKG_CXXFLAGS"="-std=c++17") 4 | sourceCpp("src/permFDP.cpp") 5 | 6 | #' Permutation-Based FDP Method for Rejection Threshold Correction 7 | #' 8 | #' This function controls FDR using the permutation method described in our manuscript. Like the BH method above, it corrects the rejection threshold rather than the p-values themselves. 9 | #' It returns the new threshold for P-value rejection. 10 | #' It uses the Rcpp and BH packages to leverage fast C++ code. 11 | #' @param pVals Vector of p-values. The length of this vector must be the same as the number of rows in the intOnly data frame 12 | #' @param threshold Original threshold that will be adjusted. 13 | #' @param myDesign Vector of 1s and 2s specifying which columns in intOnly belong to the control group (1) and which belong to the test group (2). 14 | #' @param intOnly A data frame. Each column is a sample, each row is an analyte. 15 | #' @param nPerms The number of permutations to perform. At least 100 is recommended. 16 | #' @keywords p-values FDP FDR permutation 17 | #' @export 18 | #' @examples 19 | #' controlVals = matrix(rnorm(300), ncol = 3, nrow = 100) 20 | #' testVals = matrix(rnorm(300, mean = 3), ncol = 3, nrow = 100) 21 | #' intOnly = data.frame(cbind(controlVals, testVals)) 22 | #' myDesign = c(1,1,1,2,2,2) 23 | #' pVals = c() 24 | #' for (row in 1:nrow(intOnly)) { 25 | #' pVals = c(pVals, t.test(intOnly[row, 1:3], intOnly[row, 4:6])$p.value) 26 | #' } 27 | #' threshold = 0.05 28 | #' corrThreshold = permFDP::permFDP.adjust.threshold(pVals, threshold, myDesign, intOnly, 100) 29 | #' corrThreshold 30 | 31 | permFDP.adjust.threshold = function(pVals, threshold, myDesign, intOnly, nPerms) { 32 | pVals = pVals[order(pVals)] 33 | intMatrix = as.matrix(intOnly) 34 | nc = length(which(myDesign == 1)) 35 | nt = length(which(myDesign == 2)) 36 | return(permFDRAdjustCpp(pVals, threshold, myDesign, intMatrix, nPerms, nc, nt)) 37 | } 38 | -------------------------------------------------------------------------------- /src/RcppExports.cpp: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #include 5 | 6 | using namespace Rcpp; 7 | 8 | #ifdef RCPP_USE_GLOBAL_ROSTREAM 9 | Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); 10 | Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); 11 | #endif 12 | 13 | // designTTest 14 | double designTTest(std::vector ints, std::vector design); 15 | RcppExport SEXP _permFDP_designTTest(SEXP intsSEXP, SEXP designSEXP) { 16 | BEGIN_RCPP 17 | Rcpp::RObject rcpp_result_gen; 18 | Rcpp::RNGScope rcpp_rngScope_gen; 19 | Rcpp::traits::input_parameter< std::vector >::type ints(intsSEXP); 20 | Rcpp::traits::input_parameter< std::vector >::type design(designSEXP); 21 | rcpp_result_gen = Rcpp::wrap(designTTest(ints, design)); 22 | return rcpp_result_gen; 23 | END_RCPP 24 | } 25 | // permFDRAdjust 26 | double permFDRAdjust(std::vector expPs, double threshold, std::vector design, std::vector> intOnly, int nPerms, int nc, int nt); 27 | RcppExport SEXP _permFDP_permFDRAdjust(SEXP expPsSEXP, SEXP thresholdSEXP, SEXP designSEXP, SEXP intOnlySEXP, SEXP nPermsSEXP, SEXP ncSEXP, SEXP ntSEXP) { 28 | BEGIN_RCPP 29 | Rcpp::RObject rcpp_result_gen; 30 | Rcpp::RNGScope rcpp_rngScope_gen; 31 | Rcpp::traits::input_parameter< std::vector >::type expPs(expPsSEXP); 32 | Rcpp::traits::input_parameter< double >::type threshold(thresholdSEXP); 33 | Rcpp::traits::input_parameter< std::vector >::type design(designSEXP); 34 | Rcpp::traits::input_parameter< std::vector> >::type intOnly(intOnlySEXP); 35 | Rcpp::traits::input_parameter< int >::type nPerms(nPermsSEXP); 36 | Rcpp::traits::input_parameter< int >::type nc(ncSEXP); 37 | Rcpp::traits::input_parameter< int >::type nt(ntSEXP); 38 | rcpp_result_gen = Rcpp::wrap(permFDRAdjust(expPs, threshold, design, intOnly, nPerms, nc, nt)); 39 | return rcpp_result_gen; 40 | END_RCPP 41 | } 42 | // permFDRAdjustCpp 43 | double permFDRAdjustCpp(Rcpp::NumericVector expPs, double threshold, Rcpp::NumericVector design, Rcpp::NumericMatrix intMatrix, int nPerms, int nc, int nt); 44 | RcppExport SEXP _permFDP_permFDRAdjustCpp(SEXP expPsSEXP, SEXP thresholdSEXP, SEXP designSEXP, SEXP intMatrixSEXP, SEXP nPermsSEXP, SEXP ncSEXP, SEXP ntSEXP) { 45 | BEGIN_RCPP 46 | Rcpp::RObject rcpp_result_gen; 47 | Rcpp::RNGScope rcpp_rngScope_gen; 48 | Rcpp::traits::input_parameter< Rcpp::NumericVector >::type expPs(expPsSEXP); 49 | Rcpp::traits::input_parameter< double >::type threshold(thresholdSEXP); 50 | Rcpp::traits::input_parameter< Rcpp::NumericVector >::type design(designSEXP); 51 | Rcpp::traits::input_parameter< Rcpp::NumericMatrix >::type intMatrix(intMatrixSEXP); 52 | Rcpp::traits::input_parameter< int >::type nPerms(nPermsSEXP); 53 | Rcpp::traits::input_parameter< int >::type nc(ncSEXP); 54 | Rcpp::traits::input_parameter< int >::type nt(ntSEXP); 55 | rcpp_result_gen = Rcpp::wrap(permFDRAdjustCpp(expPs, threshold, design, intMatrix, nPerms, nc, nt)); 56 | return rcpp_result_gen; 57 | END_RCPP 58 | } 59 | 60 | static const R_CallMethodDef CallEntries[] = { 61 | {"_permFDP_designTTest", (DL_FUNC) &_permFDP_designTTest, 2}, 62 | {"_permFDP_permFDRAdjust", (DL_FUNC) &_permFDP_permFDRAdjust, 7}, 63 | {"_permFDP_permFDRAdjustCpp", (DL_FUNC) &_permFDP_permFDRAdjustCpp, 7}, 64 | {NULL, NULL, 0} 65 | }; 66 | 67 | RcppExport void R_init_permFDP(DllInfo *dll) { 68 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 69 | R_useDynamicSymbols(dll, FALSE); 70 | } 71 | -------------------------------------------------------------------------------- /src/permFDP.cpp: -------------------------------------------------------------------------------- 1 | // [[Rcpp::depends(BH)]] 2 | // [[Rcpp::plugins(cpp17)]] 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | * Performs a T test on the measurements according to the design (1s and 2s) 9 | * and returns a P value. 10 | */ 11 | // [[Rcpp::export]] 12 | double designTTest(std::vector ints, std::vector design) { 13 | if (ints.size() != design.size()) Rcpp::stop("ERROR: DESIGN VECTOR AND MEASUREMENT VECTOR NOT EQUAL IN LENGTH!"); 14 | 15 | std::vector cIntensities, tIntensities; 16 | 17 | for (int i = 0; i < design.size(); i++) { 18 | if (design[i] == 1) { 19 | cIntensities.push_back(ints[i]); 20 | } else if (design[i] == 2) { 21 | tIntensities.push_back(ints[i]); 22 | } else { 23 | Rcpp::stop("DESIGN SYMBOL IS NOT 1 OR 2!"); 24 | } 25 | } 26 | 27 | auto [t, p] = boost::math::statistics::two_sample_t_test(cIntensities, tIntensities); 28 | return p; 29 | } 30 | 31 | /* 32 | * This function randomizes an experimental design while keeping the test and control samples as balanced as possible. 33 | */ 34 | std::vector randBalDesign(int nc, int nt) { 35 | 36 | // Calculate the maximally balanced number of control samples to put into the randomized control group 37 | int cIntoC = round(nc * nc / (nc + nt)); 38 | 39 | // Put control and test samples into each group accordingly 40 | int tIntoC = nc - cIntoC; 41 | int cIntoT = nc - cIntoC; 42 | int tIntoT = nt - cIntoT; 43 | 44 | std::vector controlGroup; 45 | std::vector testGroup; 46 | for (int cc = 0; cc < cIntoC; cc++) { 47 | controlGroup.push_back(1); 48 | } 49 | for (int ct = 0; ct < cIntoT; ct++) { 50 | testGroup.push_back(1); 51 | } 52 | for (int tc = 0; tc < tIntoC; tc++) { 53 | controlGroup.push_back(2); 54 | } 55 | for (int tt = 0; tt < tIntoT; tt++) { 56 | testGroup.push_back(2); 57 | } 58 | 59 | // obtain a time-based seed: 60 | unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); 61 | 62 | // Randomly shuffle each group 63 | std::shuffle(controlGroup.begin(), controlGroup.end(), std::default_random_engine(seed)); 64 | std::shuffle(testGroup.begin(), testGroup.end(), std::default_random_engine(seed)); 65 | 66 | // Return new design 67 | std::vector output; 68 | for (int i = 0; i < controlGroup.size(); i++) { 69 | output.push_back(controlGroup[i]); 70 | } 71 | for (int i = 0; i < testGroup.size(); i++) { 72 | output.push_back(testGroup[i]); 73 | } 74 | 75 | return output; 76 | } 77 | 78 | /* 79 | * Returns the number of p values that are below the threshold. 80 | * The p values passed in must be sorted in ascending order. 81 | */ 82 | int countHits(std::vector sortedPVals, double threshold) { 83 | for (int i=0; i < sortedPVals.size(); i++) { 84 | if (sortedPVals[i] > threshold) { 85 | return i; 86 | } 87 | } 88 | return sortedPVals.size(); 89 | } 90 | 91 | /* 92 | * Returns the index of the highest fdp that is at or below the threshold. 93 | */ 94 | int getHighestPositionBelowThresh(std::vector fdp, double threshold) { 95 | std::vector positions; 96 | for (int i=0; i < fdp.size(); i++) { 97 | if (fdp[i] <= threshold) { 98 | positions.push_back(i); 99 | } 100 | } 101 | 102 | if (positions.size() < 1) 103 | return -1; 104 | 105 | return *max_element(positions.begin(), positions.end()); 106 | } 107 | 108 | /* 109 | * This function controls the FDR using the permutation method described in our manuscript. 110 | * Like the BH method, it corrects the rejection threshold rather than the p-values themselves. 111 | * It returns the new threshold for p-value rejection. 112 | * intOnly is a vector of samples. Each sample is a vector of proteins. 113 | */ 114 | // [[Rcpp::export]] 115 | double permFDRAdjust(std::vector expPs, double threshold, std::vector design, 116 | std::vector> intOnly, int nPerms, int nc, int nt) { 117 | // Instantiate the lists of random p-values to estimate false hits 118 | std::vector firstSample = intOnly[0]; 119 | int nProts = firstSample.size(); 120 | std::vector> randPVals(nPerms); 121 | 122 | // Get experimentally observed p-values 123 | if (expPs.size() < 1) { 124 | for (int i_prot = 0; i_prot < nProts; i_prot++) { 125 | std::vector measurements; 126 | int nSamples = intOnly.size(); 127 | for (int i_sample = 0; i_sample < nSamples; i_sample++) { 128 | measurements.push_back(intOnly[i_sample][i_prot]); 129 | } 130 | expPs[i_prot] = designTTest(measurements, design); 131 | } 132 | } 133 | std::sort(expPs.begin(), expPs.end()); // sort ascending 134 | 135 | // For each permutation, perform t-tests and save the p-values 136 | for (int i_perm = 0; i_perm < nPerms; i_perm++) { 137 | 138 | // Get randomized balanced design 139 | std::vector balDesign = randBalDesign(nc, nt); 140 | 141 | // Instantiate vector of randomized T test P values 142 | std::vector pVals_i(intOnly[0].size()); 143 | 144 | // Pull out the protein intensities and do the t tests 145 | for (int i_prot = 0; i_prot < intOnly[0].size(); i_prot++) { 146 | std::vector cIntensities; 147 | std::vector tIntensities; 148 | 149 | for (int i_sample = 0; i_sample < balDesign.size(); i_sample++) { 150 | if (balDesign[i_sample] == 1) { 151 | cIntensities.push_back(intOnly[i_sample][i_prot]); 152 | } else if (balDesign[i_sample] == 2) { 153 | tIntensities.push_back(intOnly[i_sample][i_prot]); 154 | } else { 155 | Rcpp::stop("ERROR: DESIGN SYMBOL IS NOT 1 OR 2!"); 156 | } 157 | } 158 | 159 | auto [t, p] = boost::math::statistics::two_sample_t_test(cIntensities, tIntensities); 160 | 161 | pVals_i[i_prot] = p; 162 | } 163 | randPVals[i_perm] = pVals_i; 164 | 165 | // Sort the p values in this permutation in ascending order 166 | std::sort(randPVals[i_perm].begin(), randPVals[i_perm].end()); 167 | } 168 | 169 | // Make rank vector: 1 to m, and the estimated FDP vector. 170 | std::vector rank(expPs.size()); 171 | std::vector fdp(expPs.size()); 172 | for (int i = 0; i < expPs.size(); i++) { 173 | rank[i] = 1.0 + i; 174 | } 175 | 176 | // At every p value (rank), get the # hits for each permutation, then store the average. 177 | for (int i = 0; i< rank.size(); i++) { 178 | double thresh_i = expPs[i]; 179 | std::vector hitCounts(nPerms); 180 | 181 | // Calculate the average # hits at this threshold 182 | for (int i_perm = 0; i_perm < randPVals.size(); i_perm++) { 183 | hitCounts[i_perm] = countHits(randPVals[i_perm], thresh_i); 184 | } 185 | 186 | double sum = std::accumulate(hitCounts.begin(), hitCounts.end(), 0.0); 187 | double v = sum / hitCounts.size(); 188 | fdp[i] = v / rank[i]; 189 | } 190 | 191 | // Return the highest p value for which est FDP <= threshold 192 | int bestIndex = getHighestPositionBelowThresh(fdp, threshold); 193 | 194 | // index = -1: nothing is below the threshold. 195 | // return a new threshold below all the P values. 196 | if (bestIndex < 0) 197 | return expPs[0] / 2; 198 | 199 | // index is at the end: all p-values are below the threshold. 200 | // Return something just above the highest or halfway between the highest and 1. 201 | if (bestIndex == fdp.size() - 1) { 202 | double worstP = expPs[expPs.size() - 1]; 203 | if (worstP + 0.05 <= 1) 204 | return worstP + 0.05; 205 | 206 | return (worstP + 1) / 2; 207 | } 208 | 209 | // Otherwise: return a threshold between the p-value at the highest index and that at the next one. 210 | return (expPs[bestIndex] + expPs[bestIndex + 1]) / 2; 211 | } 212 | 213 | // [[Rcpp::export]] 214 | double permFDRAdjustCpp(Rcpp::NumericVector expPs, double threshold, Rcpp::NumericVector design, 215 | Rcpp::NumericMatrix intMatrix, int nPerms, int nc, int nt) { 216 | // Convert NumericMatrix to vector of vectors 217 | std::vector> intVecVec(intMatrix.ncol()); 218 | for (int i_col = 0; i_col < intVecVec.size(); i_col++) { 219 | std::vector column(intMatrix.nrow()); 220 | for (int i_row = 0; i_row < column.size(); i_row++) { 221 | column[i_row] = intMatrix(i_row, i_col); 222 | } 223 | intVecVec[i_col] = column; 224 | } 225 | 226 | // Convert everything else 227 | std::vector expPVec(expPs.begin(), expPs.end()); 228 | std::vector designVec(design.begin(), design.end()); 229 | 230 | return permFDRAdjust(expPVec, threshold, designVec, intVecVec, nPerms, nc, nt); 231 | } 232 | --------------------------------------------------------------------------------