--- title: "SparseArray objects" author: - name: Hervé Pagès affiliation: Fred Hutchinson Cancer Research Center, Seattle, WA date: "Compiled `r doc_date()`; Modified 24 July 2023" package: SparseArray vignette: | %\VignetteIndexEntry{SparseArray objects} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} output: BiocStyle::html_document --- # Introduction `r Biocpkg("SparseArray")` is an infrastructure package that provides an array-like container for efficient in-memory representation of multidimensional sparse data in R. The package defines the SparseArray virtual class and two concrete subclasses: COO\_SparseArray and SVT\_SparseArray. Each subclass uses its own internal representation of the nonzero multidimensional data, the "COO layout" and the "SVT layout", respectively. Note that the SparseArray virtual class could easily be extended by other S4 classes that intent to implement alternative internal representations of the nonzero multidimensional data. This vignette focuses on the SVT\_SparseArray container. # Install and load the package ```{r, eval=FALSE} if (!requireNamespace("BiocManager", quietly=TRUE)) install.packages("BiocManager") BiocManager::install("SparseArray") ``` ```{r, message=FALSE} library(SparseArray) ``` # SVT\_SparseArray objects The SVT\_SparseArray container provides an efficient representation of the nonzero multidimensional data via a novel layout called the "SVT layout". Note that SVT\_SparseArray objects mimic as much as possible the behavior of ordinary matrix and array objects in base R. In particular, they suppport most of the "standard matrix and array API" defined in base R and in the `r Biocpkg("matrixStats")` package from CRAN. ## Construction SVT\_SparseArray objects can be constructed in many ways. A common way is to coerce an ordinary matrix or array to SVT\_SparseArray: ```{r} m <- matrix(0L, nrow=6, ncol=4) m[c(1:2, 8, 10, 15:17, 24)] <- (1:8)*10L svt1 <- as(m, "SVT_SparseArray") svt1 a <- array(0L, 5:3) a[c(1:2, 8, 10, 15:17, 20, 24, 40, 56:60)] <- (1:15)*10L svt2 <- as(a, "SVT_SparseArray") svt2 ``` Alternatively, the ordinary matrix or array can be passed to the `SVT_SparseArray` constructor function: ```{r} svt1 <- SVT_SparseArray(m) svt2 <- SVT_SparseArray(a) ``` Note that coercing an ordinary matrix or array to SparseArray is also supported and will produce the same results: ```{r} svt1 <- as(m, "SparseArray") svt2 <- as(a, "SparseArray") ``` This is because, for most use cases, the SVT\_SparseArray representation is more efficient than the COO\_SparseArray representation, so the former is usually preferred over the latter. For the same reason, the `SparseArray` constructor function will also give the preference to the SVT\_SparseArray representation: ```{r} svt1 <- SparseArray(m) svt2 <- SparseArray(a) ``` This is actually the most convenient way to turn an ordinary matrix or array into an SVT\_SparseArray object. Coercion back to ordinary matrix or array is supported: ```{r} as.array(svt1) # same as as.matrix(svt1) as.array(svt2) ``` ## Accessors The standard array accessors are supported: ```{r} dim(svt2) length(svt2) dimnames(svt2) <- list(NULL, letters[1:4], LETTERS[1:3]) svt2 ``` Some additional accessors defined in the `r Biocpkg("S4Arrays")` / `r Biocpkg("SparseArray")` framework: ```{r} type(svt1) type(svt1) <- "double" svt1 is_sparse(svt1) ``` Other accessors/extractors specific to sparse arrays: ```{r} ## Get the number of nonzero array elements in 'svt1': nzcount(svt1) ## Extract the "linear indices" of the nonzero array elements in 'svt1': nzwhich(svt1) ## Extract the "array indices" (a.k.a. "array coordinates") of the ## nonzero array elements in 'svt1': nzwhich(svt1, arr.ind=TRUE) ## Extract the values of the nonzero array elements in 'svt1' and return ## them in a vector "parallel" to 'nzwhich(svt1)': #nzvals(svt1) # NOT READY YET! sparsity(svt1) ``` See `?SparseArray` for more information and additional examples. ## Subsetting and subassignment ```{r} svt2[5:3, , "C"] ``` Like with ordinary arrays in base R, assigning values of type `"double"` to an SVT\_SparseArray object of type `"integer"` will automatically change the type of the object to `"double"`: ```{r} type(svt2) svt2[5, 1, 3] <- NaN type(svt2) ``` See `?SparseArray_subsetting` for more information and additional examples. ## Summarization methods (whole array) The following summarization methods are provided at the moment: `anyNA()`, `any`, `all`, `min`, `max`, `range`, `sum`, `prod`, `mean`, `var`, `sd`. ```{r} anyNA(svt2) range(svt2, na.rm=TRUE) mean(svt2, na.rm=TRUE) var(svt2, na.rm=TRUE) ``` See `?SparseArray_summarization` for more information and additional examples. ## Operations from the 'Ops', 'Math', 'Math2', and 'Complex' groups SVT\_SparseArray objects support operations from the 'Ops', 'Math', `Math2`, and 'Complex' groups, with some restrictions. See `?S4groupGeneric` in the `r Biocpkg("methods")` package for more information about these group generics. ```{r} signif((svt1^1.5 + svt1) %% 100 - 0.6 * svt1, digits=2) ``` See `?SparseArray_Ops`, `?SparseArray_Math`, and `?SparseArray_Complex`, for more information and additional examples. ## Other operations on SVT\_SparseArray objects More operations will be added in the future e.g. `is.na()`, `is.infinite()`, `is.nan()`, etc... ## Generate a random SVT\_SparseArray object Two convenience functions are provided for this: ```{r} randomSparseArray(c(5, 6, 2), density=0.5) poissonSparseArray(c(5, 6, 2), density=0.5) ``` See `?randomSparseArray` for more information and additional examples. # SVT\_SparseMatrix objects ## Transposition ```{r} t(svt1) ``` Note that multidimensional transposition is supported via `aperm()`: ```{r} aperm(svt2) ``` See `?SparseArray_aperm` for more information and additional examples. ## Combine multidimensional objects along a given dimension Like ordinary matrices in base R, SVT\_SparseMatrix objects can be combined by rows or columns, with `rbind()` or `cbind()`: ```{r} svt3 <- poissonSparseMatrix(6, 2, density=0.5) cbind(svt1, svt3) ``` Note that multidimensional objects can be combined along any dimension with `abind()`: ```{r} svt4a <- poissonSparseArray(c(5, 6, 2), density=0.4) svt4b <- poissonSparseArray(c(5, 6, 5), density=0.2) svt4c <- poissonSparseArray(c(5, 6, 4), density=0.2) abind(svt4a, svt4b, svt4c) svt5a <- aperm(svt4a, c(1, 3:2)) svt5b <- aperm(svt4b, c(1, 3:2)) svt5c <- aperm(svt4c, c(1, 3:2)) abind(svt5a, svt5b, svt5c, along=2) ``` See `?SparseArray_abind` for more information and additional examples. ## Matrix multiplication and cross-product Like ordinary matrices in base R, SVT\_SparseMatrix objects can be multiplied with the `%*%` operator: ```{r} m6 <- matrix(0L, nrow=5, ncol=6, dimnames=list(letters[1:5], LETTERS[1:6])) m6[c(2, 6, 12:17, 22:30)] <- 101:117 svt6 <- SparseArray(m6) svt6 %*% svt3 ``` They also support `crossprod()` and `tcrossprod()`: ```{r} crossprod(svt3) ``` See `?SparseMatrix_mult` for more information and additional examples. ## matrixStats methods The `r Biocpkg("SparseArray")` package provides memory-efficient col/row summarization methods for SVT\_SparseMatrix objects: ```{r} colVars(svt6) ``` Note that multidimensional objects are supported: ```{r} colVars(svt2) colVars(svt2, dims=2) colAnyNAs(svt2) colAnyNAs(svt2, dims=2) ``` See `?matrixStats_methods` for more information and additional examples. ## `rowsum()` method A `rowsum()` method is provided: ```{r} rowsum(svt6, group=c(1:3, 2:1)) ``` See `?rowsum_methods` for more information and additional examples. ## Read/write a sparse matrix from/to a CSV file Use `writeSparseCSV()` to write a sparse matrix to a CSV file: ```{r} csv_file <- tempfile() writeSparseCSV(m6, csv_file) ``` Use `readSparseCSV()` to read the file. This will import the data as an SVT\_SparseMatrix object: ```{r} readSparseCSV(csv_file) ``` See `?readSparseCSV` for more information and additional examples. # Comparison with dgCMatrix objects The nonzero data of a SVT\_SparseArray object is stored in a _Sparse Vector Tree_. This internal data representation is referred to as the "SVT layout". It is similar to the "CSC layout" (compressed, sparse, column-oriented format) used by CsparseMatrix derivatives from the `r CRANpkg("Matrix")` package, like dgCMatrix or lgCMatrix objects, but with the following improvements: - The "SVT layout" supports sparse arrays of arbitrary dimensions. - With the "SVT layout", the sparse data can be of any type. Whereas CsparseMatrix derivatives only support sparse data of type `"double"` or `"logical"` at the moment. - The "SVT layout" imposes no limit on the number of nonzero array elements that can be stored. With dgCMatrix/lgCMatrix objects, this number must be < 2^31. - Overall, the "SVT layout" allows more efficient operations on SVT\_SparseArray objects. See `?SVT_SparseArray` for more information. # Learn more Please consult the individual man pages in the `r Biocpkg("SparseArray")` package to learn more about SVT\_SparseArray objects and about the package. A good starting point is the man page for SparseArray objects: `?SparseArray` # Session information ```{r} sessionInfo() ```