DescripyTor 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.
Files changed (64) hide show
  1. descripytor-0.1.0/DescripyTor.egg-info/PKG-INFO +723 -0
  2. descripytor-0.1.0/DescripyTor.egg-info/SOURCES.txt +62 -0
  3. descripytor-0.1.0/DescripyTor.egg-info/dependency_links.txt +1 -0
  4. descripytor-0.1.0/DescripyTor.egg-info/requires.txt +33 -0
  5. descripytor-0.1.0/DescripyTor.egg-info/top_level.txt +1 -0
  6. descripytor-0.1.0/MolFeatures/Getting_started_with_examples/descriptor_extraction_toolkit/_dx_check.py +382 -0
  7. descripytor-0.1.0/MolFeatures/Getting_started_with_examples/descriptor_extraction_toolkit/descriptor_extractor.py +703 -0
  8. descripytor-0.1.0/MolFeatures/Getting_started_with_examples/descriptor_extraction_toolkit/feature_packages.py +652 -0
  9. descripytor-0.1.0/MolFeatures/Getting_started_with_examples/descriptor_extraction_toolkit/make_picker.py +506 -0
  10. descripytor-0.1.0/MolFeatures/Getting_started_with_examples/descriptor_extraction_toolkit/webapp/app.py +1835 -0
  11. descripytor-0.1.0/MolFeatures/M1_pre_calculations/__init__.py +0 -0
  12. descripytor-0.1.0/MolFeatures/M1_pre_calculations/main.py +69 -0
  13. descripytor-0.1.0/MolFeatures/M1_pre_calculations/outwards_senders.py +104 -0
  14. descripytor-0.1.0/MolFeatures/M1_pre_calculations/pre_calculation_editors.py +74 -0
  15. descripytor-0.1.0/MolFeatures/M2_data_extractor/__init__.py +45 -0
  16. descripytor-0.1.0/MolFeatures/M2_data_extractor/cube_sterimol.py +616 -0
  17. descripytor-0.1.0/MolFeatures/M2_data_extractor/data_extractor.py +2284 -0
  18. descripytor-0.1.0/MolFeatures/M2_data_extractor/extractor_utils/__init__.py +0 -0
  19. descripytor-0.1.0/MolFeatures/M2_data_extractor/extractor_utils/bond_angle_length_utils.py +247 -0
  20. descripytor-0.1.0/MolFeatures/M2_data_extractor/extractor_utils/dipole_utils.py +275 -0
  21. descripytor-0.1.0/MolFeatures/M2_data_extractor/extractor_utils/sterimol_utils.py +913 -0
  22. descripytor-0.1.0/MolFeatures/M2_data_extractor/extractor_utils/sterimol_utils_old.py +859 -0
  23. descripytor-0.1.0/MolFeatures/M2_data_extractor/extractor_utils/vibrations_utils.py +692 -0
  24. descripytor-0.1.0/MolFeatures/M2_data_extractor/feather_extractor.py +740 -0
  25. descripytor-0.1.0/MolFeatures/M2_data_extractor/feature_extraction_gui.html +6363 -0
  26. descripytor-0.1.0/MolFeatures/M2_data_extractor/gaussian_handler.py +235 -0
  27. descripytor-0.1.0/MolFeatures/M2_data_extractor/gui_server.py +454 -0
  28. descripytor-0.1.0/MolFeatures/M2_data_extractor/morfeus_sterics.py +214 -0
  29. descripytor-0.1.0/MolFeatures/M2_data_extractor/sterimol_standalone.py +1781 -0
  30. descripytor-0.1.0/MolFeatures/M3_modeler/__init__.py +0 -0
  31. descripytor-0.1.0/MolFeatures/M3_modeler/modeling.py +3566 -0
  32. descripytor-0.1.0/MolFeatures/M3_modeler/modeling_utils.py +1200 -0
  33. descripytor-0.1.0/MolFeatures/M3_modeler/plot.py +3862 -0
  34. descripytor-0.1.0/MolFeatures/M3_modeler/plot_backup.py +3772 -0
  35. descripytor-0.1.0/MolFeatures/MolAlign/MCS_optimization.py +131 -0
  36. descripytor-0.1.0/MolFeatures/MolAlign/RDKIT_utils.py +655 -0
  37. descripytor-0.1.0/MolFeatures/MolAlign/__init__.py +0 -0
  38. descripytor-0.1.0/MolFeatures/MolAlign/df_funs.py +99 -0
  39. descripytor-0.1.0/MolFeatures/MolAlign/extract_bo.py +251 -0
  40. descripytor-0.1.0/MolFeatures/MolAlign/fmcs.py +2654 -0
  41. descripytor-0.1.0/MolFeatures/MolAlign/gaussian_handler.py +193 -0
  42. descripytor-0.1.0/MolFeatures/MolAlign/loss.py +19 -0
  43. descripytor-0.1.0/MolFeatures/MolAlign/molecules/results/json_swap.py +120 -0
  44. descripytor-0.1.0/MolFeatures/MolAlign/pybel_ff.py +56 -0
  45. descripytor-0.1.0/MolFeatures/MolAlign/renumbering.py +821 -0
  46. descripytor-0.1.0/MolFeatures/MolAlign/rotations.py +14 -0
  47. descripytor-0.1.0/MolFeatures/MolAlign/trial.py +48 -0
  48. descripytor-0.1.0/MolFeatures/__init__.py +16 -0
  49. descripytor-0.1.0/MolFeatures/__main__.py +1848 -0
  50. descripytor-0.1.0/MolFeatures/utils/__init__.py +0 -0
  51. descripytor-0.1.0/MolFeatures/utils/_build_viewer_nb.py +894 -0
  52. descripytor-0.1.0/MolFeatures/utils/constants.py +64 -0
  53. descripytor-0.1.0/MolFeatures/utils/file_handlers.py +154 -0
  54. descripytor-0.1.0/MolFeatures/utils/help_functions.py +1818 -0
  55. descripytor-0.1.0/MolFeatures/utils/mcs_and_alignment.py +339 -0
  56. descripytor-0.1.0/MolFeatures/utils/obabel_wrappers.py +21 -0
  57. descripytor-0.1.0/MolFeatures/utils/rdkit_nx_wrappers.py +67 -0
  58. descripytor-0.1.0/MolFeatures/utils/rdkit_utils.py +158 -0
  59. descripytor-0.1.0/MolFeatures/utils/visualize.py +875 -0
  60. descripytor-0.1.0/PKG-INFO +723 -0
  61. descripytor-0.1.0/README.md +684 -0
  62. descripytor-0.1.0/pyproject.toml +53 -0
  63. descripytor-0.1.0/setup.cfg +4 -0
  64. descripytor-0.1.0/setup.py +11 -0
@@ -0,0 +1,723 @@
1
+ Metadata-Version: 2.4
2
+ Name: DescripyTor
3
+ Version: 0.1.0
4
+ Summary: Molecular feature extraction, alignment, and modeling tools.
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: pandas==2.1.4
8
+ Requires-Dist: rdkit==2023.9.3
9
+ Requires-Dist: python-igraph==0.11.3
10
+ Requires-Dist: XlsxWriter==3.1.9
11
+ Requires-Dist: ipywidgets==8.1.1
12
+ Requires-Dist: pyarrow==14.0.2
13
+ Requires-Dist: plotly==5.18.0
14
+ Requires-Dist: customtkinter==5.2.1
15
+ Requires-Dist: chardet==5.2.0
16
+ Requires-Dist: matplotlib==3.8.2
17
+ Requires-Dist: rmsd==1.5.1
18
+ Requires-Dist: networkx==3.1
19
+ Requires-Dist: dash==2.14.2
20
+ Requires-Dist: pyvista==0.43.3
21
+ Requires-Dist: pyvistaqt==0.11.0
22
+ Requires-Dist: morfeus-ml==0.7.2
23
+ Requires-Dist: scikit-learn==1.3.2
24
+ Requires-Dist: seaborn==0.13.2
25
+ Requires-Dist: Pillow==10.3.0
26
+ Requires-Dist: scipy==1.11.4
27
+ Requires-Dist: tqdm==4.66.1
28
+ Requires-Dist: statsmodels==0.14.1
29
+ Requires-Dist: adjustText==1.2.0
30
+ Requires-Dist: multiprocess==0.70.17
31
+ Requires-Dist: shap==0.48.0
32
+ Requires-Dist: pymc==5.12.0
33
+ Requires-Dist: tabulate==0.9.0
34
+ Requires-Dist: ipykernel==6.28.0
35
+ Provides-Extra: dev
36
+ Requires-Dist: build>=1.2; extra == "dev"
37
+ Requires-Dist: pytest>=7; extra == "dev"
38
+ Requires-Dist: ruff>=0.5; extra == "dev"
39
+
40
+ # MolFeatures
41
+
42
+ **A Python package for computational chemists - designed for easy, chemical intuition based molecular feature extraction.**
43
+ This package is modeled after the R package *MoleculaR*.
44
+ For detailed guides and documentation, see [MoleculaR's web page](https://barkais.github.io/).
45
+
46
+ ---
47
+
48
+ ## Installation
49
+
50
+ 1. **Clone or download the repository** and extract it.
51
+ 2. **Create a new environment** (recommended, via conda or pip):
52
+
53
+ ```bash
54
+ conda create -n molfeatures python=3.10
55
+ conda activate molfeatures
56
+ ```
57
+
58
+ or
59
+
60
+ ```bash
61
+ python -m venv molfeatures
62
+ source molfeatures/bin/activate # Linux/Mac
63
+ molfeatures\Scripts\activate # Windows
64
+ ```
65
+ 3. **Install dependencies**:
66
+
67
+ ```bash
68
+ pip install -r requirements.txt
69
+ ```
70
+
71
+ Alternatively, run:
72
+
73
+ ```bash
74
+ python install_packages.py
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Examples
80
+
81
+ For hands-on examples, see the **`Getting_started_with_examples`** directory inside **MolFeatures**.
82
+
83
+ ## Exploring available options :
84
+ Type the following command inside MolFeatures to see all options -
85
+ ```bash
86
+ python __main__.py
87
+
88
+ usage: __main__.py [-h] {gui,model,feature_extraction,logs_to_feather,cube,sterimol} ...
89
+
90
+ MolFeatures Package
91
+
92
+ positional arguments:
93
+ {gui,model,feature_extraction,logs_to_feather,cube,sterimol}
94
+ gui Run the GUI app
95
+ model Run regression or classification
96
+ feature_extraction Run feature extraction - complete set - from input file
97
+ logs_to_feather Convert log files to feather files
98
+ cube Calculates cube sterimol from cube files
99
+ sterimol Calculate sterimol values from xyz files
100
+
101
+ optional arguments:
102
+ -h, --help show this help message and exit
103
+ ```
104
+
105
+
106
+
107
+ ## Recomended : Work with the jupyter notebooks to learn more about feature extraction and modeling - go to Getting_started_with_examples
108
+
109
+
110
+ # Feature Extraction: `Molecules` and `Molecule`
111
+
112
+ This document explains the feature‑extraction layer used to turn quantum‑chemistry outputs and geometries into model‑ready descriptors. It focuses on the **`Molecules`** batch orchestration class and uses **`Molecule`** methods where needed.
113
+
114
+ ---
115
+
116
+ ## Overview
117
+
118
+ * **Input**: a directory of per‑molecule **`.feather`** files (produced by your Gaussian/processing pipeline).
119
+ * **Core classes**:
120
+
121
+ * **`Molecules`** — loads many molecules, provides batch extractors that return wide, analysis‑ready DataFrames.
122
+ * **`Molecule`** — wraps one molecule’s geometry, connectivity, charges, dipoles, vibrations, etc., and exposes descriptor calculators.
123
+ * **Output**: horizontally concatenated DataFrames (per descriptor family) keyed by molecule name, plus optional visualizations and per‑molecule exports.
124
+
125
+ > **Indexing note:** Most public methods accept human‑friendly **1‑based** atom indices; internally, indices are normalized (via `adjust_indices`) to match underlying arrays.
126
+
127
+ ---
128
+
129
+ ## `Molecules`: batch orchestrator
130
+
131
+ ### Construction
132
+
133
+ ```python
134
+ from data_extractor import Molecules
135
+
136
+ molset = Molecules("/path/to/feather_dir", threshold=1.82)
137
+ ```
138
+
139
+ * Scans the directory for `*.feather`, creates a `Molecule` for each.
140
+ * Tracks which files loaded successfully (`success_molecules`) and which failed (`failed_molecules`).
141
+ * `threshold` controls the **distance cutoff** used to infer connectivity (bonds) for all created molecules.
142
+
143
+ ### Selection & export helpers
144
+
145
+ ```python
146
+ molset.filter_molecules([0, 3, 5]) # keep a subset by position
147
+ molset.export_all_xyz() # write per‑molecule XYZ files to ./xyz_files
148
+ molset.extract_all_dfs() # write each molecule’s internal DataFrames as CSVs
149
+ molset.visualize_molecules([0, 1]) # quick 3D previews
150
+ molset.visualize_smallest_molecule() # pick smallest by atom count and visualize
151
+ ```
152
+
153
+ ### Batch descriptor extractors (wide tables)
154
+
155
+ Each method iterates over all loaded molecules, calls the respective `Molecule` method, and returns a **horizontally concatenated** DataFrame (one block per molecule). Typical usage:
156
+
157
+ ```python
158
+ # Sterimol on atom pairs [[1,6], [3,4]] using CPK radii
159
+ steri = molset.get_sterimol_dict([[1,6],[3,4]], radii='CPK')
160
+
161
+ # NPA on base trio [1,2,3] (optionally also sub‑atoms)
162
+ npa = molset.get_npa_dict([1,2,3], sub_atoms=[5,6,7])
163
+
164
+ # Ring vibrations on para/cross pattern seeds
165
+ rings = molset.get_ring_vibration_dict([[8],[14]]])
166
+
167
+ # Dipoles for base specs (single or multiple groups)
168
+ dips = molset.get_dipole_dict([[1,2,3], 5, 6]) # origin set [1,2,3], y=5, plane=6
169
+
170
+ # Bond metrics
171
+ angles = molset.get_bond_angle_dict([1,2,3])
172
+ lengths = molset.get_bond_length_dict([[1,2],[3,4]])
173
+
174
+ # Vibrational descriptors
175
+ stretch = molset.get_stretch_vibration_dict([[1,2],[3,4]], threshold=3000)
176
+ bend = molset.get_bend_vibration_dict([[1,2],[3,4]], threshold=1300)
177
+
178
+ # Charges & differences (supports multiple charge types)
179
+ charges = molset.get_charge_df_dict([3,5,7,9]) # type='all' inside
180
+ charge_diff = molset.get_charge_diff_df_dict([[1,2],[3,4]]) # type='all' by default
181
+ ```
182
+
183
+ **Return shape:** A wide table where each molecule contributes a column block. When a molecule’s computation fails, it is skipped (and a message is logged/printed).
184
+
185
+ ### Turn GUI inputs into a feature set: `get_molecules_features_set(...)`
186
+
187
+ This convenience routine consumes text‑box‑like inputs (strings or widgets), parses them into lists of atom indices, runs the requested extractors, and returns a single **feature matrix** (`res_df`).
188
+
189
+ ```python
190
+ res = molset.get_molecules_features_set(entries={
191
+ 'Ring': '[[8],[14]]',
192
+ 'Stretching': '[[1,2],[3,4]]',
193
+ 'Bending': '[[1,2],[3,4]]',
194
+ 'NPA': '[1,2,3]',
195
+ 'Dipole': '[[1,2,3], 5, 6]',
196
+ 'Charges': '[3,5,7,9]',
197
+ 'Charge-Diff': '[[1,2],[3,4]]',
198
+ 'Sterimol': '[[1,6],[3,4]]',
199
+ 'Bond-Angle': '[1,2,3]',
200
+ 'Bond-Length': '[[1,2],[3,4]]',
201
+ }, parameters={'Radii': 'CPK', 'Isotropic': True}, save_as=True,
202
+ csv_file_name='features_csv')
203
+ ```
204
+
205
+ * Parses strings like `'[[1,6],[3,4]]'` into nested lists automatically.
206
+ * Runs only the steps for which you provided inputs (ring, stretching, bending, NPA, dipole, charges, charge\_diff, sterimol, bond\_angle, bond\_length).
207
+ * When `Isotropic=True`, appends **polarizability** and **energy** per molecule.
208
+ * Produces an interactive correlation heatmap and a CSV with highly correlated pairs.
209
+ * If `save_as=True`, writes `features_csv.csv` and `features_csv_correlation_table.csv`.
210
+
211
+ ---
212
+
213
+ ## `Molecule`: per‑molecule descriptors
214
+
215
+ ### Initialization
216
+
217
+ ```python
218
+ mol = Molecule("/path/to/LS1716_optimized.feather", threshold=1.82)
219
+ ```
220
+
221
+ * Loads the `.feather` through your `feather_file_handler` (no need to change CWD manually; class handles it).
222
+ * Populates:
223
+
224
+ * **Geometry**: `xyz_df` (atom, x, y, z), `coordinates_array`.
225
+ * **Connectivity**: `bonds_df` (inferred via distance cutoff), `atype_list` (atom types).
226
+ * **Quantum outputs**: `gauss_dipole_df`, `polarizability_df`, `info_df`, `energy_value`, `charge_dict`, `vibration_dict` (plus `vibration_mode_dict`).
227
+ * The `threshold` controls bond detection; increase slightly for longer bonds, decrease for stricter graphs.
228
+
229
+ ### Core utilities
230
+
231
+ * **Renumber atoms**: `renumber_atoms({old: new, ...})`
232
+ Rebuilds `xyz_df`, connectivity, types, and reindexes `charge_dict`/`vibration_dict` to match the new order. A helper `reindex_vibration_dict()` is available when you have a `new_index_order` prepared.
233
+
234
+ * **Export & visualize**:
235
+ `write_xyz_file()` → write per‑molecule XYZ;
236
+ `write_csv_files()` → dump all internal DataFrames;
237
+ `visualize_molecule(vector=None)` → 3D viewer (optionally override dipole vector).
238
+
239
+ * **Descriptor summary**:
240
+ `get_molecule_descriptors_df()` → concatenates energy, Gaussian dipole, and Sterimol into one small table and sorts by `energy_value`.
241
+
242
+ ### Sterimol
243
+
244
+ ```python
245
+ mol.get_sterimol(base_atoms=None, radii='CPK', sub_structure=True, drop_atoms=None, mode='all')
246
+ ```
247
+
248
+ * If `base_atoms=None`, an automatic base is detected.
249
+ * Accepts either a **single pair** `[i,j]` or a **list of pairs** `[[i,j], [k,l], ...]` and concatenates results.
250
+ * `process_sterimol_atom_group(...)` is the worker that computes Sterimol for one pair.
251
+
252
+ ### Charges (NBO/Hirshfeld/CM5…)
253
+
254
+ ```python
255
+ mol.get_charge_df([3,5,7,9], type='all') # dict of DataFrames per charge type
256
+ mol.get_charge_df([3,5,7,9], type=['nbo','cm5']) # select types
257
+
258
+ # Differences per pair (single or many)
259
+ mol.get_charge_diff_df([[1,2],[3,4]], type='all')
260
+ ```
261
+
262
+ * `type='all'` returns a dictionary of DataFrames for every available type in `charge_dict` (silently skips missing types).
263
+ * Differences compute `atom_i − atom_j` per mode and label the columns as `diff_i-j`.
264
+
265
+ ### Dipoles (Gaussian‑based)
266
+
267
+ ```python
268
+ # Atoms can be one of:
269
+ # [o, y, plane]
270
+ # [o1, o2, ..., y, plane]
271
+ # [[o1, o2, ...], y, plane]
272
+
273
+ df = mol.get_dipole_gaussian_df([ [1,2,3], 5, 6 ], visualize_bool=True)
274
+ ```
275
+
276
+ * Flexible “R‑style” base specification: single origin, multiple origins, or an explicit list of origins.
277
+ * Returns a one‑row DataFrame per spec; `get_dipole_gaussian_df(...)` handles a **list of specs** and concatenates rows.
278
+ * Optional visualization uses the centroid of the origin set as the vector origin.
279
+
280
+ ### Bond metrics
281
+
282
+ ```python
283
+ ang = mol.get_bond_angle([1,2,3])
284
+ len1 = mol.get_bond_length([1,2])
285
+ lenN = mol.get_bond_length([[1,2],[3,4]])
286
+ ```
287
+
288
+ ### Vibrational descriptors
289
+
290
+ **Stretch (pair‑aligned; typical high‑frequency cut)**
291
+
292
+ ```python
293
+ vst = mol.get_stretch_vibration([1,2], threshold=3000)
294
+ # or many: mol.get_stretch_vibration([[1,2],[3,4]], threshold=3000)
295
+ ```
296
+
297
+ * Validates that the pair is bonded.
298
+ * Computes dot‑product‑based alignment per mode, selects the maximum within the threshold.
299
+
300
+ **Bend (pair with common center)**
301
+
302
+ ```python
303
+ vbd = mol.get_bend_vibration([1,2], threshold=1300)
304
+ ```
305
+
306
+ * Builds a local adjacency, finds a shared center, then uses cross‑product magnitudes to identify the strongest bending mode.
307
+
308
+ **Ring vibrations (para / cross analysis)**
309
+
310
+ ```python
311
+ rings = mol.get_ring_vibrations([[1,4],[2,5]], return_nan_on_empty=True)
312
+ ```
313
+
314
+ * Resolves a benzene‑like pattern around the provided seed(s).
315
+ * Returns `cross`, `cross_angle`, `para`, `para_angle`. If filters eliminate everything and `return_nan_on_empty=True`, a NaN row is returned (instead of `None`).
316
+
317
+ ### Geometry transforms and helpers
318
+
319
+ * `get_coordinates_mean_point([i,j,k])` → centroid of selected atoms.
320
+ * `get_coordination_transformation_df([i,j,k], origin=None)` → axis transform (e.g., for frame‑aligned analyses).
321
+ * `swap_atom_pair((i,j))` → swap coordinates of two atoms (useful for quick what‑ifs).
322
+
323
+ ---
324
+
325
+ ## Practical tips
326
+
327
+ * **Indexing**: You can pass 1‑based indices; the code standardizes them internally. When you rename or reorder atoms, re‑extract descriptors to ensure consistency.
328
+ * **Connectivity cutoff**: If bonds are missing/extra, adjust `threshold` in the constructor (default 1.82 Å).
329
+ * **Robustness**: Most batch methods skip failing molecules and continue, printing a helpful message.
330
+ * **Correlations**: Use the GUI aggregator (`get_molecules_features_set`) to quickly assemble a matrix and auto‑inspect highly correlated features before modeling.
331
+
332
+ ---
333
+
334
+ ## Minimal end‑to‑end example
335
+
336
+ ```python
337
+ molset = Molecules("./mols", threshold=1.82)
338
+
339
+ # Extract a compact, model‑ready feature set
340
+ feat = molset.get_molecules_features_set(
341
+ entries={
342
+ 'Sterimol': '[[1,6],[3,4]]',
343
+ 'Stretching': '[[1,2],[3,4]]',
344
+ 'Bond-Angle': '[1,2,3]',
345
+ 'Dipole': '[[1,2,3], 5, 6]'
346
+ },
347
+ parameters={'Radii': 'CPK', 'Isotropic': True},
348
+ save_as=True,
349
+ csv_file_name='molecule_features'
350
+ )
351
+
352
+ print(feat.shape)
353
+ ```
354
+
355
+ # M3 Modeler — Machine Learning for Molecular Modeling
356
+
357
+ A comprehensive package for developing, evaluating, and applying machine‑learning models to molecular datasets. Supports both **regression** and **classification** with specialized tools for **feature selection**, **model evaluation**, **predictive analysis**, and dataset **balancing/sampling**.
358
+
359
+ ---
360
+
361
+ ## Table of Contents
362
+
363
+ * [Features](#features)
364
+ * [Installation](#installation)
365
+ * [Data Expectations](#data-expectations)
366
+ * [Quick Start](#quick-start)
367
+
368
+ * [Command Line](#command-line)
369
+ * [Python API](#python-api)
370
+ * [Cross-Validation Methods](#cross-validation-methods)
371
+ * [Core Classes](#core-classes)
372
+
373
+ * [LinearRegressionModel](#linearregressionmodel)
374
+ * [ClassificationModel](#classificationmodel)
375
+ * [OrdinalLogisticRegression](#ordinallogisticregression)
376
+ * [Feature Selection Functions](#feature-selection-functions)
377
+ * [Utility Functions](#utility-functions)
378
+ * [Database Integration](#database-integration)
379
+ * [Similarity & Stratified Sampling](#similarity--stratified-sampling)
380
+ * [Reports & Visualizations](#reports--visualizations)
381
+ * [Recipes](#recipes)
382
+ * [Troubleshooting](#troubleshooting)
383
+ * [FAQ](#faq)
384
+ * [License](#license)
385
+
386
+ ---
387
+
388
+ ## Features
389
+
390
+ **Regression**
391
+
392
+ * Robust evaluation: R², Q², MAE, RMSD with repeated CV (K‑fold / LOO / repeated holdout).
393
+ * Exhaustive feature subset search (bounded by `min_features`/`max_features`).
394
+ * Prediction intervals and coefficient statistics.
395
+ * Multicollinearity checks (VIF) + diagnostics.
396
+ * Resilient to missing and non‑numeric features (coercion + safe dropping).
397
+
398
+ **Classification**
399
+
400
+ * Metrics: Accuracy, F1, McFadden’s R².
401
+ * Stratified K‑fold (class‑aware) CV; automatic adjustment for small datasets.
402
+ * Class balancing via stratified sampling & similarity‑based sampling.
403
+
404
+ **Common**
405
+
406
+ * Results persisted to SQLite for reproducibility and incremental runs.
407
+ * Compact PDF dashboards (coefficients, CV metrics, VIF, diagnostics; similarity plots before/after sampling).
408
+
409
+ ---
410
+
411
+
412
+ ## Data Expectations
413
+
414
+ You can work in **one‑CSV** or **two‑CSV** mode.
415
+
416
+ * **One CSV**: First column is a sample identifier (e.g., `Name`). Remaining columns contain numeric **features** and a single **target** column.
417
+ * **Two CSVs**: One file for features (rows = samples, columns = descriptors) and one for target/labels. Rows must align or include a join key.
418
+
419
+ **Tidy tips**
420
+
421
+ * Non‑numeric feature columns are coerced when possible; all‑NaN or constant columns are dropped.
422
+ * If you plan to use `--leave-out`, ensure the identifier column exists and matches your samples.
423
+
424
+ ---
425
+
426
+ ## Quick Start
427
+
428
+ ### Command Line
429
+
430
+ ```bash
431
+ python __main__.py model\
432
+ --mode {regression|classification} \
433
+ --features_csv path/to/features.csv \
434
+ --target_csv path/to/targets.csv \
435
+ --y_value EXPERIMENT_TAG \
436
+ --n_jobs -1 \
437
+ --min-features 1 \
438
+ --max-features 5 \
439
+ --top-n 20 \
440
+ --bool-parallel \
441
+ --threshold 0.5 \
442
+ --leave-out SAMPLE_A SAMPLE_B
443
+ ```
444
+
445
+ **Arguments**
446
+
447
+ | Flag | Type / Choices | Required | Description |
448
+ | ---------------------- | -------------------------------- | -------: | -------------------------------------------------------------------------------------- |
449
+ | `-h`, `--help` | — | No | Show help and exit. |
450
+ | `-m`, `--mode` | `regression` \| `classification` | **Yes** | Task to run; affects metrics and thresholds. |
451
+ | `-f`, `--features_csv` | path | **Yes** | Path to CSV with input features (descriptors). |
452
+ | `-t`, `--target_csv` | path | **Yes** | Path to CSV with targets/labels. |
453
+ | `-y`, `--y_value` | str | **Yes** | Tag/slug used to name outputs (plots, DB). |
454
+ | `-j`, `--n_jobs` | int | No | CPU cores. `-1` = all. Defaults to `$NSLOTS` or all cores. |
455
+ | `--min-features` | int | No | Minimum features per model. |
456
+ | `--max-features` | int | No | Maximum features per model. |
457
+ | `--top-n` | int | No | Number of top models to keep/evaluate. |
458
+ | `--bool-parallel` | flag | No | Enable parallel evaluation (honors `--n_jobs`). |
459
+ | `--threshold` | float | No | Initial quality cutoff. **Regression**: min R². **Classification**: min McFadden’s R². |
460
+ | `--leave-out` | list\[str] | No | Space‑separated sample IDs to exclude from fitting/evaluation. |
461
+
462
+ **Examples**
463
+
464
+ Regression
465
+
466
+ ```bash
467
+ python __main__.py.py \
468
+ --mode regression \
469
+ --features_csv data/x_features.csv \
470
+ --target_csv data/y_targets.csv \
471
+ --y_value yield \
472
+ --min-features 1 --max-features 3 \
473
+ --top-n 10 \
474
+ --threshold 0.6
475
+ ```
476
+
477
+ Classification
478
+
479
+ ```bash
480
+ python __main__.py model \
481
+ --mode classification \
482
+ --features_csv data/x_features.csv \
483
+ --target_csv data/classes.csv \
484
+ --y_value enantio_select \
485
+ --min-features 1 --max-features 4 \
486
+ --top-n 20 \
487
+ --threshold 0.5 \
488
+ --bool-parallel --n_jobs -1 \
489
+ --leave-out LS1714 LS2008
490
+ ```
491
+
492
+ ### Python API
493
+
494
+ Regression
495
+
496
+ ```python
497
+ from M3_modeler.modeling import LinearRegressionModel
498
+
499
+ csvs = {
500
+ "features_csv_filepath": "data/Train.csv",
501
+ "target_csv_filepath": "" # leave empty in one‑CSV mode
502
+ }
503
+ model = LinearRegressionModel(csvs, process_method="one csv", y_value="pIC50",
504
+ min_features_num=1, max_features_num=3)
505
+
506
+ model.search_models(top_n=10, threshold=0.6, bool_parallel=True)
507
+ # Predict on left‑out set (after leave_out_samples(...))
508
+ pred, intervals = model.predict_for_leftout(return_interval=True)
509
+ ```
510
+
511
+ Classification
512
+
513
+ ```python
514
+ from M3_modeler.modeling import ClassificationModel
515
+
516
+ csvs = {
517
+ "features_csv_filepath": "data/Train.csv",
518
+ "target_csv_filepath": ""
519
+ }
520
+ clf = ClassificationModel(csvs, process_method="one csv", output_name="class",
521
+ min_features_num=1, max_features_num=4)
522
+
523
+ # Optionally downsample class 1 by similarity (drop indices from class=1)
524
+ drop_pos = clf.simi_sampler_(class_label=1, compare_with=0, plot=True, sample_size=40)
525
+
526
+ clf.search_models(top_n=20, mcfadden_threshold=0.5)
527
+ ```
528
+
529
+ ---
530
+
531
+ ## Cross-Validation Methods
532
+
533
+ This project provides several cross-validation (CV) strategies designed for honest estimates of generalization performance and to prevent data leakage. All preprocessing that can leak signal (e.g., standardization) is fit only on the training fold and applied to the validation fold.
534
+
535
+ ### Shared Principles
536
+
537
+ * No leakage: scaling/transformations are fit on the train split of each fold, then applied to the validation split.
538
+ * Out-of-fold (OOF) predictions: for each sample, we collect predictions from the fold where that sample was in validation. These OOF predictions are used to compute global metrics (e.g., Q²).
539
+ * Aggregation: per-fold metrics are summarized (mean/median and optionally stdev). Global metrics like Q² are computed from OOF predictions.
540
+ * Small datasets: when the dataset is very small, the workflow can fall back to Leave-One-Out CV (LOOCV) automatically.
541
+ * Left-out set vs CV: any explicit left-out samples you provide are held out entirely and not used in CV. They can be evaluated later with `predict_for_leftout`.
542
+
543
+ ### Regression CV
544
+
545
+ * **K-Fold CV**
546
+ Split the data into K folds; iterate K times, each time training on K−1 folds and validating on the remaining fold. Collect OOF predictions to compute:
547
+
548
+ * **Q²** = 1 − SSE\_OOF / SST, where SSE\_OOF = sum((y − yhat\_OOF)^2) over all samples and SST = sum((y − mean(y))^2).
549
+ * **R², MAE, RMSD**: reported per fold and summarized across folds.
550
+
551
+ * **Leave-One-Out CV (LOOCV)**
552
+ A special case of K-Fold with K = N (one sample per validation split). Provides low-bias estimates for tiny datasets but is computationally heavier.
553
+
554
+ * **Repeated Holdout / Shuffle-Split (optional)**
555
+ Multiple random train/validation splits (e.g., 80/20) can be run and aggregated. Useful for stress-testing stability when K-Fold may be brittle on small N.
556
+
557
+ ### Classification CV
558
+
559
+ * **Stratified K-Fold CV**
560
+ Preserves class proportions in each fold. Useful for imbalanced datasets and multi-class problems. Metrics collected per fold include:
561
+
562
+ * Accuracy and F1 (macro or weighted depending on configuration),
563
+ * McFadden’s R² (pseudo-R² derived from per-fold log-likelihoods),
564
+ which are then summarized across folds.
565
+
566
+ * **Edge cases / small classes**
567
+ The number of folds may be reduced automatically to avoid empty class folds. When extremely small, LOOCV-like behavior is used.
568
+
569
+ > Tip: For reproducibility, set a fixed random seed where applicable. For highly imbalanced data, consider pairing Stratified K-Fold with the built-in similarity-based sampling or stratified sampling utilities before CV.
570
+
571
+ ## Core Classes
572
+
573
+ ### `LinearRegressionModel`
574
+
575
+ * Calculates **R², Q², MAE, RMSD** with robust cross‑validation (LOO / K‑fold / repeated holdout).
576
+ * Exhaustive **feature subset search** (bounded by `min_features_num`/`max_features_num`).
577
+ * **Prediction intervals** and coefficient statistics for interpretability.
578
+ * **Multicollinearity** detection via VIF; diagnostics and (optional) pruning.
579
+ * Robust to missing values and non‑numeric columns.
580
+ * Proper scaling performed **inside each fold** to avoid leakage.
581
+
582
+ ### `ClassificationModel`
583
+
584
+ * Metrics: **Accuracy, F1, McFadden’s R²** (per‑fold; aggregated).
585
+ * **Stratified K‑fold** with class‑aware fold generation; automatic adjustments for small classes.
586
+ * **Class balancing** via:
587
+
588
+ * Stratified sampling (preserve class ratios).
589
+ * **Similarity‑based sampling** to obtain a diverse subset within a class.
590
+
591
+ ### `OrdinalLogisticRegression`
592
+
593
+ A scikit‑learn‑style wrapper around `statsmodels`’ `OrderedModel` that supports:
594
+
595
+ * `fit`, `predict`, and `predict_proba` APIs.
596
+ * Different link functions (logit, probit, etc.).
597
+ * Ordered categorical targets.
598
+
599
+ ---
600
+
601
+ ## Feature Selection Functions
602
+
603
+ * `fit_and_evaluate_single_combination_regression(X, y, features, ...)`
604
+
605
+ > Evaluate one feature combination for regression; returns metrics, coefficients, and diagnostics.
606
+
607
+ * `fit_and_evaluate_single_combination_classification(X, y, features, ...)`
608
+
609
+ > Evaluate one feature combination for classification; returns metrics (Accuracy, F1, McFadden’s R²), confusion matrix, etc.
610
+
611
+ * `search_models(top_n, threshold, ...)` (method on both classes)
612
+
613
+ > Exhaustive search over feature combinations with caching, pruning via threshold, and optional parallelism.
614
+
615
+ ---
616
+
617
+ ## Utility Functions
618
+
619
+ * `check_linear_regression_assumptions(X, y)`
620
+
621
+ > Statistical tests: Durbin–Watson, Breusch–Pagan, Shapiro–Wilk, plus Q–Q plots.
622
+
623
+ * `_sort_results(results_df)`
624
+
625
+ > Sorts model results by performance (Q², then R² for regression; McFadden’s R² for classification).
626
+
627
+ * `_compute_vif(X)`
628
+
629
+ > Variance Inflation Factor to flag multicollinearity.
630
+
631
+ ---
632
+
633
+ ## Database Integration
634
+
635
+ * `insert_result_into_db_regression(model_info, metrics, ...)`
636
+ * `insert_result_into_db_classification(model_info, metrics, ...)`
637
+ * `load_results_from_db(db_path, table)`
638
+
639
+ > Results are persisted to a SQLite DB per dataset, enabling incremental runs and reproducible top‑N selection.
640
+
641
+ ---
642
+
643
+ ## Similarity & Stratified Sampling
644
+
645
+ * `simi_sampler(data, class_label, compare_with=0, sample_size=K, return_kind="pos")`
646
+
647
+ > Compute cosine‑like similarity on scaled features; **keep K** evenly spaced over the similarity range within `class_label` and **drop the rest**. Returns indices to **drop** (or names/labels if requested).
648
+
649
+ * `ClassificationModel.simi_sampler_(class_label, compare_with=0, plot=True, sample_size=None)`
650
+
651
+ > Convenience wrapper that runs the sampler and **applies the drop** (only within the target class). Plots “before vs after” with dropped points marked.
652
+
653
+ * `stratified_sampling_with_plots(data, plot, sample_size)`
654
+
655
+ > Create a balanced dataset with optional class distribution plots.
656
+
657
+ **Tip:** Ensure the sampler uses/reset index (`reset_index(drop=True)`) so positional indices align with your working `X`/`y`.
658
+
659
+ ---
660
+
661
+ ## Reports & Visualizations
662
+
663
+ Each top model can generate a compact PDF “summary dashboard” including:
664
+
665
+ * Coefficients table (with signs and magnitudes),
666
+ * VIF table and multicollinearity warnings,
667
+ * Cross‑validation metrics table (per fold and aggregated),
668
+ * For classification: confusion matrix/ROC/PR as configured,
669
+ * For sampling: similarity scatter **before vs after** (dropped points highlighted).
670
+
671
+ > The table renderer (`_safe_table`) auto‑wraps and shrinks to fit, preferring readability and preventing unreadably tiny text.
672
+
673
+ ---
674
+
675
+ ## Recipes
676
+
677
+ **Balance a specific class by similarity, then search**
678
+
679
+ ```python
680
+ clf = ClassificationModel(csvs, process_method="one csv", output_name="class",
681
+ min_features_num=1, max_features_num=4)
682
+ # Drop within class=1, keep 10 most representative across similarity
683
+ clf.simi_sampler_(class_label=1, compare_with=0, sample_size=10, plot=True)
684
+ clf.search_models(top_n=30, mcfadden_threshold=0.5)
685
+ ```
686
+
687
+ **Hold out a list of samples by ID, train on the rest, then predict**
688
+
689
+ ```python
690
+ model.leave_out_samples(["Mol_0012", "Mol_0345"], keep_only=False)
691
+ model.search_models(top_n=10, threshold=0.65)
692
+ pred, intervals = model.predict_for_leftout(return_interval=True)
693
+ ```
694
+
695
+ ---
696
+
697
+ ## Troubleshooting
698
+
699
+ * **“dtype='numeric' is not compatible with arrays of bytes/strings”**
700
+ Your routine expects numeric arrays but received strings (e.g., class labels). Coerce features/targets with `pd.to_numeric(..., errors='coerce')` (regression) or skip numeric plots in classification.
701
+
702
+ * **SHAP error with KernelExplainer**
703
+ Pass a **DataFrame** with real column names to SHAP; ensure `X` is numeric (coerce and drop NaNs) and call with `X` (not just a list of feature names).
704
+
705
+ * **Similarity sampler dropped nothing**
706
+ If `sample_size >= #rows in class_label`, nothing is dropped. Reduce `sample_size`. Also ensure `class_label` dtype matches (`1` vs `'1'`).
707
+
708
+ * **Tables in PDF are tiny**
709
+ Use the updated `_safe_table` (targets nearly full axes width; enlarges figure before shrinking text). Give the table a generous subplot or reduce `max_rows`/`max_cols`.
710
+
711
+ ---
712
+
713
+ ## FAQ
714
+
715
+ **Q: Does `simi_sampler` remove from the compared class or the target class?**
716
+ A: It removes **from `class_label`** only. `compare_with` chooses the similarity axis (self‑similarity when 0).
717
+
718
+ **Q: What does `sample_size` mean in `simi_sampler`?**
719
+ A: The number of samples to **keep** within `class_label`, evenly spread across the similarity range; the rest are dropped.
720
+
721
+ **Q: How do I apply drops only inside one class?**
722
+ A: Build a mask: keep all rows from other classes, then either keep or drop the selected positions inside `class_label` only.
723
+