| from .model import ModelWrapper |
| import numpy as np |
| from rdkit import Chem |
| from rdkit.Chem import AllChem, DataStructs |
| import shap |
|
|
| def smiles_to_ecfp(smiles, radius=2, n_bits=1024): |
| mol = Chem.MolFromSmiles(smiles) |
| if mol is None: |
| return np.zeros(n_bits) |
| fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius, nBits=n_bits) |
| arr = np.zeros(n_bits, dtype=int) |
| DataStructs.ConvertToNumpyArray(fp, arr) |
| return arr |
|
|
| models = [ |
| ModelWrapper("solubility.pth"), |
| ModelWrapper("logp.pth"), |
| ModelWrapper("clintox.pth"), |
| ModelWrapper("fdaapprov.pth"), |
| ModelWrapper("cardiotoxicity.pth"), |
| ] |
|
|
| def solubility(X): |
| try: |
| X = smiles_to_ecfp(X) |
| X = np.asarray(X, dtype=float) |
| return models[0].model.predict([X]).item() |
| except Exception as e: |
| print(e) |
| return 0 |
|
|
|
|
| def logp(X): |
| try: |
| X = smiles_to_ecfp(X) |
| X = np.asarray(X, dtype=float) |
| return models[1].model.predict([X]).item() |
| except Exception as e: |
| print(e) |
| return 0 |
|
|
| def clintox(X): |
| try: |
| X = smiles_to_ecfp(X) |
| X = np.asarray(X, dtype=float) |
| return models[2].model.predict([X]).item() |
| except Exception as e: |
| print(e) |
| return 0 |
|
|
| def fdaapprov(X): |
| try: |
| X = smiles_to_ecfp(X) |
| X = np.asarray(X, dtype=float) |
| return models[3].model.predict([X]).item() |
| except Exception as e: |
| print(e) |
| return 0 |
|
|
| def cardiotoxicity(X): |
| try: |
| X = smiles_to_ecfp(X) |
| X = np.asarray(X, dtype=float) |
| return models[4].model.predict([X]).item() |
| except Exception as e: |
| print(e) |
| return 0 |
| |
| def solubility_shap(X, model_wrapper=models[0]): |
| """ |
| Возвращает предсказание растворимости + данные для фронтенда: |
| atom_shap |
| """ |
| try: |
| |
| mol = Chem.MolFromSmiles(X) |
| if mol is None: |
| return {"pred": 0, "atom_shap": [], "fp": [], "bitInfo": {}, "shap_values_bits": []} |
|
|
| bitInfo = {} |
| fp_vect = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=1024, bitInfo=bitInfo) |
| fp = np.zeros(1024, dtype=int) |
| DataStructs.ConvertToNumpyArray(fp_vect, fp) |
|
|
| |
| X_input = np.asarray(fp, dtype=float).reshape(1,-1) |
| pred = model_wrapper.model.predict(X_input).item() |
|
|
| |
| if not hasattr(model_wrapper, "shap_explainer"): |
| |
| model_wrapper.shap_explainer = shap.TreeExplainer(model_wrapper.model) |
| shap_vals_bits = model_wrapper.shap_explainer.shap_values(X_input)[0] |
|
|
| |
| atom_scores = np.zeros(mol.GetNumAtoms(), dtype=float) |
| for bit, val in enumerate(shap_vals_bits): |
| if bit in bitInfo: |
| atoms = [a for (a,r) in bitInfo[bit]] |
| for a in atoms: |
| atom_scores[a] += val |
|
|
| return { |
| "pred": pred, |
| "atom_shap": atom_scores.tolist() |
| } |
|
|
| except Exception as e: |
| print(e) |
| return {"pred": 0, "atom_shap": []} |
| |
| def logp_shap(X, model_wrapper=models[1]): |
| """ |
| Возвращает предсказание растворимости + данные для фронтенда: |
| atom_shap |
| """ |
| try: |
| |
| mol = Chem.MolFromSmiles(X) |
| if mol is None: |
| return {"pred": 0, "atom_shap": [], "fp": [], "bitInfo": {}, "shap_values_bits": []} |
|
|
| bitInfo = {} |
| fp_vect = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=1024, bitInfo=bitInfo) |
| fp = np.zeros(1024, dtype=int) |
| DataStructs.ConvertToNumpyArray(fp_vect, fp) |
|
|
| |
| X_input = np.asarray(fp, dtype=float).reshape(1,-1) |
| pred = model_wrapper.model.predict(X_input).item() |
|
|
| |
| if not hasattr(model_wrapper, "shap_explainer"): |
| |
| model_wrapper.shap_explainer = shap.TreeExplainer(model_wrapper.model) |
| shap_vals_bits = model_wrapper.shap_explainer.shap_values(X_input)[0] |
|
|
| |
| atom_scores = np.zeros(mol.GetNumAtoms(), dtype=float) |
| for bit, val in enumerate(shap_vals_bits): |
| if bit in bitInfo: |
| atoms = [a for (a,r) in bitInfo[bit]] |
| for a in atoms: |
| atom_scores[a] += val |
|
|
| return { |
| "pred": pred, |
| "atom_shap": atom_scores.tolist() |
| } |
|
|
| except Exception as e: |
| print(e) |
| return {"pred": 0, "atom_shap": []} |
| |
| def clintox_shap(X, model_wrapper=models[2]): |
| """ |
| Возвращает предсказание растворимости + данные для фронтенда: |
| atom_shap |
| """ |
| try: |
| |
| mol = Chem.MolFromSmiles(X) |
| if mol is None: |
| return {"pred": 0, "atom_shap": [], "fp": [], "bitInfo": {}, "shap_values_bits": []} |
|
|
| bitInfo = {} |
| fp_vect = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=1024, bitInfo=bitInfo) |
| fp = np.zeros(1024, dtype=int) |
| DataStructs.ConvertToNumpyArray(fp_vect, fp) |
|
|
| |
| X_input = np.asarray(fp, dtype=float).reshape(1,-1) |
| pred = model_wrapper.model.predict(X_input).item() |
|
|
| |
| if not hasattr(model_wrapper, "shap_explainer"): |
| |
| model_wrapper.shap_explainer = shap.TreeExplainer(model_wrapper.model) |
| shap_vals_bits = model_wrapper.shap_explainer.shap_values(X_input)[0] |
|
|
| |
| atom_scores = np.zeros(mol.GetNumAtoms(), dtype=float) |
| for bit, val in enumerate(shap_vals_bits): |
| if bit in bitInfo: |
| atoms = [a for (a,r) in bitInfo[bit]] |
| for a in atoms: |
| atom_scores[a] += val |
|
|
| return { |
| "pred": pred, |
| "atom_shap": atom_scores.tolist() |
| } |
|
|
| except Exception as e: |
| print(e) |
| return {"pred": 0, "atom_shap": []} |
| |
| def fdaapprov_shap(X, model_wrapper=models[3]): |
| """ |
| Возвращает предсказание растворимости + данные для фронтенда: |
| atom_shap |
| """ |
| try: |
| |
| mol = Chem.MolFromSmiles(X) |
| if mol is None: |
| return {"pred": 0, "atom_shap": [], "fp": [], "bitInfo": {}, "shap_values_bits": []} |
|
|
| bitInfo = {} |
| fp_vect = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=1024, bitInfo=bitInfo) |
| fp = np.zeros(1024, dtype=int) |
| DataStructs.ConvertToNumpyArray(fp_vect, fp) |
|
|
| |
| X_input = np.asarray(fp, dtype=float).reshape(1,-1) |
| pred = model_wrapper.model.predict(X_input).item() |
|
|
| |
| if not hasattr(model_wrapper, "shap_explainer"): |
| |
| model_wrapper.shap_explainer = shap.TreeExplainer(model_wrapper.model) |
| shap_vals_bits = model_wrapper.shap_explainer.shap_values(X_input)[0] |
|
|
| |
| atom_scores = np.zeros(mol.GetNumAtoms(), dtype=float) |
| for bit, val in enumerate(shap_vals_bits): |
| if bit in bitInfo: |
| atoms = [a for (a,r) in bitInfo[bit]] |
| for a in atoms: |
| atom_scores[a] += val |
|
|
| return { |
| "pred": pred, |
| "atom_shap": atom_scores.tolist() |
| } |
|
|
| except Exception as e: |
| print(e) |
| return {"pred": 0, "atom_shap": []} |
| |
|
|
| def cardiotoxicity_shap(X, model_wrapper=models[4]): |
| """ |
| Возвращает предсказание растворимости + данные для фронтенда: |
| atom_shap |
| """ |
| try: |
| |
| mol = Chem.MolFromSmiles(X) |
| if mol is None: |
| return {"pred": 0, "atom_shap": [], "fp": [], "bitInfo": {}, "shap_values_bits": []} |
|
|
| bitInfo = {} |
| fp_vect = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=1024, bitInfo=bitInfo) |
| fp = np.zeros(1024, dtype=int) |
| DataStructs.ConvertToNumpyArray(fp_vect, fp) |
|
|
| |
| X_input = np.asarray(fp, dtype=float).reshape(1,-1) |
| pred = model_wrapper.model.predict(X_input).item() |
|
|
| |
| if not hasattr(model_wrapper, "shap_explainer"): |
| |
| model_wrapper.shap_explainer = shap.TreeExplainer(model_wrapper.model) |
| shap_vals_bits = model_wrapper.shap_explainer.shap_values(X_input)[0] |
|
|
| |
| atom_scores = np.zeros(mol.GetNumAtoms(), dtype=float) |
| for bit, val in enumerate(shap_vals_bits): |
| if bit in bitInfo: |
| atoms = [a for (a,r) in bitInfo[bit]] |
| for a in atoms: |
| atom_scores[a] += val |
|
|
| return { |
| "pred": pred, |
| "atom_shap": atom_scores.tolist() |
| } |
|
|
| except Exception as e: |
| print(e) |
| return {"pred": 0, "atom_shap": []} |
|
|
|
|
| property_predictors = { |
| "solubility": solubility, |
| "logp": logp, |
| "clintox": clintox, |
| "fdaapprov": fdaapprov, |
| "cardiotoxicity": cardiotoxicity, |
| } |
|
|
| property_predictors_shap = { |
| "solubility": solubility_shap, |
| "logp": logp_shap, |
| "clintox": clintox_shap, |
| "fdaapprov": fdaapprov_shap, |
| "cardiotoxicity": cardiotoxicity_shap, |
| } |
|
|
|
|
| def predict(X, shap=False): |
| props = {} |
| try: |
| if shap: |
| for property in property_predictors_shap.keys(): |
| props[property] = property_predictors_shap[property](X) |
| return props |
| else: |
| for property in property_predictors.keys(): |
| props[property] = property_predictors[property](X) |
| return props |
| except Exception as e: |
| print(e) |
| return None |
|
|