% \VignetteIndexEntry{gCMAP classes and methods} % \VignetteDepends{} % \VignetteKeywords{gCMAP} % \VignettePackage{gCMAP} \documentclass[10pt]{article} \usepackage{times} \usepackage{hyperref} \usepackage{Sweave} \textwidth=6.5in \textheight=8.5in \oddsidemargin=-.1in \evensidemargin=-.1in \headheight=-.3in \newcommand{\Robject}[1]{{\texttt{#1}}} \newcommand{\Rpackage}[1]{{\textsf{#1}}} \newcommand{\Rclass}[1]{{\textit{#1}}} \newcommand{\Rfunarg}[1]{{\texttt{#1}}} \title{Gene set analyses with the gCMAP package} \author{Thomas Sandmann and Richard Bourgon} \date{\today} \begin{document} \maketitle This document exemplifies the structure and use of the classes and (some of) the methods offered by the \Rpackage{gCMAP} package. For information on performing queries via an R-only, custom web application and to access a tutorial with examples using real biological datasets available from public databases, please refer to the documentation of the \Rpackage{gCMAPWeb} companion package. \tableofcontents \newpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Introduction} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% <>= options(warn=-1) @ The \tt gCMAP \rm package offers unified access to a number of different algorithms to compare a sets of genes across expression profiling experiments. It extends the functionality of the \tt GSEABase \rm package, which provides functions to generate and combine GeneSets from various sources. \section{CMAPCollection, SignedGeneSet and CMAPResults classes} Them \tt gCMAP\rm package introduces three new classes: \itemize{ \item{SignedGeneSet: }{ Extends the \tt GeneSet \rm class, with an additional \tt geneSign \rm slot to distinguish up- and downregulated set members.} \item{CMAPCollection: }{ Is derived from the \tt eSet \rm class for efficient storage of large numbers of gene sets and related annotations.} \item{CMAPResults: }{ Provides a unified output class for different gene set enrichment analysis methods.} } \subsection{CMAPCollections} To evaluate large gene sets collections containing thousands of gene sets, the \tt gCMAP \rm package introduces a new class \tt CMAPCollections \rm, to store gene sets and their relationships with each other in the form of a (sparse) incidence matrix. A derivative of the \tt eSet \rm class, a \tt CMAPCollection \rm also stores gene and gene set annotations in its featureData and phenoData slots. CMAPCollections can be created de novo, e.g. with the \tt newCMAPCollection \rm function, or by coercing existing \tt GeneSet, SignedGeneSet \rm or \tt GeneSetCollection \rm objects. Often, large data matrices e.g. containing differential expression data from many different experiments, are available. The \tt induceCMAPCollection \rm function can be used to define gene sets from any \tt eSet \rm object by applying a user-defined threshold. The \tt gCMAPData NChannelSet \rm object stores the results of three perturbation experiments, stimulation of tissue culture cells with drug1, drug2 or drug3. For each experiment, log2 fold change, z-scores and p-values (from differential expression analysis with the \tt limma \rm package) are available. <>= library(gCMAP) data( gCMAPData ) ## example NChannelSet sampleNames( gCMAPData ) channelNames( gCMAPData ) @ To induce gene sets of interest, a data slot and thresholds must be chosen. <>= ## select all genes with z-scores > 2 or < -2 cmap <- induceCMAPCollection( gCMAPData, element="z", lower=-2, higher=2) cmap pData( cmap ) @ The sign of the differential expression (e.g. the sign of the z-score or log2 fold change) is stored in the sparseMatrix stored as \tt assayData \rm in the \tt CMAPCollection \rm. Up-regulated gene set members are indicated by +1, down-regulated members by -1. <>= head( members( cmap ) ) @ Sometimes, e.g. when selecting gene sets based on p-values, no sign information is available and all set members will simply be indicated with +1. To distinguish sets without sign information from those only containing up-regulated members, the \tt signed \rm column of the phenoData slot indicates how the information should be interpreted. <>= signed( cmap ) @ As for other eSet-like objects, CMAPCollections can be subset to extract specific genes or gene sets. <>= dim( cmap ) cmap[,1] ## the first gene set @ \section{Comparing GeneSets} To compare the list of geneIds present in different \tt CMAPCollections \rm, \tt GeneSets \rm or \tt GeneSetCollections \rm, the Fisher test can be used. In addition to the \tt GeneSets \rm of interest, we also need to provide information about the gene 'universe', the complete ensemble of genes that could potentially be included in any set, e.g. all genes for which probes are available on a microarray, etc. Here, we will use all identifiers present in the gCMAPData dataset to define the gene identifier universe. The following example compares the first gene set in our \tt CMAPCollecttion \rm to all three included sets. (In this vignette, we will refer to 'query' and 'target' objects. Every query object is compared individually to all targets and the results are returned in a single object.) <>= universe <- featureNames( gCMAPData ) results <- fisher_score(cmap[,1], cmap, universe) results @ The fisher\_score method returns a \tt CMAPResults \rm object, used by all analysis methods supported by the \tt gCMAP \rm package. \subsection{CMAPResults} Each CMAPResults object contains three elements \itemize{ \item{An \tt AnnotatedDataFrame \rm called 'table', storing the results of comparing one query to all of the targets. Additional columns can be used to store information about the target gene sets. The supported gene set enrichment analysis methods return various scores, effect sizes and p-values, documented in the \tt varMetadata \rm slot of the 'table'. They can be accessed with the \tt labels \rm method.} \item{A 'docs' \tt character \rm vector to record information about the analysis run as a whole.} \item{A \tt list \rm 'errors', where potential warnings and error messages can be stored.} } To \tt cmapTable \rm method returns the full result table, including annotation columns (if present) and labels. Individual accessors have been to return the p-value columns (\tt pval \rm or \tt padj \rm), effect size (\tt effect \rm) or to transform the adjusted p-values to z-scores on a standard normal scale (\tt zscores \rm). <>= cmapTable( results ) labels( results ) pval( results ) zscores( results ) @ Several gene set enrichment analyses support many-to-many comparisons, including fisher\_score. In this case, we receive a list of multiple \tt CMAPResults \rm objects, one for each element of the query. Each CMAPResults object contains the results for all query gene sets ordered by p-value. To extract individual slots from all CMAPResult objects in the list, e.g. with \tt sapply \rm, we must ensure that all results are returned in the same order, e.g. ordered by sampleNames. <>= result.list <- fisher_score( cmap, cmap, universe ) class( result.list ) length( result.list ) class( result.list[[1]] ) ## all pairwise adjusted p-values sapply(result.list, function( x ) { padj( x )[ sampleNames( cmap )] }) @ \section{Differential expression analysis with gene sets} Frequently, we are interested in differential expression of gene sets across two or more conditions. The \tt gCMAP \rm package currently provides unified access to the sample-label permutation strategy implemented in the \tt GSEAlm \rm package, as well as multiple functions from the \tt limma \rm package: \tt camera \rm, \tt romer \rm and \tt mroast \rm. (For a detailed explanation oft the different methods, please consult the help entries of the original packages directly.) For all methods, pre-processed expression data can be supplied as a data matrix, an \tt ExpressionSet \rm or any other \tt eSet \rm derivative. To perform a differential expression analysis, the experimental design must be specified, either by providing a design matrix directly or, for \tt eSet \rm or \tt ExpressionSet \rm objects, as a character string matching a phenoData column name. Let's generate an \tt matrix \rm with random expression values, three treated and three control samples: <>= ## random score matrix y <- matrix(rnorm(1000*6),1000,6, dimnames=list( featureNames( gCMAPData ), 1:6 )) predictor <- c( rep("Control", 3), rep("Case", 3)) @ along with a \tt CMAPCollection \rm containg four unsigned gene sets, the first of which is actually differentially up-regulated in the 'Case' group. <>= m <-replicate(4, { s <- rep(0,1000) s[ sample(1:1000, 20)] <- 1 s[ sample(1:1000, 20)] <- -1 s }) dimnames(m) <- list(row.names( y ), paste("set", 1:4, sep="")) ## Set1 is up-regulated y[,c(4:6)] <- y[,c(4:6)] + m[,1]*2 ## create CMAPCollection cmap <- CMAPCollection(m, signed=rep(TRUE,4)) @ The gCMAP package offers four different algorithms to test for differential expression between the 'control' and 'treatment' samples: <>= gsealm_score(y, cmap, predictor=predictor, nPerm=100) @ <>= mroast_score(y, cmap, predictor=predictor) @ Both gsealm\_score and mroast perform self-contained test. (Goeman and Buhlmann, 2007). (Please note that we only run 100 \tt gsealm\_score \rm permutations to obtain a p-value in this example - in a real analysis, increasing this number, e.g. to 1000, is recommended.) In case a competitive hypothesis needs to be tested, the camera\_score and romer\_score methods (calling the \tt romer \rm and \tt camera \rm functions from the limma package, respectively) can be used instead. <>= camera_score(y, cmap, predictor=predictor) romer_score(y, cmap, predictor=predictor) @ Currently, only gsealm\_score takes the sign of the gene set members (indicating whether a gene had originally be identified as up- or down-regulated) into account. \section{Analysis of individual score profiles} In addition to analyzing complete experiments, other approaches to gene set enrichment testing evaluate whether a given statistic for the members of a gene set ranked highly relative to random sets. The wilcox\_score method calculates the Wilcox-rank sum statistic, assessing whether the ranked scores of a gene set are enriched at the top or bottom of the complete list of scores. The gsealm\_jg\_score calculates the mean score for all gene set members and provides a p-value based on the standard normal distribution (Jiang and Gentleman, 2007). The connectivity\_score is calculated according to Lamb, J. et al. (2006) and corresponds to the scaled score described in this publication. (It does not provide a p-value.) For illustration, we compare the first column of z-scores stored in the gCMAPData \tt NChannelSet \rm to the three gene sets induced from the same dataset in the first section of this vignette.. <>= profile <- assayDataElement(gCMAPData[,1], "z") ## extract first column head(profile) sampleNames(cmap) ## three gene sets gsealm_jg_score(profile, cmap) @ As expected the first gene set, which was derived from the same experiment as the profile, receives highly significant p-values. Alternatively, the Wilcox Rank sum test or the original Connectivity Score can be calculated. (Please note that the \tt connectivity\_score \rm does not return a p-value and is hard to interpret for a single profile.) <>= wilcox_score(profile, cmap) connectivity_score(profile, cmap) @ \section{Overview plots} When comparing a set of genes, a profile or a complete experiment to a large gene set collection, e.g. induced from the original Connectivity map data generated at the Broad institute (Lamb et al, Science, 2006), high level diagnostic plots can provide a first overview of the results. For illustration purposes, we generate a random profile of z-scores for 1000 genes as well as CMAPCollection with a random set of 1000 gene sets. One of them, set1, is actually differentially regulated. <>= ## create random score profile set.seed(123) z <- rnorm(1000) names(z) <- paste("g", 1:1000, sep="") ## generate random incidence matrix of gene sets n <-replicate(1000, { s <- rep(0,1000) s[ sample(1:1000, 20)] <- 1 s[ sample(1:1000, 20)] <- -1 s }) dimnames(n) <- list(names(z), paste("set", 1:1000, sep="")) ## Set1 is up-regulated z <- z + n[,1]*2 ## create CMAPCollection cmap.2 <- CMAPCollection(n, signed=rep(TRUE,1000)) @ <>= ## gene-set enrichment test res <- gsealm_jg_score(z, cmap.2) class(res) res @ \setkeys{Gin}{width=.85\linewidth} <>= plot(res) @ A call to the \tt plot \rm method on a \tt CMAPResults \rm object yields two graphical overviews: on the left, a density of all 1000 reported effect sizes, in this case JG-scores, is shown. In the absence of correlation between genes, this distribution follows a normal distribution. ( While this is true for this set of randomly generated scores, the distribution of JG scores observed in practice is actually broader than expected, testament to the non-random patterns of gene expression.) On the right, a heatmap of the rank-ordered scores is displayed, with low and high scores displayed as blue and red stripes, respectively. By default, scores between -3 and 3 are hidden. To display scores above 3 or below -3, a color gradient from white to red or from white to blue is applied, respectively. (Both the choice of colors and thresholds of the color gradients can be configured, please see the \tt CMAPResults \rm help page for details.) \setkeys{Gin}{width=.85\linewidth} <>= sets.down <- effect( res ) < -3 plot(res) @ \section{Retrieving gene-level information} Once significantly enriched gene sets have been identified, we may want to take a closer look at the behavior of individual genes. Are expression changes associated with many gene set members or do specific genes respond particularly strongly ? All methods implemented in the \tt gCMAP \rm package, with the exception of \tt fisher\_score \rm, return gene-level scores when the optional 'keep.scores' parameter is set to 'TRUE'. To demonstrate, we repeat the \tt gsealm\_score \rm call from above. <>= res <- gsealm_score(y, cmap, predictor=predictor, nPerm=100, keep.scores=TRUE) res set1.expr <- geneScores(res)[["set1"]] head(set1.expr) @ Expression scores for each gene set are now available in the geneScores \tt cmapResults \rm colum, which can be accessed through a method with the same name. Each matrix of expression scores is accompanied by an additional 'sign' attribute to remind us whether gene set members were annotated as up- or down-regulated. For example, we can now visualize the expression scores of set1 member genes in a heatmap. As expected, genes annotated as 'up-regulated' (red sidebar) show higher expression in Cases than Controls and the reverse is true for genes annotated as 'down-regulated' (blue sidebar). \setkeys{Gin}{width=.65\linewidth} <>= heatmap(set1.expr, scale="none", Colv=NA, labCol=predictor, RowSideColors=ifelse( attr(set1.expr, "sign") == "up", "red", "blue"), margin=c(7,5)) legend(0.35,0,legend=c("up", "down"), fill=c("red", "blue"), title="Annotated sign", horiz=TRUE, xpd=TRUE) @ Each row in the \tt CMAPResults \rm objects features an subset of the original query ExpressionSet. As genes can be part of many different genes sets, querying large gene set collections may result in storing duplicate data rows over and over again, considerably increasing the memory footprint of the \tt CMAPResults \rm object. Alternatively, we can extract the scores from the original data source. For example, we can obtain a nested list of scores for all sets and data columns by passing the \tt CMAPCollection \rm (cmap) and the score matrix (y) to the \tt featureScores \rm method. The element for 'set1' corresponds to the score matrix we obtained above. <>= res <- featureScores(cmap, y) class(res) names(res) identical( res[["set1"]], set1.expr ) @ <>= sessionInfo() @ \end{document}