library(TDbasedUFEadv)
library(Biobase)
#> Loading required package: BiocGenerics
#> Loading required package: generics
#>
#> Attaching package: 'generics'
#> The following objects are masked from 'package:base':
#>
#> as.difftime, as.factor, as.ordered, intersect, is.element, setdiff,
#> setequal, union
#>
#> Attaching package: 'BiocGenerics'
#> The following objects are masked from 'package:stats':
#>
#> IQR, mad, sd, var, xtabs
#> The following objects are masked from 'package:base':
#>
#> Filter, Find, Map, Position, Reduce, anyDuplicated, aperm, append,
#> as.data.frame, basename, cbind, colnames, dirname, do.call,
#> duplicated, eval, evalq, get, grep, grepl, is.unsorted, lapply,
#> mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
#> rank, rbind, rownames, sapply, saveRDS, table, tapply, unique,
#> unsplit, which.max, which.min
#> Welcome to Bioconductor
#>
#> Vignettes contain introductory material; view with
#> 'browseVignettes()'. To cite Bioconductor, see
#> 'citation("Biobase")', and for packages 'citation("pkgname")'.
library(RTCGA.rnaseq)
library(TDbasedUFE)
library(MOFAdata)
library(TDbasedUFE)
library(RTCGA.clinical)
Here is a flowchart how we can make use of individual functions in TDbasedUFE and TDbasedUFEadv.
In order to make use of TDbasedUFE for the drug repositioning, we previously proposed(Taguchi 2017a) the integrated analysis of two gene expression profiles, each of which is composed of gene expression of drug treated one and disease one. At first, we try to prepare two omics profiles, expDrug and expDisease, that represent gene expression profiles of cell lines treated by various drugs and a cell line of diseases by
Cancer_cell_lines <- list(ACC.rnaseq, BLCA.rnaseq, BRCA.rnaseq, CESC.rnaseq)
Drug_and_Disease <- prepareexpDrugandDisease(Cancer_cell_lines)
expDrug <- Drug_and_Disease$expDrug
expDisease <- Drug_and_Disease$expDisease
rm(Cancer_cell_lines)
expDrug is taken from RTCGA package and those associated with Drugs based upon (Ding, Zu, and Gu 2016). Those files are listed in drug_response.txt included in Clinical drug responses at http://lifeome.net/supp/drug_response/. expDisease is composed of files in BRCA.rnaseq, but not included in expDrug (For more details, see source code of prepareexpDrugandDisease). Then prepare a tensor as
Z <- prepareTensorfromMatrix(
exprs(expDrug[seq_len(200), seq_len(100)]),
exprs(expDisease[seq_len(200), seq_len(100)])
)
sample <- outer(
colnames(expDrug)[seq_len(100)],
colnames(expDisease)[seq_len(100)], function(x, y) {
paste(x, y)
}
)
Z <- PrepareSummarizedExperimentTensor(
sample = sample, feature = rownames(expDrug)[seq_len(200)], value = Z
)
In the above, sample are pairs of file IDs taken from expDrug and expDisease. Since full data cannot be treated because of memory restriction, we restricted the first two hundred features and the first one hundred samples, respectively (In the below, we will introduce how to deal with the full data sets).
Then HOSVD is applied to a tensor as
HOSVD <- computeHosvd(Z)
#> | | | 0% | |======================= | 33% | |=============================================== | 67% | |======================================================================| 100%
Here we tries to find if Cisplatin causes distinct expression (0: cell lines treated with drugs other than Cisplatin, 1: cell lines treated with Cisplatin) and those between two classes (1 vs 2) of BRCA (in this case, there are no meaning of two classes) within top one hundred samples.
Cond <- prepareCondDrugandDisease(expDrug)
cond <- list(NULL, Cond[, colnames = "Cisplatin"][seq_len(100)], rep(1:2, each = 50))
Then try to select singular value vectors attributed to objects. When you try this vignettes, although you can do it in the interactive mode (see below), here we assume that you have already finished the selection.
In the case you prefer to select by yourself you can execute interactive mode.
input_all <- selectSingularValueVectorLarge(HOSVD,cond)
When you can see Next'',
Prev’‘, and ``Select’’ radio
buttons by which you can performs selection as well as histogram and
standard deviation optimization by which you can verify the success of
selection interactively.
Next we select which genes’ expression is altered by Cisplatin.
You might need to specify suitable value for de which is initial value of standard deviation.
Then we get the following plot.
Finally, list the genes selected as those associated with distinct expression.
head(tableFeatures(Z,index))
#> Feature p value adjusted p value
#> 4 ACADVL.37 2.233863e-24 4.467726e-22
#> 6 ACLY.47 1.448854e-19 1.448854e-17
#> 1 A2M.2 6.101507e-16 4.067671e-14
#> 3 ABHD2.11057 3.934360e-10 1.967180e-08
#> 2 AARS.16 1.449491e-06 5.797964e-05
#> 5 ACIN1.22985 6.510593e-06 2.170198e-04
rm(Z)
rm(HOSVD)
detach("package:RTCGA.rnaseq")
rm(SVD)
#> Warning in rm(SVD): object 'SVD' not found
The described methods were frequently used in the studies(Taguchi 2017b) (Taguchi 2018) (Taguchi and Turki 2020) by maintainers.
In the case that there are large number of features, it is impossible to apply HOSVD to a full tensor (Then we have reduced the size of tensor). In this case, we apply SVD instead of HOSVD to matrix generated from a tensor as follows. In contrast to the above where only top two hundred features and top one hundred samples are included, the following one includes all features and all samples since it can save required memory because partial summation of features.
SVD <- computeSVD(exprs(expDrug), exprs(expDisease))
Z <- t(exprs(expDrug)) %*% exprs(expDisease)
sample <- outer(
colnames(expDrug), colnames(expDisease),
function(x, y) {
paste(x, y)
}
)
Z <- PrepareSummarizedExperimentTensor(
sample = sample,
feature = rownames(expDrug), value = Z
)
Nest select singular value vectors attributed to drugs and cell lines then identify features associated with altered expression by treatment of Cisplatin as well as distinction between two classes. Again, it included all samples for expDrug and expDisease.
Next we select singular value vectors and optimize standard deviation as batch mode
Again you need to select suitable de by trials and errors.
For interactive mode, one should do
index_all <- selectFeatureRect(SVD,cond,de=c(0.01,0.01))
but it is not possible in vignettes that does not allow interactive mode.
Then you can see selected features as
head(tableFeatures(Z,index_all[[1]]))
#> Feature p value adjusted p value
#> 15 ACTB.60 0 0
#> 22 ADAM6.8755 0 0
#> 42 AHNAK.79026 0 0
#> 150 AZGP1.563 0 0
#> 152 B2M.567 0 0
#> 219 C4A.720 0 0
head(tableFeatures(Z,index_all[[2]]))
#> Feature p value adjusted p value
#> 7 ABHD2.11057 0 0
#> 14 ACTB.60 0 0
#> 18 ADAM6.8755 0 0
#> 36 AHNAK.79026 0 0
#> 95 AZGP1.563 0 0
#> 135 C4A.720 0 0
The upper one is for distinct expression between cell lines treated with Cisplatin and other cell lines and the lower one is for distinct expression between two classes of BRCA cell lines.
Although they are highly coincident, not fully same ones (Row: expDrug, column:expDisease).
table(index_all[[1]]$index,index_all[[2]]$index)
#>
#> FALSE TRUE
#> FALSE 18455 185
#> TRUE 949 942
Confusion matrix of features selected between expDrug and expDisease.
The described methods were frequently used in the studies(Taguchi and Turki 2019) by maintainers.
The above procedure can be used when two omics data that shares samples must be integrated. Prepare data set as
(see vignettes QuickStart in TDbasedUFE for more details about this data set). Generate tensor from matrix as in the above, but since not features but samples are shared between two matrices, the resulting Z has samples as features and features as samples, respectively.
Z <- prepareTensorfromMatrix(
t(CLL_data$Drugs[seq_len(200), seq_len(50)]),
t(CLL_data$Methylation[seq_len(200), seq_len(50)])
)
Z <- prepareTensorRect(
sample = colnames(CLL_data$Drugs)[seq_len(50)],
feature = list(
Drugs = rownames(CLL_data$Drugs)[seq_len(200)],
Methylatiion = rownames(CLL_data$Methylation)[seq_len(200)]
),
sampleData = list(CLL_covariates$Gender[seq_len(50)]),
value = Z
)
HOSVD was applied to Z as
HOSVD <- computeHosvd(Z)
#> | | | 0% | |======================= | 33% | |=============================================== | 67% | |======================================================================| 100%
Condition is distinction between male and female (see QucikStart in TDbasedUFE package). Then try to find singular value vectors distinct between male and female in interactive mode.
In the above, selection was supposed to be performed before executing the above, since vignettes does not allow interactive mode. In actual, you need to execute it in interactive mode
index_all <- selectFeatureTransRect(HOSVD,cond,de=c(0.01,0.01))
and try to select iteratively. Selected features can be shown in the below.
head(tableFeaturesSquare(Z,index_all,1))
#> Feature p value adjusted p value
#> 6 D_041_1 8.625818e-12 1.725164e-09
#> 1 D_001_1 2.648615e-07 2.648615e-05
#> 5 D_020_1 6.373260e-07 4.248840e-05
#> 2 D_001_2 3.526011e-06 1.763006e-04
#> 3 D_007_1 7.228555e-06 2.891422e-04
#> 4 D_007_2 5.526041e-05 1.842014e-03
head(tableFeaturesSquare(Z,index_all,2))
#> [1] Feature p value adjusted p value
#> <0 rows> (or 0-length row.names)
This method was used in the studies(Taguchi 2019) by the maintainer.
As in the case where two omics profiles share features, in the case where two omics data share the samples, we can also take an alternative approach where SVD is applied to an matrix generated from a tensor by taking partial summation.
SVD <- computeSVD(t(CLL_data$Drugs), t(CLL_data$Methylation))
Z <- CLL_data$Drugs %*% t(CLL_data$Methylation)
sample <- colnames(CLL_data$Methylation)
Z <- prepareTensorRect(
sample = sample,
feature = list(rownames(CLL_data$Drugs), rownames(CLL_data$Methylation)),
value = array(NA, dim(Z)), sampleData = list(CLL_covariates[, 1])
)
Condition is also distinction between male (m) and female (f).
In order to apply the previous function to SVD, we exchange feature singular value vectors with sample singular value vectors.
Then try to find which sample singular value vectors should be selected and which features are selected based upon feature singular value vectors corresponding to selected sample feature vectors. Although I do not intend to repeat whole process, we decided to select the sixth singular value vectors which are some what distinct between male and female. Since package does not allow us interactive mode, we place here batch mode.
In the real usage, we can activate selectFeatureRect in interactive mode as well.
index_all <- selectFeatureRect(SVD,cond,de=c(0.5,0.5))
Then we can list the Drugs and Methylation sites selected as being distinct between male and female.
head(tableFeaturesSquare(Z,index_all,1))
#> Feature p value adjusted p value
#> 1 D_004_4 1.210706e-11 3.753189e-09
#> 5 D_040_4 1.759860e-08 2.727782e-06
#> 4 D_040_3 1.473704e-05 1.522828e-03
#> 3 D_021_2 6.873730e-05 5.072336e-03
#> 2 D_007_3 8.181187e-05 5.072336e-03
head(tableFeaturesSquare(Z,index_all,2))
#> [1] Feature p value adjusted p value
#> <0 rows> (or 0-length row.names)
This method was used in many studies(Taguchi and Ng 2018) (Ng and Y 2020) by maintainer.
Here is a flowchart how we can make use of individual functions in TDbasedUFE and TDbasedUFEadv.
As an alternative approach that can integrate multiple omics that share sample, we propose the method that makes use of projection provided by SVD.
We prepare a tensor that is a bundle of the first ten singular value vectors generated by applying SVD to individual omics profiles.
data("CLL_data")
data("CLL_covariates")
Z <- prepareTensorfromList(CLL_data, 10L)
Z <- PrepareSummarizedExperimentTensor(
feature = character("1"),
sample = array(colnames(CLL_data$Drugs), 1), value = Z,
sampleData = list(CLL_covariates[, 1])
)
Then HOSVD was applied to a tensor
HOSVD <- computeHosvd(Z,scale=FALSE)
#> | | | 0% | |======================= | 33% | |=============================================== | 67% | |======================================================================| 100%
Next we select singular value vectors attributed to samples. In order to select those distinct between male (m) and female (f), we set conditions as
But here in order to include TDbasedUFEadv into package, we are forced to execute function as batch mode as
Interactive more can be activated as
input_all <- selectSingularValueVectorLarge(HOSVD,cond)
Although we do not intend to repeat how to use menu in interactive mode, please select the 12th one and the third one.
Finally, we perform the following function to select features in individual omics profiles in an batch mode, since packaging does not allow interactive mode.
HOSVD$U[[1]] <- HOSVD$U[[2]]
index_all <- selectFeatureSquare(HOSVD, input_all, CLL_data,
de = c(0.5, 0.1, 0.1, 1), interact = FALSE
) # Batch mode
In actual usage, you can activate interactive mode as
HOSVD$U[[1]] <- HOSVD$U[[2]]
index_all <- selectFeatureSquare(HOSVD, input_all, CLL_data,
de = c(0.5, 0.1, 0.1, 1)
)
Finally, we list the selected features for four omics profiles that share samples.
for (id in c(1:4))
{
attr(Z, "feature") <- rownames(CLL_data[[id]])
print(tableFeatures(Z, index_all[[id]]))
}
#> [1] Feature p value adjusted p value
#> <0 rows> (or 0-length row.names)
#> [1] Feature p value adjusted p value
#> <0 rows> (or 0-length row.names)
#> Feature p value adjusted p value
#> 5 ENSG00000173110 3.368388e-10 1.684194e-06
#> 2 ENSG00000214787 1.017605e-09 2.544013e-06
#> 12 ENSG00000204389 5.527594e-08 9.212657e-05
#> 16 ENSG00000070808 1.274235e-07 1.592794e-04
#> 14 ENSG00000168878 1.821868e-07 1.821868e-04
#> 17 ENSG00000183876 3.708588e-07 3.090490e-04
#> 15 ENSG00000204388 9.345517e-07 6.675370e-04
#> 1 ENSG00000186522 2.802006e-06 1.751254e-03
#> 7 ENSG00000053918 6.473465e-06 3.596369e-03
#> 3 ENSG00000152953 8.284655e-06 4.142327e-03
#> 4 ENSG00000136237 1.164833e-05 5.294694e-03
#> 11 ENSG00000071246 1.453660e-05 6.056918e-03
#> 10 ENSG00000185920 2.170178e-05 7.771502e-03
#> 18 ENSG00000078900 2.176021e-05 7.771502e-03
#> 13 ENSG00000189325 2.833035e-05 9.443449e-03
#> 9 ENSG00000165259 3.070426e-05 9.595083e-03
#> 6 ENSG00000140443 3.499777e-05 9.772303e-03
#> 8 ENSG00000170160 3.518029e-05 9.772303e-03
#> Feature p value adjusted p value
#> 1 del17p13 0.0001409456 0.009725248
This method was used in many studies(Taguchi and Turki 2022) by maintainer.
Now we discuss what to do when multiple omics data share not samples but features. We prepare data set from RTCGA.rnaseq as follows, with retrieving reduced partial sets from four ones. One should notice that RTCGA is an old package from TCGA (as for 2015). I used it only for demonstration purpose. If you would like to use TCGA for your research, I recommend you to use more modern packages, e.g., curatedTCGAData in Bioconductor.
library(RTCGA.rnaseq) #it must be here, not in the first chunk
Multi <- list(
BLCA.rnaseq[seq_len(100), 1 + seq_len(1000)],
BRCA.rnaseq[seq_len(100), 1 + seq_len(1000)],
CESC.rnaseq[seq_len(100), 1 + seq_len(1000)],
COAD.rnaseq[seq_len(100), 1 + seq_len(1000)]
)
Multi includes four objects, each of which is matrix that represent 100 samples (rows) and 1000 (features). Please note it is different from usual cases where columns and rows are features and samples, respectively. They are marge into tensor as follows
The function, prepareTeansorfromList which was used in the previous subsection where samples are shared, can be used as it is. However, the first and second modes of a tensor must be exchanged by aperm function for the latter analyses, because of the difference as mentioned in the above. Then tensor object associated with various information is generated as usual as follows and HOSVD was applied to it.
Clinical <- list(BLCA.clinical, BRCA.clinical, CESC.clinical, COAD.clinical)
Multi_sample <- list(
BLCA.rnaseq[seq_len(100), 1, drop = FALSE],
BRCA.rnaseq[seq_len(100), 1, drop = FALSE],
CESC.rnaseq[seq_len(100), 1, drop = FALSE],
COAD.rnaseq[seq_len(100), 1, drop = FALSE]
)
# patient.stage_event.tnm_categories.pathologic_categories.pathologic_m
ID_column_of_Multi_sample <- c(770, 1482, 773, 791)
# patient.bcr_patient_barcode
ID_column_of_Clinical <- c(20, 20, 12, 14)
Z <- PrepareSummarizedExperimentTensor(
feature = colnames(ACC.rnaseq)[1 + seq_len(1000)],
sample = array("", 1), value = Z,
sampleData = prepareCondTCGA(
Multi_sample, Clinical,
ID_column_of_Multi_sample, ID_column_of_Clinical
)
)
HOSVD <- computeHosvd(Z)
#> | | | 0% | |======================= | 33% | |=============================================== | 67% | |======================================================================| 100%
In order to see which singular value vectors attributed to samples are used for the selection of singular value vectors attributed to features, we need to assign sample conditions.
Since package does not allow us to include interactive mode, we place here batch mode as follows. Finally, selected feature are listed as follows.
head(tableFeatures(Z,index))
#> Feature p value adjusted p value
#> 10 ACTB|60 0.000000e+00 0.000000e+00
#> 11 ACTG1|71 0.000000e+00 0.000000e+00
#> 37 ALDOA|226 0.000000e+00 0.000000e+00
#> 19 ADAM6|8755 5.698305e-299 1.424576e-296
#> 22 AEBP1|165 1.057392e-218 2.114785e-216
#> 9 ACTA2|59 7.862975e-198 1.310496e-195
In actual, you can activate interactive mode as
par(mai=c(0.3,0.2,0.2,0.2))
index <- selectFeatureProj(HOSVD,Multi,cond,de=1e-3)
Although we do not intend to explain how to use menu interactively, we select the third singular value vectors as shown in above.
This method was used in many studies(Taguchi and Turki 2021) by maintainer.
sessionInfo()
#> R version 4.4.2 (2024-10-31)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.1 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=C
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] RTCGA.rnaseq_20151101.36.0 MOFAdata_1.22.0
#> [3] Biobase_2.67.0 BiocGenerics_0.53.3
#> [5] generics_0.1.3 STRINGdb_2.19.0
#> [7] enrichR_3.2 RTCGA.clinical_20151101.36.0
#> [9] RTCGA_1.37.0 enrichplot_1.27.1
#> [11] DOSE_4.1.0 TDbasedUFEadv_1.7.0
#> [13] TDbasedUFE_1.7.0 BiocStyle_2.35.0
#>
#> loaded via a namespace (and not attached):
#> [1] rTensor_1.4.8 splines_4.4.2 later_1.3.2
#> [4] bitops_1.0-9 ggplotify_0.1.2 tibble_3.2.1
#> [7] R.oo_1.27.0 XML_3.99-0.17 lifecycle_1.0.4
#> [10] rstatix_0.7.2 lattice_0.22-6 backports_1.5.0
#> [13] magrittr_2.0.3 sass_0.4.9 rmarkdown_2.29
#> [16] jquerylib_0.1.4 yaml_2.3.10 plotrix_3.8-4
#> [19] httpuv_1.6.15 ggtangle_0.0.4 cowplot_1.1.3
#> [22] DBI_1.2.3 buildtools_1.0.0 RColorBrewer_1.1-3
#> [25] abind_1.4-8 zlibbioc_1.52.0 rvest_1.0.4
#> [28] GenomicRanges_1.59.1 purrr_1.0.2 R.utils_2.12.3
#> [31] RCurl_1.98-1.16 hash_2.2.6.3 yulab.utils_0.1.8
#> [34] WriteXLS_6.7.0 GenomeInfoDbData_1.2.13 IRanges_2.41.1
#> [37] KMsurv_0.1-5 S4Vectors_0.45.2 ggrepel_0.9.6
#> [40] tidytree_0.4.6 maketools_1.3.1 proto_1.0.0
#> [43] codetools_0.2-20 xml2_1.3.6 tximportData_1.34.0
#> [46] tidyselect_1.2.1 aplot_0.2.3 UCSC.utils_1.3.0
#> [49] farver_2.1.2 viridis_0.6.5 stats4_4.4.2
#> [52] jsonlite_1.8.9 Formula_1.2-5 survival_3.7-0
#> [55] tools_4.4.2 chron_2.3-61 treeio_1.31.0
#> [58] Rcpp_1.0.13-1 glue_1.8.0 gridExtra_2.3
#> [61] xfun_0.49 qvalue_2.39.0 ggthemes_5.1.0
#> [64] GenomeInfoDb_1.43.1 dplyr_1.1.4 withr_3.0.2
#> [67] BiocManager_1.30.25 fastmap_1.2.0 fansi_1.0.6
#> [70] caTools_1.18.3 digest_0.6.37 R6_2.5.1
#> [73] mime_0.12 gridGraphics_0.5-1 colorspace_2.1-1
#> [76] GO.db_3.20.0 gtools_3.9.5 RSQLite_2.3.8
#> [79] R.methodsS3_1.8.2 utf8_1.2.4 tidyr_1.3.1
#> [82] data.table_1.16.2 httr_1.4.7 sqldf_0.4-11
#> [85] pkgconfig_2.0.3 gtable_0.3.6 blob_1.2.4
#> [88] XVector_0.47.0 sys_3.4.3 survMisc_0.5.6
#> [91] htmltools_0.5.8.1 carData_3.0-5 fgsea_1.33.0
#> [94] scales_1.3.0 png_0.1-8 ggfun_0.1.7
#> [97] knitr_1.49 km.ci_0.5-6 tzdb_0.4.0
#> [100] reshape2_1.4.4 rjson_0.2.23 nlme_3.1-166
#> [103] curl_6.0.1 cachem_1.1.0 zoo_1.8-12
#> [106] stringr_1.5.1 KernSmooth_2.23-24 parallel_4.4.2
#> [109] AnnotationDbi_1.69.0 pillar_1.9.0 grid_4.4.2
#> [112] vctrs_0.6.5 gplots_3.2.0 promises_1.3.0
#> [115] ggpubr_0.6.0 car_3.1-3 xtable_1.8-4
#> [118] tximport_1.35.0 evaluate_1.0.1 readr_2.1.5
#> [121] gsubfn_0.7 cli_3.6.3 compiler_4.4.2
#> [124] rlang_1.1.4 crayon_1.5.3 ggsignif_0.6.4
#> [127] labeling_0.4.3 survminer_0.5.0 plyr_1.8.9
#> [130] fs_1.6.5 stringi_1.8.4 viridisLite_0.4.2
#> [133] BiocParallel_1.41.0 assertthat_0.2.1 munsell_0.5.1
#> [136] Biostrings_2.75.1 lazyeval_0.2.2 GOSemSim_2.33.0
#> [139] Matrix_1.7-1 hms_1.1.3 patchwork_1.3.0
#> [142] bit64_4.5.2 ggplot2_3.5.1 KEGGREST_1.47.0
#> [145] shiny_1.9.1 igraph_2.1.1 broom_1.0.7
#> [148] memoise_2.0.1 bslib_0.8.0 ggtree_3.15.0
#> [151] fastmatch_1.1-4 bit_4.5.0 ape_5.8