qsarmil 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qsarmil-0.1.0/PKG-INFO +13 -0
- qsarmil-0.1.0/pyproject.toml +25 -0
- qsarmil-0.1.0/qsarmil/__init__.py +0 -0
- qsarmil-0.1.0/qsarmil/conformer/__init__.py +1 -0
- qsarmil-0.1.0/qsarmil/conformer/base.py +112 -0
- qsarmil-0.1.0/qsarmil/conformer/rdkit.py +17 -0
- qsarmil-0.1.0/qsarmil/data/__init__.py +0 -0
- qsarmil-0.1.0/qsarmil/data/fragment.py +115 -0
- qsarmil-0.1.0/qsarmil/descriptor/__init__.py +1 -0
- qsarmil-0.1.0/qsarmil/descriptor/rdkit.py +76 -0
- qsarmil-0.1.0/qsarmil/descriptor/wrapper.py +34 -0
- qsarmil-0.1.0/qsarmil/fragment/__init__.py +0 -0
- qsarmil-0.1.0/qsarmil/fragment/base.py +0 -0
- qsarmil-0.1.0/qsarmil/fragment/rdkit.py +0 -0
- qsarmil-0.1.0/qsarmil/utils/__init__.py +0 -0
- qsarmil-0.1.0/qsarmil/utils/logging.py +33 -0
- qsarmil-0.1.0/qsarmil.egg-info/PKG-INFO +13 -0
- qsarmil-0.1.0/qsarmil.egg-info/SOURCES.txt +20 -0
- qsarmil-0.1.0/qsarmil.egg-info/dependency_links.txt +1 -0
- qsarmil-0.1.0/qsarmil.egg-info/requires.txt +6 -0
- qsarmil-0.1.0/qsarmil.egg-info/top_level.txt +5 -0
- qsarmil-0.1.0/setup.cfg +4 -0
qsarmil-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qsarmil
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Molecular multi-instance machine learning
|
|
5
|
+
Author-email: Dmitry Zankov <dvzankov@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Description-Content-Type: text/x-rst
|
|
8
|
+
Requires-Dist: mikit-learn
|
|
9
|
+
Requires-Dist: rdkit
|
|
10
|
+
Requires-Dist: molfeat
|
|
11
|
+
Requires-Dist: py3Dmol
|
|
12
|
+
Requires-Dist: tqdm
|
|
13
|
+
Requires-Dist: huggingface_hub
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "qsarmil"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Molecular multi-instance machine learning"
|
|
9
|
+
readme = "README.rst"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Dmitry Zankov", email = "dvzankov@gmail.com" }
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
dependencies = [
|
|
16
|
+
"mikit-learn",
|
|
17
|
+
"rdkit",
|
|
18
|
+
"molfeat",
|
|
19
|
+
"py3Dmol",
|
|
20
|
+
"tqdm",
|
|
21
|
+
"huggingface_hub"
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[tool.setuptools.packages.find]
|
|
25
|
+
where = ["."]
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .rdkit import RDKitConformerGenerator
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import joblib
|
|
2
|
+
from tqdm import tqdm
|
|
3
|
+
from rdkit.Chem import AllChem, rdMolAlign
|
|
4
|
+
from rdkit import RDLogger
|
|
5
|
+
from joblib import Parallel, delayed
|
|
6
|
+
from qsarmil.utils.logging import FailedMolecule, FailedConformer
|
|
7
|
+
RDLogger.DisableLog('rdApp.*')
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ConformerGenerator:
|
|
11
|
+
def __init__(self, num_conf=10, e_thresh=None, rmsd_thresh=None, num_cpu=1, verbose=True):
|
|
12
|
+
super().__init__()
|
|
13
|
+
|
|
14
|
+
self.num_conf = num_conf
|
|
15
|
+
self.e_thresh = e_thresh
|
|
16
|
+
self.rmsd_thresh = rmsd_thresh
|
|
17
|
+
self.num_cpu = num_cpu
|
|
18
|
+
self.verbose = verbose
|
|
19
|
+
|
|
20
|
+
def _prepare_molecule(self, mol):
|
|
21
|
+
return NotImplemented
|
|
22
|
+
|
|
23
|
+
def _embedd_conformers(self, mol):
|
|
24
|
+
mol = self._prepare_molecule(mol)
|
|
25
|
+
params = AllChem.ETKDGv3()
|
|
26
|
+
params.numThreads = 0
|
|
27
|
+
params.maxAttempts = 1000
|
|
28
|
+
params.pruneRmsThresh = 0.1
|
|
29
|
+
AllChem.EmbedMultipleConfs(mol, numConfs=self.num_conf, params=params)
|
|
30
|
+
return mol
|
|
31
|
+
|
|
32
|
+
def _optimize_conformers(self, mol):
|
|
33
|
+
for conf in mol.GetConformers():
|
|
34
|
+
AllChem.UFFOptimizeMolecule(mol, confId=conf.GetId())
|
|
35
|
+
return mol
|
|
36
|
+
|
|
37
|
+
def _generate_conformers(self, mol):
|
|
38
|
+
if isinstance(mol, (FailedMolecule, FailedConformer)):
|
|
39
|
+
return mol
|
|
40
|
+
try:
|
|
41
|
+
mol = self._embedd_conformers(mol)
|
|
42
|
+
if not mol.GetNumConformers():
|
|
43
|
+
return FailedConformer(mol)
|
|
44
|
+
mol = self._optimize_conformers(mol)
|
|
45
|
+
except Exception:
|
|
46
|
+
return FailedConformer(mol)
|
|
47
|
+
|
|
48
|
+
if self.e_thresh is not None:
|
|
49
|
+
mol = filter_by_energy(mol, self.e_thresh)
|
|
50
|
+
|
|
51
|
+
if self.rmsd_thresh is not None:
|
|
52
|
+
mol = filter_by_rmsd(mol, self.rmsd_thresh)
|
|
53
|
+
|
|
54
|
+
return mol
|
|
55
|
+
|
|
56
|
+
def run(self, list_of_mols):
|
|
57
|
+
with tqdm(total=len(list_of_mols), desc="Generating conformers", disable=not self.verbose) as progress_bar:
|
|
58
|
+
# Define a custom callback to update the tqdm bar
|
|
59
|
+
class TqdmCallback(joblib.parallel.BatchCompletionCallBack):
|
|
60
|
+
def __call__(self, *args, **kwargs):
|
|
61
|
+
progress_bar.update(self.batch_size)
|
|
62
|
+
return super().__call__(*args, **kwargs)
|
|
63
|
+
|
|
64
|
+
# Patch joblib to use our callback
|
|
65
|
+
old_callback = joblib.parallel.BatchCompletionCallBack
|
|
66
|
+
joblib.parallel.BatchCompletionCallBack = TqdmCallback
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
results = Parallel(n_jobs=self.num_cpu)(
|
|
70
|
+
delayed(self._generate_conformers)(mol) for mol in list_of_mols
|
|
71
|
+
)
|
|
72
|
+
finally:
|
|
73
|
+
joblib.parallel.BatchCompletionCallBack = old_callback # Restore
|
|
74
|
+
|
|
75
|
+
return results
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def filter_by_energy(mol, e_thresh=1):
|
|
79
|
+
conf_energy_list = []
|
|
80
|
+
for conf in mol.GetConformers():
|
|
81
|
+
ff = AllChem.UFFGetMoleculeForceField(mol, confId=conf.GetId())
|
|
82
|
+
if ff is None:
|
|
83
|
+
continue
|
|
84
|
+
conf_energy_list.append((conf.GetId(), ff.CalcEnergy()))
|
|
85
|
+
conf_energy_list = sorted(conf_energy_list, key=lambda x: x[1])
|
|
86
|
+
|
|
87
|
+
min_energy = conf_energy_list[0][1]
|
|
88
|
+
for conf_id, conf_energy in conf_energy_list[1:]:
|
|
89
|
+
if conf_energy - min_energy >= e_thresh:
|
|
90
|
+
mol.RemoveConformer(conf_id)
|
|
91
|
+
|
|
92
|
+
return mol
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def filter_by_rmsd(mol, rmsd_thresh=2):
|
|
96
|
+
conf_ids = [conf.GetId() for conf in mol.GetConformers()]
|
|
97
|
+
to_remove = set()
|
|
98
|
+
|
|
99
|
+
for i, conf_id_i in enumerate(conf_ids):
|
|
100
|
+
if conf_id_i in to_remove:
|
|
101
|
+
continue
|
|
102
|
+
for conf_id_j in conf_ids[i + 1:]:
|
|
103
|
+
if conf_id_j in to_remove:
|
|
104
|
+
continue
|
|
105
|
+
rmsd = rdMolAlign.GetConformerRMS(mol, conf_id_i, conf_id_j, prealigned=False)
|
|
106
|
+
if rmsd < rmsd_thresh:
|
|
107
|
+
to_remove.add(conf_id_j)
|
|
108
|
+
|
|
109
|
+
for conf_id in to_remove:
|
|
110
|
+
mol.RemoveConformer(conf_id)
|
|
111
|
+
|
|
112
|
+
return mol
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from rdkit import Chem
|
|
2
|
+
from rdkit.Chem import AllChem
|
|
3
|
+
from qsarmil.conformer.base import ConformerGenerator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RDKitConformerGenerator(ConformerGenerator):
|
|
7
|
+
def __init__(self, num_conf=10, e_thresh=None, num_cpu=1, verbose=True):
|
|
8
|
+
super().__init__(num_conf=num_conf, e_thresh=e_thresh, num_cpu=num_cpu, verbose=verbose)
|
|
9
|
+
|
|
10
|
+
def _prepare_molecule(self, mol):
|
|
11
|
+
mol = Chem.AddHs(mol)
|
|
12
|
+
return mol
|
|
13
|
+
|
|
14
|
+
def _embedd_conformers(self, mol):
|
|
15
|
+
mol = self._prepare_molecule(mol)
|
|
16
|
+
AllChem.EmbedMultipleConfs(mol, numConfs=self.num_conf, maxAttempts=700, randomSeed=42)
|
|
17
|
+
return mol
|
|
File without changes
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
from rdkit import Chem
|
|
2
|
+
from rdkit.Chem import Descriptors, rdMolDescriptors, BRICS
|
|
3
|
+
import numpy as np
|
|
4
|
+
from typing import List, Tuple
|
|
5
|
+
from rdkit import Chem
|
|
6
|
+
from rdkit.Chem import Draw
|
|
7
|
+
import numpy as np
|
|
8
|
+
import matplotlib.pyplot as plt
|
|
9
|
+
|
|
10
|
+
# Supported RDKit molecular property functions
|
|
11
|
+
PROPERTY_FUNCTIONS = {
|
|
12
|
+
"LogP": Descriptors.MolLogP,
|
|
13
|
+
"MolWt": Descriptors.MolWt,
|
|
14
|
+
"TPSA": rdMolDescriptors.CalcTPSA,
|
|
15
|
+
"NumHDonors": Descriptors.NumHDonors,
|
|
16
|
+
"NumHAcceptors": Descriptors.NumHAcceptors,
|
|
17
|
+
"MolMR": Descriptors.MolMR,
|
|
18
|
+
"NumRotatableBonds": Descriptors.NumRotatableBonds,
|
|
19
|
+
"RingCount": Descriptors.RingCount,
|
|
20
|
+
"FractionCSP3": Descriptors.FractionCSP3,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def create_fragment_bags(
|
|
24
|
+
mols: List[Chem.Mol],
|
|
25
|
+
bag_size: int = 5,
|
|
26
|
+
property_name: str = "LogP",
|
|
27
|
+
random_state: int = 42
|
|
28
|
+
) -> Tuple[List[List[Chem.Mol]], List[float], List[List[float]]]:
|
|
29
|
+
"""
|
|
30
|
+
Create bags of BRICS fragments and compute bag-level label as the sum of a chosen molecular property.
|
|
31
|
+
|
|
32
|
+
Parameters:
|
|
33
|
+
- mols: list of RDKit Mol objects
|
|
34
|
+
- fragments_per_bag: number of fragments to sample per molecule
|
|
35
|
+
- property_name: RDKit property to calculate per fragment (e.g., "LogP", "MolWt")
|
|
36
|
+
- random_state: for reproducible fragment sampling
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
- bags: list of bags (each a list of fragment Mol objects)
|
|
40
|
+
- labels: list of total property per bag
|
|
41
|
+
- fragment_props: list of property values per fragment per bag
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
if property_name not in PROPERTY_FUNCTIONS:
|
|
45
|
+
raise ValueError(f"Unsupported property: {property_name}")
|
|
46
|
+
|
|
47
|
+
get_property = PROPERTY_FUNCTIONS[property_name]
|
|
48
|
+
rng = np.random.RandomState(random_state)
|
|
49
|
+
|
|
50
|
+
bags = []
|
|
51
|
+
labels = []
|
|
52
|
+
fragment_props = []
|
|
53
|
+
|
|
54
|
+
for mol in mols:
|
|
55
|
+
if mol is None:
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
# Generate BRICS fragments
|
|
59
|
+
frag_smiles_set = BRICS.BRICSDecompose(mol)
|
|
60
|
+
frags = [Chem.MolFromSmiles(smi) for smi in frag_smiles_set if smi]
|
|
61
|
+
frags = [f for f in frags if f is not None]
|
|
62
|
+
|
|
63
|
+
if len(frags) < bag_size:
|
|
64
|
+
continue # skip molecules with too few fragments
|
|
65
|
+
|
|
66
|
+
# Randomly sample fragments
|
|
67
|
+
sampled_frags = rng.choice(frags, size=bag_size, replace=False).tolist()
|
|
68
|
+
|
|
69
|
+
# Compute property per fragment
|
|
70
|
+
props = [get_property(f) for f in sampled_frags]
|
|
71
|
+
total = float(np.sum(props))
|
|
72
|
+
|
|
73
|
+
bags.append(sampled_frags)
|
|
74
|
+
labels.append(total)
|
|
75
|
+
fragment_props.append(props)
|
|
76
|
+
|
|
77
|
+
return bags, labels, fragment_props
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def display_fragments_with_weights(fragments, props, pred_weights, sort=True, max_fragments=16, title=None):
|
|
81
|
+
|
|
82
|
+
props = np.array(props)
|
|
83
|
+
pred_weights = np.array(pred_weights)
|
|
84
|
+
|
|
85
|
+
if sort:
|
|
86
|
+
sorted_idx = np.argsort(props)[::-1]
|
|
87
|
+
fragments = [fragments[i] for i in sorted_idx]
|
|
88
|
+
props = props[sorted_idx]
|
|
89
|
+
pred_weights = pred_weights[sorted_idx]
|
|
90
|
+
|
|
91
|
+
fragments = fragments[:max_fragments]
|
|
92
|
+
props = props[:max_fragments]
|
|
93
|
+
pred_weights = pred_weights[:max_fragments]
|
|
94
|
+
|
|
95
|
+
cols = 4
|
|
96
|
+
rows = (len(fragments) + cols - 1) // cols
|
|
97
|
+
|
|
98
|
+
fig, axes = plt.subplots(rows, cols, figsize=(cols * 3, rows * 3))
|
|
99
|
+
axes = axes.flatten()
|
|
100
|
+
|
|
101
|
+
for ax in axes[len(fragments):]:
|
|
102
|
+
ax.axis('off')
|
|
103
|
+
|
|
104
|
+
for i, (frag, prop, weight) in enumerate(zip(fragments, props, pred_weights)):
|
|
105
|
+
ax = axes[i]
|
|
106
|
+
img = Draw.MolToImage(frag, size=(150, 150))
|
|
107
|
+
ax.imshow(img)
|
|
108
|
+
ax.set_title(f"True prop: {prop:.3f}\nWeight: {weight:.2f}", fontsize=10)
|
|
109
|
+
ax.axis('off')
|
|
110
|
+
|
|
111
|
+
if title:
|
|
112
|
+
fig.suptitle(title, fontsize=16)
|
|
113
|
+
|
|
114
|
+
plt.tight_layout(rect=[0, 0, 1, 0.95]) # leave space for suptitle
|
|
115
|
+
plt.show()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .rdkit import RDKitGEOM, RDKitAUTOCORR, RDKitRDF, RDKitMORSE, RDKitWHIM, RDKitGETAWAY
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from rdkit.Chem import Descriptors3D
|
|
3
|
+
|
|
4
|
+
def validate_desc_vector(x):
|
|
5
|
+
|
|
6
|
+
# nan values
|
|
7
|
+
if np.isnan(x).sum() > 0:
|
|
8
|
+
imp = np.mean(x[~np.isnan(x)])
|
|
9
|
+
x = np.where(np.isnan(x), imp, x) # TODO temporary solution, should be revised
|
|
10
|
+
# extreme dsc values
|
|
11
|
+
if (abs(x) >= 10 ** 25).sum() > 0:
|
|
12
|
+
imp = np.mean(x[abs(x) <= 10 ** 25])
|
|
13
|
+
x = np.where(abs(x) <= 10 ** 25, x, imp)
|
|
14
|
+
return x
|
|
15
|
+
|
|
16
|
+
class RDKitDescriptor3D:
|
|
17
|
+
def __init__(self, desc_name=None):
|
|
18
|
+
super().__init__()
|
|
19
|
+
|
|
20
|
+
if desc_name:
|
|
21
|
+
self.transformer = getattr(Descriptors3D.rdMolDescriptors, desc_name)
|
|
22
|
+
|
|
23
|
+
def __call__(self, mol, conformer_id=None):
|
|
24
|
+
x = np.array(self.transformer(mol, confId=conformer_id))
|
|
25
|
+
x = validate_desc_vector(x)
|
|
26
|
+
return x
|
|
27
|
+
|
|
28
|
+
class RDKitGEOM(RDKitDescriptor3D):
|
|
29
|
+
def __init__(self):
|
|
30
|
+
super().__init__()
|
|
31
|
+
|
|
32
|
+
self.columns = ['CalcAsphericity',
|
|
33
|
+
'CalcEccentricity',
|
|
34
|
+
'CalcInertialShapeFactor',
|
|
35
|
+
'CalcNPR1',
|
|
36
|
+
'CalcNPR2',
|
|
37
|
+
'CalcPMI1',
|
|
38
|
+
'CalcPMI2',
|
|
39
|
+
'CalcPMI3',
|
|
40
|
+
'CalcRadiusOfGyration',
|
|
41
|
+
'CalcSpherocityIndex',
|
|
42
|
+
'CalcPBF']
|
|
43
|
+
|
|
44
|
+
def __call__(self, mol, conformer_id=None):
|
|
45
|
+
x = []
|
|
46
|
+
for desc_name in self.columns:
|
|
47
|
+
transformer = getattr(Descriptors3D.rdMolDescriptors, desc_name)
|
|
48
|
+
x.append(transformer(mol, confId=conformer_id))
|
|
49
|
+
x = np.array(x)
|
|
50
|
+
x = validate_desc_vector(x)
|
|
51
|
+
return x
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class RDKitAUTOCORR(RDKitDescriptor3D):
|
|
55
|
+
def __init__(self):
|
|
56
|
+
super().__init__('CalcAUTOCORR3D')
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class RDKitRDF(RDKitDescriptor3D):
|
|
60
|
+
def __init__(self):
|
|
61
|
+
super().__init__('CalcRDF')
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class RDKitMORSE(RDKitDescriptor3D):
|
|
65
|
+
def __init__(self):
|
|
66
|
+
super().__init__('CalcMORSE')
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class RDKitWHIM(RDKitDescriptor3D):
|
|
70
|
+
def __init__(self):
|
|
71
|
+
super().__init__('CalcWHIM')
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class RDKitGETAWAY(RDKitDescriptor3D):
|
|
75
|
+
def __init__(self):
|
|
76
|
+
super().__init__('CalcGETAWAY')
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from qsarmil.utils.logging import FailedDescriptor
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class DescriptorWrapper:
|
|
6
|
+
def __init__(self, transformer):
|
|
7
|
+
super().__init__()
|
|
8
|
+
self.transformer = transformer
|
|
9
|
+
|
|
10
|
+
def _ce2bag(self, mol):
|
|
11
|
+
bag = []
|
|
12
|
+
for conf in mol.GetConformers():
|
|
13
|
+
x = self.transformer(mol, conformer_id=conf.GetId())
|
|
14
|
+
bag.append(x)
|
|
15
|
+
|
|
16
|
+
return np.array(bag)
|
|
17
|
+
|
|
18
|
+
def transform(self, list_of_mols):
|
|
19
|
+
list_of_bags = []
|
|
20
|
+
for mol_id, mol in enumerate(list_of_mols):
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
x = self._ce2bag(mol)
|
|
24
|
+
except Exception as e:
|
|
25
|
+
print(e)
|
|
26
|
+
x = FailedDescriptor(mol)
|
|
27
|
+
list_of_bags.append(x)
|
|
28
|
+
|
|
29
|
+
return list_of_bags
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from rdkit import Chem
|
|
2
|
+
|
|
3
|
+
from rdkit import RDLogger
|
|
4
|
+
RDLogger.DisableLog('rdApp.*')
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FailedMolecule:
|
|
8
|
+
def __init__(self, smiles):
|
|
9
|
+
super().__init__()
|
|
10
|
+
self.smiles = smiles
|
|
11
|
+
|
|
12
|
+
def __str__(self):
|
|
13
|
+
return f'{self.smiles} -> SMILES parsing failed'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class FailedConformer:
|
|
17
|
+
def __init__(self, mol):
|
|
18
|
+
super().__init__()
|
|
19
|
+
self.mol = mol
|
|
20
|
+
|
|
21
|
+
def __str__(self):
|
|
22
|
+
smi = Chem.MolToSmiles(self.mol)
|
|
23
|
+
return f'{smi} -> conformer generation failed'
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FailedDescriptor:
|
|
27
|
+
def __init__(self, mol):
|
|
28
|
+
super().__init__()
|
|
29
|
+
self.mol = mol
|
|
30
|
+
|
|
31
|
+
def __str__(self):
|
|
32
|
+
smi = Chem.MolToSmiles(self.mol)
|
|
33
|
+
return f'{smi} -> descriptor calculation failed'
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qsarmil
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Molecular multi-instance machine learning
|
|
5
|
+
Author-email: Dmitry Zankov <dvzankov@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Description-Content-Type: text/x-rst
|
|
8
|
+
Requires-Dist: mikit-learn
|
|
9
|
+
Requires-Dist: rdkit
|
|
10
|
+
Requires-Dist: molfeat
|
|
11
|
+
Requires-Dist: py3Dmol
|
|
12
|
+
Requires-Dist: tqdm
|
|
13
|
+
Requires-Dist: huggingface_hub
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
pyproject.toml
|
|
2
|
+
qsarmil/__init__.py
|
|
3
|
+
qsarmil.egg-info/PKG-INFO
|
|
4
|
+
qsarmil.egg-info/SOURCES.txt
|
|
5
|
+
qsarmil.egg-info/dependency_links.txt
|
|
6
|
+
qsarmil.egg-info/requires.txt
|
|
7
|
+
qsarmil.egg-info/top_level.txt
|
|
8
|
+
qsarmil/conformer/__init__.py
|
|
9
|
+
qsarmil/conformer/base.py
|
|
10
|
+
qsarmil/conformer/rdkit.py
|
|
11
|
+
qsarmil/data/__init__.py
|
|
12
|
+
qsarmil/data/fragment.py
|
|
13
|
+
qsarmil/descriptor/__init__.py
|
|
14
|
+
qsarmil/descriptor/rdkit.py
|
|
15
|
+
qsarmil/descriptor/wrapper.py
|
|
16
|
+
qsarmil/fragment/__init__.py
|
|
17
|
+
qsarmil/fragment/base.py
|
|
18
|
+
qsarmil/fragment/rdkit.py
|
|
19
|
+
qsarmil/utils/__init__.py
|
|
20
|
+
qsarmil/utils/logging.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
qsarmil-0.1.0/setup.cfg
ADDED