robert 2.0.2__tar.gz → 2.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.
- {robert-2.0.2 → robert-2.1.0}/LICENSE +0 -0
- {robert-2.0.2 → robert-2.1.0}/PKG-INFO +54 -41
- {robert-2.0.2 → robert-2.1.0}/README.md +0 -1
- {robert-2.0.2 → robert-2.1.0}/robert/__init__.py +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/__main__.py +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/aqme.py +6 -4
- {robert-2.0.2 → robert-2.1.0}/robert/argument_parser.py +2 -4
- {robert-2.0.2 → robert-2.1.0}/robert/curate.py +66 -16
- robert-2.1.0/robert/evaluate.py +121 -0
- {robert-2.0.2 → robert-2.1.0}/robert/generate.py +34 -6
- {robert-2.0.2 → robert-2.1.0}/robert/generate_utils.py +24 -1
- {robert-2.0.2 → robert-2.1.0}/robert/icons/Robert_icon.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/icons/Robert_logo.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/icons/Robert_logo_transparent.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/icons/info_icon.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/icons/pdf_icon.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/icons/play_icon.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/icons/stop_icon.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/model_params/ADAB_params.yaml +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/model_params/GB_params.yaml +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/model_params/GP_params.yaml +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/model_params/MVL_params.yaml +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/model_params/NN_params.yaml +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/model_params/RF_params.yaml +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/model_params/VR_params.yaml +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/predict.py +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/predict_utils.py +48 -10
- {robert-2.0.2 → robert-2.1.0}/robert/report/Robert_icon.ico +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/Robert_logo.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/Robert_logo1.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/abbrev.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/adv_anal.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/features.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/generate.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/outliers.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/pred.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/repro.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_0.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_1.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_10.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_2.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_3.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_4.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_5.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_6.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_7.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_8.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_9.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_w_1_0.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_w_1_1.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_w_2_0.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_w_2_1.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_w_2_2.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_w_3_0.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_w_3_1.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_w_3_2.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/score_w_3_3.jpg +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/transpa.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report/y_distrib.png +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert/report.py +43 -26
- {robert-2.0.2 → robert-2.1.0}/robert/report_utils.py +4 -16
- {robert-2.0.2 → robert-2.1.0}/robert/robert.py +4 -21
- {robert-2.0.2 → robert-2.1.0}/robert/utils.py +464 -145
- {robert-2.0.2 → robert-2.1.0}/robert/verify.py +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert.egg-info/PKG-INFO +54 -41
- {robert-2.0.2 → robert-2.1.0}/robert.egg-info/SOURCES.txt +0 -0
- {robert-2.0.2 → robert-2.1.0}/robert.egg-info/dependency_links.txt +0 -0
- robert-2.1.0/robert.egg-info/requires.txt +18 -0
- {robert-2.0.2 → robert-2.1.0}/robert.egg-info/top_level.txt +0 -0
- {robert-2.0.2 → robert-2.1.0}/setup.cfg +10 -10
- {robert-2.0.2 → robert-2.1.0}/setup.py +17 -17
- robert-2.1.0/tests/test_1curate.py +371 -0
- {robert-2.0.2 → robert-2.1.0}/tests/test_2generate.py +119 -76
- {robert-2.0.2 → robert-2.1.0}/tests/test_3verify.py +25 -18
- {robert-2.0.2 → robert-2.1.0}/tests/test_4predict.py +31 -17
- {robert-2.0.2 → robert-2.1.0}/tests/test_5aqme_n_full.py +40 -39
- robert-2.0.2/robert/evaluate.py +0 -181
- robert-2.0.2/robert.egg-info/requires.txt +0 -16
- robert-2.0.2/tests/test_1curate.py +0 -321
|
File without changes
|
|
@@ -1,41 +1,54 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
2
|
-
Name: robert
|
|
3
|
-
Version: 2.0
|
|
4
|
-
Summary: Refiner and Optimizer of a Bunch of Existing Regression Tools
|
|
5
|
-
Home-page: https://github.com/jvalegre/robert
|
|
6
|
-
Download-URL: https://github.com/jvalegre/robert/archive/refs/tags/2.0.
|
|
7
|
-
Author: Juan V. Alegre Requena, David Dalmau
|
|
8
|
-
Author-email: jv.alegre@csic.es
|
|
9
|
-
License: MIT
|
|
10
|
-
Keywords: workflows,machine learning,cheminformatics,data curation,prediction,automated
|
|
11
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
-
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: Topic :: Software Development :: Build Tools
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist:
|
|
27
|
-
Requires-Dist:
|
|
28
|
-
Requires-Dist:
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Requires-Dist:
|
|
31
|
-
Requires-Dist:
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist:
|
|
34
|
-
Requires-Dist:
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist:
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
Requires-Dist:
|
|
40
|
-
|
|
41
|
-
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: robert
|
|
3
|
+
Version: 2.1.0
|
|
4
|
+
Summary: Refiner and Optimizer of a Bunch of Existing Regression Tools
|
|
5
|
+
Home-page: https://github.com/jvalegre/robert
|
|
6
|
+
Download-URL: https://github.com/jvalegre/robert/archive/refs/tags/2.1.0.tar.gz
|
|
7
|
+
Author: Juan V. Alegre Requena, David Dalmau
|
|
8
|
+
Author-email: jv.alegre@csic.es
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: workflows,machine learning,cheminformatics,data curation,prediction,automated
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: PyYAML==6.0.3
|
|
23
|
+
Requires-Dist: matplotlib==3.10.0
|
|
24
|
+
Requires-Dist: pandas==2.3.3
|
|
25
|
+
Requires-Dist: numpy==2.3.4
|
|
26
|
+
Requires-Dist: progress==1.6.1
|
|
27
|
+
Requires-Dist: seaborn==0.13.2
|
|
28
|
+
Requires-Dist: scipy==1.15.0
|
|
29
|
+
Requires-Dist: scikit-learn==1.7.2
|
|
30
|
+
Requires-Dist: bayesian-optimization==3.1.0
|
|
31
|
+
Requires-Dist: numba==0.62.1
|
|
32
|
+
Requires-Dist: shap==0.49.1
|
|
33
|
+
Requires-Dist: weasyprint==63.1
|
|
34
|
+
Requires-Dist: PySide6==6.9.2
|
|
35
|
+
Requires-Dist: PyMuPDF
|
|
36
|
+
Requires-Dist: ansi2html
|
|
37
|
+
Requires-Dist: rdkit==2025.9.1
|
|
38
|
+
Requires-Dist: psutil==7.0.0
|
|
39
|
+
Requires-Dist: requests==2.32.5
|
|
40
|
+
Dynamic: author
|
|
41
|
+
Dynamic: author-email
|
|
42
|
+
Dynamic: classifier
|
|
43
|
+
Dynamic: description
|
|
44
|
+
Dynamic: description-content-type
|
|
45
|
+
Dynamic: download-url
|
|
46
|
+
Dynamic: home-page
|
|
47
|
+
Dynamic: keywords
|
|
48
|
+
Dynamic: license
|
|
49
|
+
Dynamic: license-file
|
|
50
|
+
Dynamic: requires-dist
|
|
51
|
+
Dynamic: requires-python
|
|
52
|
+
Dynamic: summary
|
|
53
|
+
|
|
54
|
+
Documentation in Read The Docs: https://robert.readthedocs.io
|
|
@@ -20,7 +20,6 @@ Don't miss out the latest hands-on tutorials from our [YouTube channel](https://
|
|
|
20
20
|
3. Install ROBERT using pip: `pip install robert`
|
|
21
21
|
4. Install RDKit (only if you plan to use easyROB): `pip install rdkit`
|
|
22
22
|
5. Install libraries for the PDF report `conda install -y -c conda-forge glib gtk3 pango mscorefonts`
|
|
23
|
-
6. (Only for compatible devices) Install Intelex accelerator: `pip install scikit-learn-intelex==2025.2.0`
|
|
24
23
|
* Inexperienced users should visit the *Users with no Python experience* section in [Read the Docs](https://robert.readthedocs.io).
|
|
25
24
|
## Update the program
|
|
26
25
|
1. Update to the latest version: `pip install robert --upgrade`
|
|
File without changes
|
|
File without changes
|
|
@@ -35,7 +35,7 @@ from robert.utils import (load_variables,
|
|
|
35
35
|
)
|
|
36
36
|
|
|
37
37
|
# list of potential arguments from CSV inputs in AQME
|
|
38
|
-
aqme_args = ['charge','mult','complex_type','geom','constraints_atoms','constraints_dist','constraints_angle','constraints_dihedral']
|
|
38
|
+
aqme_args = ['charge','mult','complex_type','geom','constraints_atoms','constraints_dist','constraints_angle','constraints_dihedral','sample']
|
|
39
39
|
|
|
40
40
|
class aqme:
|
|
41
41
|
"""
|
|
@@ -79,13 +79,15 @@ class aqme:
|
|
|
79
79
|
# load database just to perform data checks (i.e. no need to run AQME if the specified y is not
|
|
80
80
|
# in the database, since the program would crush in the subsequent CURATE job)
|
|
81
81
|
job_type = 'aqme'
|
|
82
|
+
path_sdf = Path(f'{os.getcwd()}/CSEARCH/sdf_temp')
|
|
82
83
|
if aqme_test:
|
|
83
84
|
job_type = 'aqme_test'
|
|
85
|
+
if not path_sdf.exists():
|
|
86
|
+
path_sdf.mkdir(exist_ok=True, parents=True)
|
|
84
87
|
|
|
85
88
|
# move the SDF files from the csv_name run (otherwise, the xTB calcs are repeated in csv_test)
|
|
86
89
|
else:
|
|
87
|
-
path_sdf
|
|
88
|
-
if os.path.exists(path_sdf):
|
|
90
|
+
if path_sdf.exists():
|
|
89
91
|
shutil.rmtree(path_sdf)
|
|
90
92
|
path_sdf.mkdir(exist_ok=True, parents=True)
|
|
91
93
|
for sdf_file in glob.glob(f'{os.getcwd()}/CSEARCH/*.sdf'):
|
|
@@ -120,7 +122,7 @@ class aqme:
|
|
|
120
122
|
aqme_indv_name = 'AQME_indiv'
|
|
121
123
|
else:
|
|
122
124
|
smi_suffix = column.split("_")[1]
|
|
123
|
-
csv_temp['code_name'] = csv_temp['code_name'] + '_' + smi_suffix
|
|
125
|
+
csv_temp['code_name'] = csv_temp['code_name'].astype(str) + '_' + smi_suffix
|
|
124
126
|
csv_temp.to_csv(f'AQME_indiv_{smi_suffix}.csv', index=False)
|
|
125
127
|
aqme_indv_name = f'AQME_indiv_{smi_suffix}'
|
|
126
128
|
|
|
@@ -19,8 +19,6 @@ var_dict = {
|
|
|
19
19
|
"seed": 0,
|
|
20
20
|
"destination": None,
|
|
21
21
|
"csv_name" : '',
|
|
22
|
-
"csv_train": '',
|
|
23
|
-
"csv_valid": '',
|
|
24
22
|
"csv_test": '',
|
|
25
23
|
"y" : '',
|
|
26
24
|
"discard" : [],
|
|
@@ -35,11 +33,12 @@ var_dict = {
|
|
|
35
33
|
"test_set" : 0.2,
|
|
36
34
|
"auto_test" : True,
|
|
37
35
|
"auto_type": True,
|
|
36
|
+
"auto_fill": True,
|
|
38
37
|
"model" : ['RF','GB','NN','MVL'],
|
|
39
38
|
"eval_model" : 'MVL',
|
|
40
39
|
"custom_params" : None,
|
|
41
40
|
"type" : "reg",
|
|
42
|
-
"split" : "
|
|
41
|
+
"split" : "auto",
|
|
43
42
|
"nprocs": 8,
|
|
44
43
|
"error_type" : "rmse",
|
|
45
44
|
"pfi_epochs" : 5,
|
|
@@ -53,7 +52,6 @@ var_dict = {
|
|
|
53
52
|
"repeat_kfolds" : 10,
|
|
54
53
|
"alpha" : 0.05,
|
|
55
54
|
"params_dir" : '',
|
|
56
|
-
"csv_test" : '',
|
|
57
55
|
"t_value" : 2,
|
|
58
56
|
"shap_show" : 10,
|
|
59
57
|
"pfi_show" : 10,
|
|
@@ -50,7 +50,8 @@ Parameters
|
|
|
50
50
|
Number of repetitions for the k-fold cross-validation of the RFECV feature selector.
|
|
51
51
|
auto_type : bool, default=True
|
|
52
52
|
If there are only two y values, the program automatically changes the type of problem to classification.
|
|
53
|
-
|
|
53
|
+
auto_fill : bool, default = True
|
|
54
|
+
Complete missing values in columns with descriptors of "float" type using a KNN imputer
|
|
54
55
|
|
|
55
56
|
"""
|
|
56
57
|
#####################################################.
|
|
@@ -97,12 +98,23 @@ class curate:
|
|
|
97
98
|
|
|
98
99
|
# apply the correlation filters and returns the database without correlated descriptors
|
|
99
100
|
if self.args.corr_filter_x or self.args.corr_filter_y:
|
|
100
|
-
|
|
101
|
+
csv_df_result = correlation_filter(self,csv_df)
|
|
102
|
+
# Check if result is a tuple (model-specific CSVs) or single dataframe
|
|
103
|
+
if isinstance(csv_df_result, tuple):
|
|
104
|
+
csv_df, csv_df_per_model = csv_df_result
|
|
105
|
+
else:
|
|
106
|
+
csv_df = csv_df_result
|
|
107
|
+
csv_df_per_model = None
|
|
108
|
+
else:
|
|
109
|
+
csv_df_per_model = None
|
|
101
110
|
|
|
102
|
-
# save the curated
|
|
103
|
-
|
|
111
|
+
# save the curated CSVs (one per model if RFECV is applied)
|
|
112
|
+
if csv_df_per_model is not None:
|
|
113
|
+
_ = self.save_curate((csv_df, csv_df_per_model))
|
|
114
|
+
else:
|
|
115
|
+
_ = self.save_curate(csv_df)
|
|
104
116
|
|
|
105
|
-
# create Pearson heatmap
|
|
117
|
+
# create Pearson heatmap (use the general filtered dataframe)
|
|
106
118
|
_ = pearson_map(self,csv_df,'curate')
|
|
107
119
|
|
|
108
120
|
# finish the printing of the CURATE info file
|
|
@@ -140,21 +152,59 @@ class curate:
|
|
|
140
152
|
'''
|
|
141
153
|
Saves the curated database and options used in CURATE
|
|
142
154
|
'''
|
|
143
|
-
|
|
144
|
-
# saves curated database
|
|
145
|
-
csv_basename = os.path.basename(f'{self.args.csv_name}').split('.')[0]
|
|
146
|
-
csv_curate_name = f'{csv_basename}_CURATE.csv'
|
|
147
|
-
csv_curate_name = self.args.destination.joinpath(csv_curate_name)
|
|
148
|
-
_ = csv_df.to_csv(f'{csv_curate_name}', index = None, header=True)
|
|
149
|
-
path_reduced = '/'.join(f'{csv_curate_name}'.replace('\\','/').split('/')[-2:])
|
|
150
|
-
self.args.log.write(f'\no The curated database was stored in {path_reduced}.')
|
|
151
155
|
|
|
152
|
-
|
|
156
|
+
csv_basename = os.path.basename(f'{self.args.csv_name}').split('.')[0]
|
|
157
|
+
|
|
158
|
+
# Check if csv_df is a tuple (csv_df_filtered, csv_df_per_model) from correlation_filter
|
|
159
|
+
if isinstance(csv_df, tuple):
|
|
160
|
+
csv_df_filtered, csv_df_per_model = csv_df
|
|
161
|
+
|
|
162
|
+
# Save model-specific curated databases (sorted for reproducibility)
|
|
163
|
+
for model in csv_df_per_model:
|
|
164
|
+
csv_curate_name = f'{csv_basename}_CURATE_{model}.csv'
|
|
165
|
+
csv_curate_name = self.args.destination.joinpath(csv_curate_name)
|
|
166
|
+
# Sort rows by y value for reproducibility
|
|
167
|
+
csv_df_to_save = csv_df_per_model[model].reset_index(drop=True).sort_values(by=self.args.y).reset_index(drop=True)
|
|
168
|
+
_ = csv_df_to_save.to_csv(f'{csv_curate_name}', index=None, header=True)
|
|
169
|
+
|
|
170
|
+
# y values to predict, considering that ROBERT will work with multiple values of y in future versions
|
|
171
|
+
if not isinstance(self.args.y,list):
|
|
172
|
+
count_y = 1
|
|
173
|
+
else:
|
|
174
|
+
count_y = len(self.args.y)
|
|
175
|
+
|
|
176
|
+
txt_csv = f'\n o Model {model}: {len(csv_df_per_model[model].columns)-len(self.args.ignore)-count_y} descriptors remaining:\n'
|
|
177
|
+
txt_csv += ' ' + ', '.join(f'{var}' for var in csv_df_per_model[model].columns if var not in self.args.ignore and var != self.args.y)
|
|
178
|
+
self.args.log.write(txt_csv)
|
|
179
|
+
|
|
180
|
+
self.args.log.write(f'\no Model-specific curated databases were stored in {self.args.destination}')
|
|
181
|
+
|
|
182
|
+
# Save general curated database (for reference/Pearson map, sorted for reproducibility)
|
|
183
|
+
csv_curate_name_general = f'{csv_basename}_CURATE.csv'
|
|
184
|
+
csv_curate_name_general = self.args.destination.joinpath(csv_curate_name_general)
|
|
185
|
+
csv_df_to_save_general = csv_df_filtered.reset_index(drop=True).sort_values(by=self.args.y).reset_index(drop=True)
|
|
186
|
+
_ = csv_df_to_save_general.to_csv(f'{csv_curate_name_general}', index=None, header=True)
|
|
187
|
+
|
|
188
|
+
else:
|
|
189
|
+
# Original behavior: save single curated database
|
|
190
|
+
csv_curate_name_general = f'{csv_basename}_CURATE.csv'
|
|
191
|
+
csv_curate_name_general = self.args.destination.joinpath(csv_curate_name_general)
|
|
192
|
+
_ = csv_df.to_csv(f'{csv_curate_name_general}', index=None, header=True)
|
|
193
|
+
path_reduced = '/'.join(f'{csv_curate_name_general}'.replace('\\','/').split('/')[-2:])
|
|
194
|
+
self.args.log.write(f'\no The curated database was stored in {path_reduced}.')
|
|
195
|
+
|
|
196
|
+
# Save important options used in CURATE
|
|
153
197
|
options_name = f'CURATE_options.csv'
|
|
154
198
|
options_name = self.args.destination.joinpath(options_name)
|
|
155
199
|
options_df = pd.DataFrame()
|
|
156
200
|
options_df['y'] = [self.args.y]
|
|
157
201
|
options_df['ignore'] = [self.args.ignore]
|
|
158
202
|
options_df['names'] = [self.args.names]
|
|
159
|
-
options_df['csv_name'] = [
|
|
160
|
-
|
|
203
|
+
options_df['csv_name'] = [csv_curate_name_general]
|
|
204
|
+
|
|
205
|
+
# Save class label mapping if it exists (for classification with string labels)
|
|
206
|
+
if hasattr(self.args, 'class_0_label'):
|
|
207
|
+
options_df['class_0_label'] = [self.args.class_0_label]
|
|
208
|
+
options_df['class_1_label'] = [self.args.class_1_label]
|
|
209
|
+
|
|
210
|
+
_ = options_df.to_csv(f'{options_name}', index=None, header=True)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Parameters
|
|
3
|
+
----------
|
|
4
|
+
|
|
5
|
+
GENERAL
|
|
6
|
+
+++++++
|
|
7
|
+
|
|
8
|
+
csv_name : str, default=''
|
|
9
|
+
Name of the CSV file containing all the points used in the model (combining train + valid + test).
|
|
10
|
+
A path can be provided (i.e. 'C:/Users/FOLDER/FILE.csv').
|
|
11
|
+
y : str, default=''
|
|
12
|
+
Name of the column containing the response variable in the input CSV file (i.e. 'solubility').
|
|
13
|
+
names : str, default=''
|
|
14
|
+
Column of the names for each datapoint. Names are used to print outliers.
|
|
15
|
+
eval_model : str, default='MVL'
|
|
16
|
+
ML models that can be evaluated (for now, only models from sklearn are accepted, more options will be added):
|
|
17
|
+
1. 'MVL' (Multivariate lineal models, LinearRegression() in sklearn)
|
|
18
|
+
type : str, default='reg'
|
|
19
|
+
Type of the pedictions. Options:
|
|
20
|
+
1. 'reg' (Regressor)
|
|
21
|
+
2. 'clas' (Classifier)
|
|
22
|
+
seed : int, default=0
|
|
23
|
+
Random seed used in the ML predictor models and other protocols.
|
|
24
|
+
destination : str, default=None,
|
|
25
|
+
Directory to create the output file(s).
|
|
26
|
+
|
|
27
|
+
Affect VERIFY and PREDICT
|
|
28
|
+
+++++++++++++++++++++++++
|
|
29
|
+
|
|
30
|
+
kfold : int, default=5
|
|
31
|
+
Number of random data splits for the cross-validation of the models.
|
|
32
|
+
repeat_kfolds : int, default=10
|
|
33
|
+
Number of repetitions for the k-fold cross-validation of the models.
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
#####################################################.
|
|
37
|
+
# This file stores the EVALUATE class #
|
|
38
|
+
# used to evaluate existing models #
|
|
39
|
+
#####################################################.
|
|
40
|
+
|
|
41
|
+
import os
|
|
42
|
+
import shutil
|
|
43
|
+
import time
|
|
44
|
+
import pandas as pd
|
|
45
|
+
from pathlib import Path
|
|
46
|
+
from robert.utils import load_variables, finish_print, load_database, prepare_sets
|
|
47
|
+
from robert.generate_utils import set_sets
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class evaluate:
|
|
51
|
+
"""
|
|
52
|
+
Class containing all the functions from the EVALUATE module.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
kwargs : argument class
|
|
57
|
+
Specify any arguments from the EVALUATE module (for a complete list of variables, visit the ROBERT documentation)
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(self, **kwargs):
|
|
61
|
+
|
|
62
|
+
start_time = time.time()
|
|
63
|
+
|
|
64
|
+
# load default and user-specified variables
|
|
65
|
+
self.args = load_variables(kwargs, "evaluate")
|
|
66
|
+
|
|
67
|
+
# clean folders from previous runs
|
|
68
|
+
_ = self.clean_eval()
|
|
69
|
+
|
|
70
|
+
# load database, discard user-defined descriptors and perform data checks
|
|
71
|
+
csv_df, csv_X, csv_y = load_database(self,self.args.csv_name,"generate",print_info=False)
|
|
72
|
+
|
|
73
|
+
# standardizes and separates an external test set
|
|
74
|
+
Xy_data = prepare_sets(self,csv_df,csv_X,csv_y,None,self.args.names,None,None,None,BO_opt=True)
|
|
75
|
+
|
|
76
|
+
# saves database and model params in the /GENERATE/Best_model/No_PFI folder
|
|
77
|
+
_ = self.save_generate(csv_df,Xy_data)
|
|
78
|
+
|
|
79
|
+
# finish the printing of the EVALUATE info file
|
|
80
|
+
_ = finish_print(self,start_time,'EVALUATE')
|
|
81
|
+
|
|
82
|
+
def clean_eval(self):
|
|
83
|
+
'''
|
|
84
|
+
Cleans folders from previous runs
|
|
85
|
+
'''
|
|
86
|
+
|
|
87
|
+
for folder in ['CURATE','GENERATE','VERIFY','PREDICT']:
|
|
88
|
+
eval_folder = f'{Path(os.getcwd()).joinpath(folder)}'
|
|
89
|
+
if os.path.exists(eval_folder):
|
|
90
|
+
shutil.rmtree(eval_folder)
|
|
91
|
+
|
|
92
|
+
def save_generate(self,csv_df,Xy_data):
|
|
93
|
+
'''
|
|
94
|
+
Saves database and model params in the /GENERATE/Best_model/No_PFI folder
|
|
95
|
+
'''
|
|
96
|
+
|
|
97
|
+
# copy database with Set column
|
|
98
|
+
generate_folder = Path('GENERATE/Best_model/No_PFI')
|
|
99
|
+
if os.path.exists(generate_folder):
|
|
100
|
+
shutil.rmtree(generate_folder)
|
|
101
|
+
Path(generate_folder).mkdir(exist_ok=True, parents=True)
|
|
102
|
+
|
|
103
|
+
# include the Set column to differentiate between train and test sets (and external test, if any)
|
|
104
|
+
csv_df = set_sets(csv_df,Xy_data)
|
|
105
|
+
|
|
106
|
+
_ = csv_df.to_csv(f'{generate_folder}/{self.args.eval_model}_db.csv', index = None, header=True)
|
|
107
|
+
|
|
108
|
+
# save all the parameters of the model
|
|
109
|
+
df_params = pd.DataFrame()
|
|
110
|
+
df_params['kfold'] = [self.args.kfold]
|
|
111
|
+
df_params['repeat_kfolds'] = [self.args.repeat_kfolds]
|
|
112
|
+
df_params['model'] = [self.args.eval_model]
|
|
113
|
+
df_params['type'] = [self.args.type]
|
|
114
|
+
df_params['seed'] = [self.args.seed]
|
|
115
|
+
df_params['y'] = [self.args.y]
|
|
116
|
+
df_params['names'] = [self.args.names]
|
|
117
|
+
df_params['error_type'] = [self.args.error_type]
|
|
118
|
+
df_params['params'] = '{}'
|
|
119
|
+
df_params['X_descriptors'] = [list(Xy_data['X_descriptors'])]
|
|
120
|
+
|
|
121
|
+
_ = df_params.to_csv(f'{generate_folder}/{self.args.eval_model}.csv', index = None, header=True)
|
|
@@ -72,14 +72,14 @@ Parameters
|
|
|
72
72
|
Number of random data splits for the cross-validation of the models.
|
|
73
73
|
repeat_kfolds : int, default=10
|
|
74
74
|
Number of repetitions for the k-fold cross-validation of the models.
|
|
75
|
-
split : str, default='even'
|
|
75
|
+
split : str, default= 'even' (regression) or 'rnd' (classification)
|
|
76
76
|
Specifies how the data is split into training and test sets. Options:
|
|
77
77
|
1. 'even': splits the data evenly into training and test sets.
|
|
78
78
|
2. 'RND': randomly splits the data.
|
|
79
79
|
3. 'stratified': splits the data while preserving the distribution of the target variable.
|
|
80
|
-
4. 'KN': uses a k-means approach to select representative samples.
|
|
81
|
-
5. '
|
|
82
|
-
6. '
|
|
80
|
+
4. 'KN': uses a k-means approach to select representative samples for training (good for intrapolation, bad for extrapolation).
|
|
81
|
+
5. 'extra_q1': selects the 20% lowest values.
|
|
82
|
+
6. 'extra_q5': selects the 20% highest values.
|
|
83
83
|
|
|
84
84
|
"""
|
|
85
85
|
#####################################################.
|
|
@@ -87,6 +87,7 @@ Parameters
|
|
|
87
87
|
# used in model generation #
|
|
88
88
|
#####################################################.
|
|
89
89
|
|
|
90
|
+
import os
|
|
90
91
|
import time
|
|
91
92
|
from robert.utils import (
|
|
92
93
|
load_variables,
|
|
@@ -145,8 +146,32 @@ class generate:
|
|
|
145
146
|
|
|
146
147
|
self.args.log.write(f' - {cycle}/{len(self.args.model)} - ML model: {ML_model} ')
|
|
147
148
|
|
|
149
|
+
# Try to load model-specific curated CSV first, fall back to general CSV
|
|
150
|
+
# Get the base name from the original csv_name (remove path if any)
|
|
151
|
+
if 'CURATE' in str(self.args.csv_name):
|
|
152
|
+
# If csv_name is already a CURATE file, extract the original base name
|
|
153
|
+
csv_basename = os.path.basename(f'{self.args.csv_name}').replace('_CURATE.csv', '').replace('.csv', '')
|
|
154
|
+
else:
|
|
155
|
+
csv_basename = os.path.basename(f'{self.args.csv_name}').split('.')[0]
|
|
156
|
+
|
|
157
|
+
curate_folder = self.args.initial_dir.joinpath('CURATE')
|
|
158
|
+
csv_model_specific = curate_folder.joinpath(f'{csv_basename}_CURATE_{ML_model}.csv')
|
|
159
|
+
|
|
160
|
+
# Store the original csv_name temporarily
|
|
161
|
+
original_csv_name = self.args.csv_name
|
|
162
|
+
|
|
163
|
+
if os.path.exists(csv_model_specific):
|
|
164
|
+
csv_to_load = csv_model_specific
|
|
165
|
+
# Temporarily update csv_name to the model-specific CSV
|
|
166
|
+
self.args.csv_name = str(csv_model_specific)
|
|
167
|
+
self.args.log.write(f' o Using model-specific curated database: {os.path.basename(csv_model_specific)}')
|
|
168
|
+
else:
|
|
169
|
+
csv_to_load = self.args.csv_name
|
|
170
|
+
self.args.log.write(f' x Using general database (model-specific not found): {os.path.basename(self.args.csv_name)}')
|
|
171
|
+
|
|
148
172
|
# load database, discard user-defined descriptors and perform data checks
|
|
149
|
-
csv_df, csv_X, csv_y = load_database(self,
|
|
173
|
+
csv_df, csv_X, csv_y = load_database(self,csv_to_load,"generate",print_info=False)
|
|
174
|
+
|
|
150
175
|
|
|
151
176
|
# standardizes and separates an external test set
|
|
152
177
|
Xy_data = prepare_sets(self,csv_df,csv_X,csv_y,None,self.args.names,None,None,None,BO_opt=True)
|
|
@@ -157,12 +182,15 @@ class generate:
|
|
|
157
182
|
# apply the PFI descriptor filter if it's activated
|
|
158
183
|
if self.args.pfi_filter:
|
|
159
184
|
# load database, discard user-defined descriptors and perform data checks
|
|
160
|
-
csv_df, csv_X, csv_y = load_database(self,
|
|
185
|
+
csv_df, csv_X, csv_y = load_database(self,csv_to_load,"generate",print_info=False)
|
|
161
186
|
|
|
162
187
|
# standardizes and separates an external test set
|
|
163
188
|
Xy_data = prepare_sets(self,csv_df,csv_X,csv_y,None,self.args.names,None,None,None,BO_opt=True)
|
|
164
189
|
|
|
165
190
|
_ = PFI_workflow(self, csv_df, ML_model, Xy_data)
|
|
191
|
+
|
|
192
|
+
# Restore the original csv_name
|
|
193
|
+
self.args.csv_name = original_csv_name
|
|
166
194
|
|
|
167
195
|
cycle += 1
|
|
168
196
|
|
|
@@ -7,6 +7,7 @@ import shutil
|
|
|
7
7
|
import pandas as pd
|
|
8
8
|
import numpy as np
|
|
9
9
|
import glob
|
|
10
|
+
import json
|
|
10
11
|
from robert.utils import (
|
|
11
12
|
load_params,
|
|
12
13
|
PFI_filter,
|
|
@@ -50,7 +51,23 @@ def BO_workflow(self, Xy_data, csv_df, ML_model):
|
|
|
50
51
|
db_name = self.args.destination.joinpath(f"Raw_data/No_PFI/{ML_model}_db")
|
|
51
52
|
params_name = self.args.destination.joinpath(f"Raw_data/No_PFI/{ML_model.upper()}")
|
|
52
53
|
_ = csv_df.to_csv(f'{db_name}.csv', index = None, header=True)
|
|
53
|
-
|
|
54
|
+
|
|
55
|
+
# Convert params dict to string to avoid serialization issues
|
|
56
|
+
bo_data_to_save = bo_data.copy()
|
|
57
|
+
if 'params' in bo_data_to_save:
|
|
58
|
+
bo_data_to_save['params'] = json.dumps(bo_data_to_save['params'])
|
|
59
|
+
if 'X_descriptors' in bo_data_to_save:
|
|
60
|
+
bo_data_to_save['X_descriptors'] = json.dumps(bo_data_to_save['X_descriptors'])
|
|
61
|
+
|
|
62
|
+
# Save class label mapping if it exists (for classification with string labels)
|
|
63
|
+
if hasattr(self.args, 'class_0_label'):
|
|
64
|
+
bo_data_to_save['class_0_label'] = self.args.class_0_label
|
|
65
|
+
bo_data_to_save['class_1_label'] = self.args.class_1_label
|
|
66
|
+
|
|
67
|
+
# Save split type
|
|
68
|
+
bo_data_to_save['split'] = self.args.split
|
|
69
|
+
|
|
70
|
+
bo_data_df = pd.DataFrame([bo_data_to_save])
|
|
54
71
|
_ = bo_data_df.to_csv(f'{params_name}.csv', index = None, header=True)
|
|
55
72
|
|
|
56
73
|
return bo_data
|
|
@@ -133,6 +150,12 @@ def save_pfi_csv(self,csv_df,name_csv_hyperopt,PFI_dict,Xy_data_PFI,ML_model):
|
|
|
133
150
|
|
|
134
151
|
name_csv_hyperopt_PFI = name_csv_hyperopt.replace('No_PFI','PFI')
|
|
135
152
|
path_csv_PFI = self.args.destination.joinpath(f'{name_csv_hyperopt_PFI}_PFI')
|
|
153
|
+
|
|
154
|
+
# Save class label mapping if it exists (for classification with string labels)
|
|
155
|
+
if hasattr(self.args, 'class_0_label'):
|
|
156
|
+
PFI_dict['class_0_label'] = self.args.class_0_label
|
|
157
|
+
PFI_dict['class_1_label'] = self.args.class_1_label
|
|
158
|
+
|
|
136
159
|
csv_PFI_df = pd.DataFrame([PFI_dict])
|
|
137
160
|
_ = csv_PFI_df.to_csv(f'{path_csv_PFI}.csv', index = None, header=True)
|
|
138
161
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|