-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathREADME.rmd
More file actions
188 lines (134 loc) · 4.87 KB
/
Copy pathREADME.rmd
File metadata and controls
188 lines (134 loc) · 4.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
---
title: "morgancpp: Efficient structure for storing and comparing Morgan fingerprints"
date: "4/27/2020"
output: github_document
---
```{r setup, include=FALSE}
library(knitr)
knitr::opts_chunk$set(echo = TRUE)
```
## Installation
The package can be installed directly from GitHub:
```{r, echo = TRUE, eval = FALSE}
if(!require(devtools)) install.packages("devtools")
devtools::install_github("labsyspharm/morgancpp")
```
Once installed, the package can be loaded through the standard `library()` interface:
```{r}
library(morgancpp)
```
## Example data
The package works with Morgan fingerprints specified as hexadecimal strings of length 512.
An example set of 100,000 fingerprints is included with the package. It can be loaded as follows:
```{r}
fn <- system.file("examples/example1.txt.gz", package = "morgancpp")
fps <- scan(fn, what = character())
```
```{r, echo = FALSE}
paste0(substr(fps, start = 0, stop = 80), "...")[1:3]
```
## Computing similarity of fingerprints
The tanimoto similarity can be computed directly on hexadecimal strings:
```{r, error = TRUE}
tanimoto(fps[1], fps[1])
tanimoto(fps[1], fps[2])
tanimoto(fps[1], "FFF")
```
## The `MorganFPS` data structure
However, doing this for a large number of fingerprints will be slow. Instead, we can initialize the c++ data structure to store fingerprints in an efficient manner and query that structure for similarity.
### From RDkit "full" hex-encoded fingerprints
These fingerprint representations can be generated in RDkit by converting the
output of `ToBitString()` to hexadecimal encoding. The example data above
is encoded that way.
```{python, echo = TRUE, eval = FALSE}
AllChem.GetMorganFingerprintAsBitVect(inchi).ToBitString()
```
These fingerprints can be imported to morgancpp by passing the fingerprint
character vector directly to `MorganFPS$new()`.
```{r}
m <- MorganFPS$new(fps)
object.size(fps)
m$size()
```
### From RDkit run-length encoded (RLE) fingerprints
Run-length encoding (RLE) is an alternative, more space efficient way of
representing fingerprints.
```{python, echo = TRUE, eval = FALSE}
AllChem.GetMorganFingerprintAsBitVect(inchi).ToBitString()
```
These fingerprints can be imported to morgancpp by wrapping the fingerprint
character vector in `fingerprints()` specifying their encoding and passing them
to `MorganFPS$new()`.
```{r}
m2 <- MorganFPS$new(
fingerprints(
c(
"e0ffffff000400001a00000026582eb62a09002c2a620c18309638069c0644327826440c324e3e98",
"e0ffffff0004000037000000043c221a0c0e0c044a140ede321e3e2c06000e104c14362c040c206a3a76022a06401c1800540402021e002a0a00183e1640101a462e1208",
"e0ffffff000400003200000002042c04182a1c125a0006ae8e2a00140618060622620e365c92307e0a023c021478041e02320e0c04282046000e10124c3208"
),
format = "rle"
)
)
```
## Computing similarities
Similarity between fingerprints in the structure can be computed by indexing:
```{r}
m$tanimoto(1, 1)
m$tanimoto(1, 2)
```
The entire similarity profile against all other fingerprints in the collection can be obtained for compounds already in the collection (specified as index `i`) or new external compounds (specified as hexadecimal strings):
```{r}
res1 <- m$tanimoto_all( 1 ) # Compound 1 against all 100,000 fingerprints
```
```{r, echo = FALSE, results = "asis"}
kable(head(res1), label = "res1")
```
```{r}
res2 <- m$tanimoto_ext( fps[1] ) # External compound against all 100,000 fingerprints
```
```{r, echo = FALSE, results = "asis"}
kable(head(res2), label = "res2")
```
## Tresholded searches
Often the similarities between all NxN pairs of fingerprints above a certain
threshold are of interest. `tanimoto_threshold()` computes these similarities
and outputs them as a data frame.
```{r}
res3 <- m$tanimoto_threshold(0.9)
```
```{r, echo = FALSE, results = "asis"}
kable(head(res3), label = "res3")
```
## Saving fingerprints
Fingerprints can be stored on disk in a binary format supporting extremely fast writing
and reading performance using [Zstandard](https://github.com/facebook/zstd)
compression.
```{r, echo = TRUE}
tmp_file <- tempfile()
m$save_file(tmp_file)
m2 <- MorganFPS$new(tmp_file, from_file = TRUE)
m2$size()
```
## The `MorganMap` data structure
In addition to finding similarities between fingerprints there is a specialized
data structure for finding identical fingerprints as fast as possible.
```{r}
map <- MorganMap$new(fps)
res4 <- map$find_matches(sample(fps, 10))
```
```{r, echo = FALSE, results = "asis"}
kable(head(res4), label = "res4")
```
## Additional documentation
Obtaining additional information about functionality of the package can be done through the standard R interface:
```{r, echo = TRUE, eval = FALSE}
# All available functions
library( help = morgancpp )
# Help for individual functions / data structures
?morgancpp::tanimoto
?morgancpp::MorganFPS
?morgancpp::MorganMap
# C++ docstrings providing full signatures of each method
morgancpp::MorganFPS
```