Spaces:
Running
Running
| ##################################################################################### | |
| # Python Script to build Machine Learning Models from CSV data containing smiles # | |
| # Written by Ruel Cedeno, Ph.D. # | |
| ##################################################################################### | |
| ###################### | |
| # Import libraries # | |
| ###################### | |
| #Data Processing | |
| import pandas as pd | |
| import numpy as np | |
| from scipy.stats import pearsonr | |
| import pickle | |
| from joblib import dump, load | |
| from mapply.mapply import mapply | |
| from copy import deepcopy | |
| import datetime | |
| from joblib import parallel_backend | |
| import re | |
| from collections import defaultdict | |
| #Rdkit | |
| import rdkit.Chem as Chem | |
| from rdkit.Chem import rdFingerprintGenerator | |
| from rdkit.Chem import AllChem | |
| from rdkit.Chem import Descriptors, PandasTools | |
| from rdkit import DataStructs | |
| from rdkit.Chem.Lipinski import NumHDonors, NumHAcceptors, NHOHCount,NOCount | |
| from rdkit.SimDivFilters import rdSimDivPickers | |
| from collections import defaultdict | |
| from rdkit.DataStructs import TanimotoSimilarity | |
| from rdkit.Chem.Scaffolds.MurckoScaffold import MurckoScaffoldSmilesFromSmiles | |
| #Sklearn / ML | |
| from sklearn.pipeline import Pipeline | |
| from sklearn.model_selection import cross_val_score, GridSearchCV | |
| from sklearn.metrics import make_scorer | |
| from sklearn.model_selection import train_test_split | |
| from sklearn import preprocessing | |
| from sklearn.ensemble import RandomForestRegressor, ExtraTreesClassifier | |
| from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error | |
| from sklearn.inspection import permutation_importance | |
| from sklearn.model_selection import cross_val_score, cross_validate, ShuffleSplit, StratifiedKFold, StratifiedShuffleSplit, RandomizedSearchCV, KFold, GridSearchCV, RepeatedKFold, RepeatedStratifiedKFold, GroupShuffleSplit, StratifiedGroupKFold | |
| from sklearn.model_selection import BaseCrossValidator | |
| from sklearn.feature_selection import VarianceThreshold | |
| from sklearn.ensemble import AdaBoostClassifier, GradientBoostingClassifier, RandomForestClassifier, VotingClassifier, VotingRegressor, ExtraTreesRegressor | |
| from sklearn.tree import DecisionTreeClassifier | |
| from sklearn.svm import SVC | |
| from sklearn.neural_network import MLPClassifier | |
| from sklearn.pipeline import Pipeline,make_pipeline | |
| from sklearn.metrics import cohen_kappa_score,accuracy_score, precision_score, recall_score, f1_score,roc_auc_score,confusion_matrix, matthews_corrcoef | |
| from sklearn.decomposition import PCA | |
| from sklearn.preprocessing import StandardScaler | |
| from sklearn.metrics import silhouette_samples, silhouette_score | |
| from sklearn.cluster import KMeans | |
| from sklearn import datasets, decomposition | |
| from sklearn.manifold import TSNE | |
| import xgboost as xg | |
| from lightgbm import LGBMRegressor | |
| from lightgbm import LGBMClassifier | |
| import plotly.express as px | |
| from sklearn.svm import SVR | |
| from time import process_time | |
| from sklearn.model_selection import KFold | |
| from custom_classes import RemoveZeroVarianceFeatures, RemoveAutocorrelatedFeatures | |
| def canonicalize_smi(smi): | |
| try: | |
| canon_smi = Chem.MolToSmiles(Chem.MolFromSmiles(smi,sanitize=False)) | |
| except TypeError: | |
| canon_smi = "CCCCC" | |
| return canon_smi | |
| def get_canon_smi(smi_series): | |
| return list(mapply(smi_series, lambda x: canonicalize_smi(x), progressbar=False)) | |
| def get_BM(smi_series): | |
| return list(mapply(smi_series, lambda x: Chem.Scaffolds.MurckoScaffold.MurckoScaffoldSmilesFromSmiles(x,includeChirality=True), progressbar=False)) | |
| def stratified_train_test_split(X, y, test_size=0.2, random_state=None,n_bins=10): | |
| # Bin the target variable | |
| y_binned = pd.qcut(y, q=n_bins, labels=False, duplicates='drop') | |
| # Perform stratified split using the binned target | |
| #y = np.array(y) if len(np.unique(y)) == 2 else np.array(y) >= np.median(y) | |
| X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, stratify=y_binned, random_state=random_state) | |
| return X_train, X_test, y_train, y_test | |
| def stratified_train_test_split_idx(canon_series, y, test_size=0.2, random_state=None,n_bins=10): | |
| # Bin the target variable | |
| y_binned = pd.qcut(y, q=n_bins, labels=False, duplicates='drop') | |
| # Generate an array of indices corresponding to the dataset | |
| indices = np.arange(len(canon_series)) | |
| # Perform stratified split using the binned target variable and indices | |
| train_indices, test_indices = train_test_split( | |
| indices, | |
| test_size=test_size, | |
| stratify=y_binned, | |
| random_state=random_state | |
| ) | |
| train_test_index = {} | |
| train_test_index["train"] = list(train_indices) | |
| train_test_index["test"] = list(test_indices) | |
| return train_test_index | |
| def scaffold_based_train_test_split_idx(canon_series, y,test_size=0.2, random_state=None): | |
| if random_state is not None: | |
| np.random.seed(random_state) | |
| df = pd.DataFrame() | |
| df["smiles"] =canon_series.values | |
| df["scaff_id"] = get_BM(canon_series) | |
| # Extract the required columns | |
| X = df.index.values | |
| y = np.array(y) if len(np.unique(y)) == 2 else np.array(y) >= np.median(y) | |
| #y = y if np.unique(y) == 2 else np.array(y) >= np.median(y) | |
| groups = df['scaff_id'].values | |
| n_splits = 5 | |
| # Initialize RepeatedGroupShuffleSplit | |
| rgss = StratifiedGroupKFold(n_splits=n_splits, shuffle=True,random_state=random_state) | |
| # Find the best split that maintains the ratio of "is_positive" | |
| best_train_idx, best_test_idx = None, None | |
| best_diff = float('inf') | |
| for train_idx, test_idx in rgss.split(X, y, groups): | |
| y_train, y_test = y[train_idx], y[test_idx] | |
| train_pos_ratio = y_train.mean() | |
| test_pos_ratio = y_test.mean() | |
| ratio_diff = abs(train_pos_ratio - test_pos_ratio) | |
| if ratio_diff < best_diff: | |
| best_diff = ratio_diff | |
| best_train_idx, best_test_idx = train_idx, test_idx | |
| return {'train': best_train_idx.tolist(), 'test': best_test_idx.tolist()} | |
| class RepeatedScaffoldBasedCV(BaseCrossValidator): | |
| def __init__(self, n_splits, n_repeats, smiles_series, y, test_size, random_state=42): | |
| self.n_splits = n_splits | |
| self.n_repeats = n_repeats | |
| self.smiles_series = smiles_series | |
| self.y = y | |
| self.test_size = test_size | |
| self.random_state = random_state | |
| def split(self, X, y=None, groups=None): | |
| np.random.seed(self.random_state) | |
| for repeat in range(self.n_repeats): | |
| for split in range(self.n_splits): | |
| random_state = np.random.randint(0, 10000) | |
| split_dict = scaffold_based_train_test_split_idx( | |
| self.smiles_series, self.y, self.test_size, random_state | |
| ) | |
| train_idx = split_dict['train'] | |
| test_idx = split_dict['test'] | |
| #print("test_idx",test_idx) | |
| #print("train_idx",train_idx) | |
| yield train_idx, test_idx | |
| def get_n_splits(self, X=None, y=None, groups=None): | |
| return self.n_splits * self.n_repeats | |
| class RepeatedStratifiedBasedCV(BaseCrossValidator): | |
| def __init__(self, n_splits, n_repeats, smiles_series, y, test_size, random_state=42): | |
| self.n_splits = n_splits | |
| self.n_repeats = n_repeats | |
| self.smiles_series = smiles_series | |
| self.y = y | |
| self.test_size = test_size | |
| self.random_state = random_state | |
| def split(self, X, y=None, groups=None): | |
| np.random.seed(self.random_state) | |
| for repeat in range(self.n_repeats): | |
| for split in range(self.n_splits): | |
| random_state = np.random.randint(0, 10000) | |
| split_dict = stratified_train_test_split_idx( | |
| self.smiles_series, self.y, self.test_size, random_state | |
| ) | |
| train_idx = split_dict['train'] | |
| test_idx = split_dict['test'] | |
| #print("test_idx",test_idx) | |
| #print("train_idx",train_idx) | |
| yield train_idx, test_idx | |
| def get_n_splits(self, X=None, y=None, groups=None): | |
| return self.n_splits * self.n_repeats | |
| def get_rdkit_desc(mol): | |
| rdkit_desc = np.array([descriptor_function(mol) for descriptor_name,descriptor_function in Descriptors.descList]) | |
| rdkit_desc_clean = np.clip(np.nan_to_num(np.array(rdkit_desc).astype(float), copy=False, nan=0),a_min=-1e5, a_max=1e5) | |
| return rdkit_desc_clean | |
| def spearman_corr(y_true, y_pred): | |
| return np.corrcoef(y_true, y_pred, rowvar=False)[0, 1] | |
| nbits=1024 | |
| fpdict = {} | |
| #fpdict['ecfp4'] = lambda m: AllChem.GetMorganFingerprintAsBitVect(m, 2, nBits=nbits, useChirality=True) | |
| invgen = AllChem.GetMorganFeatureAtomInvGen() | |
| fpdict['ecfp4_np'] = lambda m: rdFingerprintGenerator.GetMorganGenerator(radius=2,fpSize=nbits,includeChirality=True).GetFingerprintAsNumPy(m) | |
| fpdict['fcfp4_np'] = lambda m: rdFingerprintGenerator.GetMorganGenerator(radius=2,fpSize=nbits,includeChirality=True,atomInvariantsGenerator=invgen).GetFingerprintAsNumPy(m) | |
| fpdict['ecfp4_bit'] = lambda m: rdFingerprintGenerator.GetMorganGenerator(radius=2,fpSize=nbits,includeChirality=True).GetFingerprint(m) | |
| fpdict['rdk5'] = lambda m: Chem.RDKFingerprint(m, maxPath=5, fpSize=nbits, nBitsPerHash=2) | |
| fpdict['rdkit'] = lambda m: get_rdkit_desc(m) | |
| #fpdict['ecfc6'] = lambda m: AllChem.GetMorganFingerprint(m, 3,nBits=nbits, useChirality=True) | |
| def CalculateFP(smiles,fp_name='ecfp4'): | |
| try: | |
| #print("smiles",smiles) | |
| m = Chem.MolFromSmiles(smiles) | |
| return fpdict[fp_name](m) | |
| except: | |
| print(smiles,"INVALID !") | |
| return fpdict[fp_name](Chem.MolFromSmiles('CCCC')) | |
| def get_desc(smi_series, desc_name='ecfp4_bit'): | |
| if desc_name == 'ecfp4_bit': # return bits instead of numpy array | |
| with parallel_backend('multiprocessing'): | |
| return list(mapply(smi_series, lambda x: CalculateFP(x, 'ecfp4_bit'), progressbar=True)) | |
| elif desc_name == 'ECFP4': | |
| with parallel_backend('multiprocessing'): | |
| return np.array(list(mapply(smi_series, lambda x: CalculateFP(x, 'ecfp4_np'), progressbar=True))) | |
| elif desc_name == 'RDK5': | |
| with parallel_backend('multiprocessing'): | |
| return list(mapply(smi_series, lambda x: CalculateFP(x, 'rdk5'), progressbar=True)) | |
| elif desc_name == 'FCFP4': | |
| with parallel_backend('multiprocessing'): | |
| return list(mapply(smi_series, lambda x: CalculateFP(x, 'fcfp4_np'), progressbar=True)) | |
| elif desc_name == 'RDKIT': | |
| return list(mapply(smi_series, lambda x: CalculateFP(x, 'rdkit'), progressbar=True)) | |
| #return list(smi_series.apply(lambda x: CalculateFP(Chem.MolFromSmiles(x), 'rdkit') )) | |
| else: | |
| raise ValueError(f"Descriptor name '{desc_name}' is not recognized.") | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| rand_state = 42 | |
| from sklearn.impute import SimpleImputer | |
| ################################################################## | |
| #### CLASSIFICATION | |
| ################################################################### | |
| from sklearn.metrics import average_precision_score | |
| from sklearn.metrics import confusion_matrix | |
| def get_confusion_matrix(clf,X,y): | |
| y_pred = clf.predict(X) | |
| return confusion_matrix(y, y_pred).ravel() | |
| ################################################################## | |
| #### CLASSIFICATION | |
| ################################################################### | |
| from sklearn.metrics import average_precision_score | |
| from sklearn.metrics import confusion_matrix | |
| def get_confusion_matrix(clf,X,y): | |
| y_pred = clf.predict(X) | |
| return confusion_matrix(y, y_pred).ravel() | |
| class QSAR_Classifier: | |
| X,y,X_train,X_test,y_train,y_test = [],[],[],[],[],[] | |
| random_state = 42 | |
| model_performance = pd.DataFrame() | |
| df_cv = pd.DataFrame() | |
| best_model = lambda: None | |
| use_default_mordred_desc = False | |
| def __init__(self,X,y,canon_series,test_size=0.2,CV_split=5,train_test_index=None): | |
| self.X = np.array(X) | |
| self.y = np.array(y) | |
| self.test_size = test_size | |
| self.canon_series = canon_series | |
| self.CV_split = CV_split | |
| self.train_test_index = train_test_index | |
| if train_test_index is None: | |
| self.X_train, self.X_test, self.y_train, self.y_test = stratified_train_test_split(X, y, test_size=self.test_size, n_bins=10, random_state=42) | |
| else: | |
| self.X_train = self.X[train_test_index["train"]] | |
| self.X_test = self.X[train_test_index["test"]] | |
| self.y_train = self.y[train_test_index["train"]] | |
| self.y_test = self.y[train_test_index["test"]] | |
| def compare_model_cv(self,model_obj_list,model_name_list,scaffold_split=True): | |
| df = pd.DataFrame() | |
| df_cv_list = [] | |
| n_fold = 5 | |
| n_repeats = int(self.CV_split/n_fold) | |
| scoring = {'ACC':'accuracy','AUC':'roc_auc','MCC':'matthews_corrcoef','MAP':'average_precision'} | |
| for obj,name in zip(model_obj_list,model_name_list): | |
| model_opt = obj | |
| #folds = StratifiedKFold(n_splits=5, shuffle=False, random_state=None) | |
| if not scaffold_split: | |
| folds = RepeatedStratifiedBasedCV(n_fold, n_repeats, self.canon_series.iloc[self.train_test_index["train"]], self.y_train, self.test_size, self.random_state) | |
| else: | |
| folds = RepeatedScaffoldBasedCV(n_fold, n_repeats, self.canon_series.iloc[self.train_test_index["train"]], self.y_train, self.test_size, self.random_state) | |
| #folds = StratifiedKFold(n_splits=5, shuffle=False, random_state=None) | |
| scores = cross_validate(model_opt, self.X_train, self.y_train, scoring=scoring, cv=folds,return_train_score=False) | |
| res_mean = pd.DataFrame(scores).transpose().mean(axis=1) | |
| res_std = pd.DataFrame(scores).transpose().std(axis=1) # 5 = number of cv folds | |
| metric_name = list(res_mean.keys()) | |
| model_opt_trained = deepcopy(model_opt.fit(self.X_train,self.y_train)) | |
| df['metric'] = metric_name + ['Test_ACC','Test_AUC', 'Test_MCC','Test(tn, fp, fn, tp)'] + [f"{j}_std" for j in metric_name ]+['model_obj'] | |
| df_cv_i = pd.DataFrame(scores) | |
| df_cv_i["algo"] = name | |
| df_cv_list.append(df_cv_i) | |
| print(f"model={name}") | |
| print(scores) | |
| y_test_pred = model_opt_trained.predict(self.X_test) | |
| test_acc,test_auc,test_mcc = [np.round(metric_func(self.y_test,y_test_pred),2) for metric_func in [accuracy_score,roc_auc_score,matthews_corrcoef]] | |
| test_conf = confusion_matrix(self.y_test,y_test_pred).ravel() | |
| df[name] = list(np.round(res_mean.values,2)) + [test_acc,test_auc,test_mcc] +[(test_conf)] + list(res_std.values) +[deepcopy(model_opt)] | |
| self.model_performance = df | |
| #self.best_model = self.model_performance[df.columns[1]].iloc[-1] #take the first column and the last row | |
| self.df_cv = pd.concat(df_cv_list,ignore_index=True) | |
| return self.model_performance.set_index("metric"), self.df_cv | |
| def create_pipeline(clf): | |
| pipeline = Pipeline([ | |
| ('remove_zero_variance', VarianceThreshold(threshold=0.05)), | |
| ('remove_autocorrelated', RemoveAutocorrelatedFeatures(threshold=0.95)), | |
| ('scaler', StandardScaler()), | |
| ('estimator', clf) | |
| ]) | |
| return pipeline | |
| xgb_c = create_pipeline(xg.XGBClassifier(n_estimators=500,verbosity = 0, device='cpu')) | |
| lgbm_c = create_pipeline(LGBMClassifier(n_estimators=500,objective='binary',verbose=-1,device = "cpu")) | |
| rf_c = create_pipeline(RandomForestClassifier(n_estimators=500)) | |
| et_c = create_pipeline(ExtraTreesClassifier(n_estimators=500)) | |
| voting_c = VotingClassifier(estimators=[ | |
| ('LGBM', lgbm_c), | |
| ('XGB', xgb_c), | |
| ('RF',rf_c), | |
| ('ET',et_c)], voting='soft', n_jobs=-1) | |
| classifier_dict = {} | |
| classifier_dict["LightGBM"] = lgbm_c | |
| classifier_dict["XGBoost"] = xgb_c | |
| classifier_dict["RandomForest"] = rf_c | |
| classifier_dict["ExtraTrees"] = et_c | |
| classifier_dict["Consensus"] = voting_c | |
| ################################################################## | |
| #### REGRESSION | |
| ################################################################### | |
| def pearson_r_scorer(clf, X, y): | |
| y_pred = clf.predict(X) | |
| return pearsonr(y,y_pred)[0] | |
| def RMSE_scorer(clf, X, y): | |
| y_pred = clf.predict(X) | |
| return (mean_squared_error(y,y_pred))**0.5 | |
| def MAE_scorer(clf, X, y): | |
| y_pred = clf.predict(X) | |
| return (mean_absolute_error(y,y_pred)) | |
| class QSAR_Regressor: | |
| X,y,X_train,X_test,y_train,y_test = [],[],[],[],[],[] | |
| test_size = 0.15 | |
| random_state = rand_state | |
| model_performance = pd.DataFrame() | |
| df_cv = pd.DataFrame() | |
| best_model = lambda: None | |
| use_default_mordred_desc = False | |
| def __init__(self,X,y,canon_series,test_size=0.15,CV_split=5,train_test_index=None): | |
| self.X = np.array(X) | |
| self.y = np.array(y) | |
| self.test_size = test_size | |
| self.canon_series = canon_series | |
| self.CV_split = CV_split | |
| self.train_test_index=train_test_index | |
| if train_test_index is None: | |
| self.X_train, self.X_test, self.y_train, self.y_test = stratified_train_test_split(X, y, test_size=self.test_size, n_bins=10, random_state=42) | |
| else: | |
| self.X_train = self.X[train_test_index["train"]] | |
| self.X_test = self.X[train_test_index["test"]] | |
| self.y_train = self.y[train_test_index["train"]] | |
| self.y_test = self.y[train_test_index["test"]] | |
| """ | |
| else: | |
| try: | |
| self.X_train, self.X_test, self.y_train, self.y_test = scaffold_based_train_test_split(self.canon_series,X, y, test_size=self.test_size, random_state=42) | |
| except: #When scaffold split fails (e.g. all have the same scaffold, revert to random stratified split) | |
| self.X_train, self.X_test, self.y_train, self.y_test = stratified_train_test_split(X, y, test_size=self.test_size, n_bins=10, random_state=42) | |
| """ | |
| def compare_model_cv(self,model_obj_list,model_name_list,criteria='roc_auc',retrain_to_all=True,scaffold_split=True): | |
| df = pd.DataFrame() | |
| df_cv_list = [] | |
| scoring = {"pearsonR":pearson_r_scorer, "RMSE": RMSE_scorer, 'MAE':MAE_scorer} | |
| n_fold = 5 | |
| n_repeats = int(self.CV_split/n_fold) | |
| for obj,name in zip(model_obj_list,model_name_list): | |
| model_opt = obj | |
| #folds = StratifiedKFold(n_splits=5, shuffle=False, random_state=None) | |
| if not scaffold_split: | |
| folds = RepeatedStratifiedBasedCV(n_fold, n_repeats, self.canon_series.iloc[self.train_test_index["train"]], self.y_train, self.test_size, self.random_state) | |
| else: | |
| folds = RepeatedScaffoldBasedCV(n_fold, n_repeats, self.canon_series.iloc[self.train_test_index["train"]], self.y_train, self.test_size, self.random_state) | |
| scores = cross_validate(model_opt, self.X_train, self.y_train, scoring=scoring, cv=folds,return_train_score=False) | |
| res_mean = pd.DataFrame(scores).transpose().mean(axis=1) | |
| res_std = pd.DataFrame(scores).transpose().std(axis=1) # 5 = number of cv folds | |
| metric_name = list(res_mean.keys()) | |
| model_opt_trained = deepcopy(model_opt.fit(self.X_train,self.y_train)) | |
| df['metric'] = metric_name + ['Test_pearsonR','Test_MAE','Test_RMSE'] + [f"{j}_std" for j in metric_name ]+['model_obj'] | |
| df_cv_i = pd.DataFrame(scores) | |
| df_cv_i["algo"] = name | |
| df_cv_list.append(df_cv_i) | |
| y_test_pred = model_opt_trained.predict(self.X_test) | |
| test_pearson_r,test_mae,test_rmse, = [np.round(metric_func(self.y_test,y_test_pred),2) for metric_func in | |
| [lambda y,y_pred: pearsonr(y,y_pred)[0],mean_absolute_error, lambda y,y_pred: mean_squared_error(y,y_pred)**0.5 ]] | |
| df[name] = list(np.round(res_mean.values,2)) + [test_pearson_r,test_mae,test_rmse] + list(res_std.values) +[deepcopy(model_opt)] | |
| self.model_performance = df | |
| self.df_cv = pd.concat(df_cv_list,ignore_index=True) | |
| return self.model_performance.set_index("metric"), self.df_cv | |
| #callbacks = [lightgbm.early_stopping(10, verbose=0), lgb.log_evaluation(period=0)] | |
| rand_state = 42 | |
| xgb_r = create_pipeline(xg.XGBRegressor(random_state=rand_state)) | |
| lgbm_r = create_pipeline(LGBMRegressor(n_estimators=500, subsample=0.8, colsample_bytree=0.8,subsample_freq=1,random_state=rand_state)) | |
| svr_r = make_pipeline(preprocessing.StandardScaler(), SVR()) | |
| rf_r = create_pipeline(RandomForestRegressor(n_estimators=500,oob_score=True,random_state=rand_state)) | |
| et_r = create_pipeline(ExtraTreesRegressor(n_estimators=500)) | |
| voting = VotingRegressor(estimators=[ | |
| ('LGBM', lgbm_r), | |
| ('XGB', xgb_r), | |
| ('RF',rf_r), | |
| ('ET',et_r)], n_jobs=-1) | |
| regressor_dict = {} | |
| regressor_dict["LightGBM"] = lgbm_r | |
| regressor_dict["XGBoost"] = xgb_r | |
| regressor_dict["RandomForest"] = rf_r | |
| regressor_dict['ExtraTrees'] = et_r | |
| regressor_dict["Consensus"] = voting | |
| def benchmark_model(smi_series,y,desc_list=['ECFP4'],model_name=["LightGBM"],task='Binary Classification',test_size=0.15,CV_split=5,split_type='Random Split'): | |
| res_df = pd.DataFrame() | |
| cv_df = pd.DataFrame() | |
| y = list(y) | |
| if split_type =='Random Split': | |
| scaffold_split = False | |
| train_test_index = stratified_train_test_split_idx(smi_series, y, test_size=0.2, random_state=42) | |
| elif split_type == 'Scaffold Split': | |
| scaffold_split = True | |
| train_test_index = scaffold_based_train_test_split_idx(smi_series,y, test_size=0.2, random_state=42) | |
| data_obj_dict = {} | |
| if task == "Binary Classification": | |
| for desc in desc_list: | |
| X = get_desc(smi_series,desc) | |
| model = QSAR_Classifier(X,y,smi_series,test_size=test_size,train_test_index=train_test_index) | |
| model_obj_list = [classifier_dict[i] for i in model_name] | |
| df_model, df_cv_i = model.compare_model_cv(model_obj_list,model_name,scaffold_split=scaffold_split) | |
| trans_df = df_model.transpose() | |
| trans_df['algo'] = list(trans_df.index) | |
| trans_df['desc'] = [ desc for i in list(trans_df.index)] | |
| trans_df.reset_index(drop=True) | |
| res_df = pd.concat([res_df,trans_df],ignore_index=True) | |
| data_obj_dict[desc] = model | |
| df_cv_i['desc'] = desc | |
| #print(df_cv_i) | |
| cv_df = pd.concat([cv_df,df_cv_i],ignore_index=True) | |
| res_df = res_df.rename(columns=lambda x: x.replace('test_', 'Val_') if x.startswith('test_') else x) # in sklearn, validation results are labeled as 'test_' | |
| prior_cols = ['algo', 'desc','Test_ACC','Test_AUC', 'Test_MCC', 'Test(tn, fp, fn, tp)','Val_ACC','Val_AUC','Val_MCC','Val_MAP'] | |
| non_prior_cols = [i for i in res_df.columns if i not in prior_cols] | |
| if task == "Regression": | |
| for desc in desc_list: | |
| X = get_desc(smi_series,desc) | |
| model = QSAR_Regressor(X,y,smi_series,test_size=test_size,train_test_index=train_test_index) | |
| model_obj_list = [regressor_dict[i] for i in model_name] | |
| df_model, df_cv_i = model.compare_model_cv(model_obj_list,model_name,scaffold_split=scaffold_split) | |
| trans_df = df_model.transpose() | |
| trans_df['algo'] = list(trans_df.index) | |
| trans_df['desc'] = [ desc for i in list(trans_df.index)] | |
| trans_df.reset_index(drop=True) | |
| res_df = pd.concat([res_df,trans_df],ignore_index=True) | |
| data_obj_dict[desc] = model | |
| df_cv_i['desc'] = desc | |
| cv_df = pd.concat([cv_df,df_cv_i],ignore_index=True) | |
| res_df = res_df.rename(columns=lambda x: x.replace('test_', 'Val_') if x.startswith('test_') else x) | |
| prior_cols = ['algo', 'desc','Test_pearsonR','Test_MAE','Test_RMSE','Val_pearsonR','Val_MAE','Val_RMSE'] | |
| non_prior_cols = [i for i in res_df.columns if i not in prior_cols] | |
| print("cv_df",cv_df) | |
| return res_df[prior_cols + non_prior_cols], data_obj_dict, cv_df | |
| def eval_predictions(y_exp,y_pred,task="Classifier",thresh=None,y_transformed_binary=False): | |
| thresh = thresh if thresh is not None else np.median(y_exp) | |
| if y_transformed_binary == True: | |
| thresh = 0.5 | |
| classifier_metrics_name = ["Accuracy","AUC-ROC","AUC-PR","MCC","ConfusionMatrix(tn,fp,fn,tp)"] | |
| classifier_metrics_func = [lambda y,y_pred: accuracy_score(y >= thresh,y_pred >= 0.5), | |
| lambda y,y_pred: roc_auc_score(y>=thresh,y_pred), | |
| lambda y,y_pred: average_precision_score(y>=thresh,y_pred), | |
| lambda y,y_pred: matthews_corrcoef(y >= thresh,y_pred >= 0.5), | |
| lambda y,y_pred: [confusion_matrix(y >= thresh,y_pred >=0.5).ravel()]] | |
| regressor_metrics_name = ["PearsonR","MAE","RMSE"] | |
| regressor_metrics_func = [lambda y,y_pred: pearsonr(y,y_pred)[0], | |
| lambda y,y_pred: mean_absolute_error(y,y_pred), | |
| lambda y,y_pred: mean_squared_error(y,y_pred)**0.5 ] | |
| if task == "Classifier": | |
| result_df = {name:func(y_exp,y_pred) for name,func in zip(classifier_metrics_name,classifier_metrics_func)} | |
| if task == "Regressor": | |
| result_df = {name:func(y_exp,y_pred) for name,func in zip(regressor_metrics_name,regressor_metrics_func)} | |
| return result_df | |
| #smi_col = "smiles" | |
| #df = pd.DataFrame({'smiles': ['CCCCC','CCCCCCCCCCCC','CCCCCCCCCCC','CCCCCCCCCCCCCCCCCCCCC'], 'pMIC_Ng':[3,6,9,12]}) | |
| #df = pd.read_csv("denovo_top_50.csv") | |
| #df_res = benchmark_model(df.smiles,[i > 3 for i in df.pMIC_g]) | |
| #print(df_res) | |
| #result_global.query('desc == "cddd"').model.values[0].apply_model(X_cddd) | |