dragon-ml-toolbox 19.14.0__py3-none-any.whl → 20.0.0__py3-none-any.whl

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 (219) hide show
  1. {dragon_ml_toolbox-19.14.0.dist-info → dragon_ml_toolbox-20.0.0.dist-info}/METADATA +29 -46
  2. dragon_ml_toolbox-20.0.0.dist-info/RECORD +178 -0
  3. ml_tools/{ETL_cleaning.py → ETL_cleaning/__init__.py} +13 -5
  4. ml_tools/ETL_cleaning/_basic_clean.py +351 -0
  5. ml_tools/ETL_cleaning/_clean_tools.py +128 -0
  6. ml_tools/ETL_cleaning/_dragon_cleaner.py +245 -0
  7. ml_tools/ETL_cleaning/_imprimir.py +13 -0
  8. ml_tools/{ETL_engineering.py → ETL_engineering/__init__.py} +8 -4
  9. ml_tools/ETL_engineering/_dragon_engineering.py +261 -0
  10. ml_tools/ETL_engineering/_imprimir.py +24 -0
  11. ml_tools/{_core/_ETL_engineering.py → ETL_engineering/_transforms.py} +14 -267
  12. ml_tools/{_core → GUI_tools}/_GUI_tools.py +37 -40
  13. ml_tools/{GUI_tools.py → GUI_tools/__init__.py} +7 -5
  14. ml_tools/GUI_tools/_imprimir.py +12 -0
  15. ml_tools/IO_tools/_IO_loggers.py +235 -0
  16. ml_tools/IO_tools/_IO_save_load.py +151 -0
  17. ml_tools/IO_tools/_IO_utils.py +140 -0
  18. ml_tools/{IO_tools.py → IO_tools/__init__.py} +13 -5
  19. ml_tools/IO_tools/_imprimir.py +14 -0
  20. ml_tools/MICE/_MICE_imputation.py +132 -0
  21. ml_tools/{MICE_imputation.py → MICE/__init__.py} +6 -7
  22. ml_tools/{_core/_MICE_imputation.py → MICE/_dragon_mice.py} +243 -322
  23. ml_tools/MICE/_imprimir.py +11 -0
  24. ml_tools/{ML_callbacks.py → ML_callbacks/__init__.py} +12 -4
  25. ml_tools/ML_callbacks/_base.py +101 -0
  26. ml_tools/ML_callbacks/_checkpoint.py +232 -0
  27. ml_tools/ML_callbacks/_early_stop.py +208 -0
  28. ml_tools/ML_callbacks/_imprimir.py +12 -0
  29. ml_tools/ML_callbacks/_scheduler.py +197 -0
  30. ml_tools/{ML_chaining_utilities.py → ML_chain/__init__.py} +8 -3
  31. ml_tools/{_core/_ML_chaining_utilities.py → ML_chain/_chaining_tools.py} +5 -129
  32. ml_tools/ML_chain/_dragon_chain.py +140 -0
  33. ml_tools/ML_chain/_imprimir.py +11 -0
  34. ml_tools/ML_configuration/__init__.py +90 -0
  35. ml_tools/ML_configuration/_base_model_config.py +69 -0
  36. ml_tools/ML_configuration/_finalize.py +366 -0
  37. ml_tools/ML_configuration/_imprimir.py +47 -0
  38. ml_tools/ML_configuration/_metrics.py +593 -0
  39. ml_tools/ML_configuration/_models.py +206 -0
  40. ml_tools/ML_configuration/_training.py +124 -0
  41. ml_tools/ML_datasetmaster/__init__.py +28 -0
  42. ml_tools/ML_datasetmaster/_base_datasetmaster.py +337 -0
  43. ml_tools/{_core/_ML_datasetmaster.py → ML_datasetmaster/_datasetmaster.py} +9 -329
  44. ml_tools/ML_datasetmaster/_imprimir.py +15 -0
  45. ml_tools/{_core/_ML_sequence_datasetmaster.py → ML_datasetmaster/_sequence_datasetmaster.py} +13 -15
  46. ml_tools/{_core/_ML_vision_datasetmaster.py → ML_datasetmaster/_vision_datasetmaster.py} +63 -65
  47. ml_tools/ML_evaluation/__init__.py +53 -0
  48. ml_tools/ML_evaluation/_classification.py +629 -0
  49. ml_tools/ML_evaluation/_feature_importance.py +409 -0
  50. ml_tools/ML_evaluation/_imprimir.py +25 -0
  51. ml_tools/ML_evaluation/_loss.py +92 -0
  52. ml_tools/ML_evaluation/_regression.py +273 -0
  53. ml_tools/{_core/_ML_sequence_evaluation.py → ML_evaluation/_sequence.py} +8 -11
  54. ml_tools/{_core/_ML_vision_evaluation.py → ML_evaluation/_vision.py} +12 -17
  55. ml_tools/{_core → ML_evaluation_captum}/_ML_evaluation_captum.py +11 -38
  56. ml_tools/{ML_evaluation_captum.py → ML_evaluation_captum/__init__.py} +6 -4
  57. ml_tools/ML_evaluation_captum/_imprimir.py +10 -0
  58. ml_tools/{_core → ML_finalize_handler}/_ML_finalize_handler.py +3 -7
  59. ml_tools/ML_finalize_handler/__init__.py +10 -0
  60. ml_tools/ML_finalize_handler/_imprimir.py +8 -0
  61. ml_tools/ML_inference/__init__.py +22 -0
  62. ml_tools/ML_inference/_base_inference.py +166 -0
  63. ml_tools/{_core/_ML_chaining_inference.py → ML_inference/_chain_inference.py} +14 -17
  64. ml_tools/ML_inference/_dragon_inference.py +332 -0
  65. ml_tools/ML_inference/_imprimir.py +11 -0
  66. ml_tools/ML_inference/_multi_inference.py +180 -0
  67. ml_tools/ML_inference_sequence/__init__.py +10 -0
  68. ml_tools/ML_inference_sequence/_imprimir.py +8 -0
  69. ml_tools/{_core/_ML_sequence_inference.py → ML_inference_sequence/_sequence_inference.py} +11 -15
  70. ml_tools/ML_inference_vision/__init__.py +10 -0
  71. ml_tools/ML_inference_vision/_imprimir.py +8 -0
  72. ml_tools/{_core/_ML_vision_inference.py → ML_inference_vision/_vision_inference.py} +15 -19
  73. ml_tools/ML_models/__init__.py +32 -0
  74. ml_tools/{_core/_ML_models_advanced.py → ML_models/_advanced_models.py} +22 -18
  75. ml_tools/ML_models/_base_mlp_attention.py +198 -0
  76. ml_tools/{_core/_models_advanced_base.py → ML_models/_base_save_load.py} +73 -49
  77. ml_tools/ML_models/_dragon_tabular.py +248 -0
  78. ml_tools/ML_models/_imprimir.py +18 -0
  79. ml_tools/ML_models/_mlp_attention.py +134 -0
  80. ml_tools/{_core → ML_models}/_models_advanced_helpers.py +13 -13
  81. ml_tools/ML_models_sequence/__init__.py +10 -0
  82. ml_tools/ML_models_sequence/_imprimir.py +8 -0
  83. ml_tools/{_core/_ML_sequence_models.py → ML_models_sequence/_sequence_models.py} +5 -8
  84. ml_tools/ML_models_vision/__init__.py +29 -0
  85. ml_tools/ML_models_vision/_base_wrapper.py +254 -0
  86. ml_tools/ML_models_vision/_image_classification.py +182 -0
  87. ml_tools/ML_models_vision/_image_segmentation.py +108 -0
  88. ml_tools/ML_models_vision/_imprimir.py +16 -0
  89. ml_tools/ML_models_vision/_object_detection.py +135 -0
  90. ml_tools/ML_optimization/__init__.py +21 -0
  91. ml_tools/ML_optimization/_imprimir.py +13 -0
  92. ml_tools/{_core/_ML_optimization_pareto.py → ML_optimization/_multi_dragon.py} +18 -24
  93. ml_tools/ML_optimization/_single_dragon.py +203 -0
  94. ml_tools/{_core/_ML_optimization.py → ML_optimization/_single_manual.py} +75 -213
  95. ml_tools/{_core → ML_scaler}/_ML_scaler.py +8 -11
  96. ml_tools/ML_scaler/__init__.py +10 -0
  97. ml_tools/ML_scaler/_imprimir.py +8 -0
  98. ml_tools/ML_trainer/__init__.py +20 -0
  99. ml_tools/ML_trainer/_base_trainer.py +297 -0
  100. ml_tools/ML_trainer/_dragon_detection_trainer.py +402 -0
  101. ml_tools/ML_trainer/_dragon_sequence_trainer.py +540 -0
  102. ml_tools/ML_trainer/_dragon_trainer.py +1160 -0
  103. ml_tools/ML_trainer/_imprimir.py +10 -0
  104. ml_tools/{ML_utilities.py → ML_utilities/__init__.py} +14 -6
  105. ml_tools/ML_utilities/_artifact_finder.py +382 -0
  106. ml_tools/ML_utilities/_imprimir.py +16 -0
  107. ml_tools/ML_utilities/_inspection.py +325 -0
  108. ml_tools/ML_utilities/_train_tools.py +205 -0
  109. ml_tools/{ML_vision_transformers.py → ML_vision_transformers/__init__.py} +9 -6
  110. ml_tools/{_core/_ML_vision_transformers.py → ML_vision_transformers/_core_transforms.py} +11 -155
  111. ml_tools/ML_vision_transformers/_imprimir.py +14 -0
  112. ml_tools/ML_vision_transformers/_offline_augmentation.py +159 -0
  113. ml_tools/{_core/_PSO_optimization.py → PSO_optimization/_PSO.py} +58 -15
  114. ml_tools/{PSO_optimization.py → PSO_optimization/__init__.py} +5 -3
  115. ml_tools/PSO_optimization/_imprimir.py +10 -0
  116. ml_tools/SQL/__init__.py +7 -0
  117. ml_tools/{_core/_SQL.py → SQL/_dragon_SQL.py} +7 -11
  118. ml_tools/SQL/_imprimir.py +8 -0
  119. ml_tools/{_core → VIF}/_VIF_factor.py +5 -8
  120. ml_tools/{VIF_factor.py → VIF/__init__.py} +4 -2
  121. ml_tools/VIF/_imprimir.py +10 -0
  122. ml_tools/_core/__init__.py +7 -1
  123. ml_tools/_core/_logger.py +8 -18
  124. ml_tools/_core/_schema_load_ops.py +43 -0
  125. ml_tools/_core/_script_info.py +2 -2
  126. ml_tools/{data_exploration.py → data_exploration/__init__.py} +32 -16
  127. ml_tools/data_exploration/_analysis.py +214 -0
  128. ml_tools/data_exploration/_cleaning.py +566 -0
  129. ml_tools/data_exploration/_features.py +583 -0
  130. ml_tools/data_exploration/_imprimir.py +32 -0
  131. ml_tools/data_exploration/_plotting.py +487 -0
  132. ml_tools/data_exploration/_schema_ops.py +176 -0
  133. ml_tools/{ensemble_evaluation.py → ensemble_evaluation/__init__.py} +6 -4
  134. ml_tools/{_core → ensemble_evaluation}/_ensemble_evaluation.py +3 -7
  135. ml_tools/ensemble_evaluation/_imprimir.py +14 -0
  136. ml_tools/{ensemble_inference.py → ensemble_inference/__init__.py} +5 -3
  137. ml_tools/{_core → ensemble_inference}/_ensemble_inference.py +15 -18
  138. ml_tools/ensemble_inference/_imprimir.py +9 -0
  139. ml_tools/{ensemble_learning.py → ensemble_learning/__init__.py} +4 -6
  140. ml_tools/{_core → ensemble_learning}/_ensemble_learning.py +7 -10
  141. ml_tools/ensemble_learning/_imprimir.py +10 -0
  142. ml_tools/{excel_handler.py → excel_handler/__init__.py} +5 -3
  143. ml_tools/{_core → excel_handler}/_excel_handler.py +6 -10
  144. ml_tools/excel_handler/_imprimir.py +13 -0
  145. ml_tools/{keys.py → keys/__init__.py} +4 -1
  146. ml_tools/keys/_imprimir.py +11 -0
  147. ml_tools/{_core → keys}/_keys.py +2 -0
  148. ml_tools/{math_utilities.py → math_utilities/__init__.py} +5 -2
  149. ml_tools/math_utilities/_imprimir.py +11 -0
  150. ml_tools/{_core → math_utilities}/_math_utilities.py +1 -5
  151. ml_tools/{optimization_tools.py → optimization_tools/__init__.py} +9 -4
  152. ml_tools/optimization_tools/_imprimir.py +13 -0
  153. ml_tools/optimization_tools/_optimization_bounds.py +236 -0
  154. ml_tools/optimization_tools/_optimization_plots.py +218 -0
  155. ml_tools/{path_manager.py → path_manager/__init__.py} +6 -3
  156. ml_tools/{_core/_path_manager.py → path_manager/_dragonmanager.py} +11 -347
  157. ml_tools/path_manager/_imprimir.py +15 -0
  158. ml_tools/path_manager/_path_tools.py +346 -0
  159. ml_tools/plot_fonts/__init__.py +8 -0
  160. ml_tools/plot_fonts/_imprimir.py +8 -0
  161. ml_tools/{_core → plot_fonts}/_plot_fonts.py +2 -5
  162. ml_tools/schema/__init__.py +15 -0
  163. ml_tools/schema/_feature_schema.py +223 -0
  164. ml_tools/schema/_gui_schema.py +191 -0
  165. ml_tools/schema/_imprimir.py +10 -0
  166. ml_tools/{serde.py → serde/__init__.py} +4 -2
  167. ml_tools/serde/_imprimir.py +10 -0
  168. ml_tools/{_core → serde}/_serde.py +3 -8
  169. ml_tools/{utilities.py → utilities/__init__.py} +11 -6
  170. ml_tools/utilities/_imprimir.py +18 -0
  171. ml_tools/{_core/_utilities.py → utilities/_utility_save_load.py} +13 -190
  172. ml_tools/utilities/_utility_tools.py +192 -0
  173. dragon_ml_toolbox-19.14.0.dist-info/RECORD +0 -111
  174. ml_tools/ML_chaining_inference.py +0 -8
  175. ml_tools/ML_configuration.py +0 -86
  176. ml_tools/ML_configuration_pytab.py +0 -14
  177. ml_tools/ML_datasetmaster.py +0 -10
  178. ml_tools/ML_evaluation.py +0 -16
  179. ml_tools/ML_evaluation_multi.py +0 -12
  180. ml_tools/ML_finalize_handler.py +0 -8
  181. ml_tools/ML_inference.py +0 -12
  182. ml_tools/ML_models.py +0 -14
  183. ml_tools/ML_models_advanced.py +0 -14
  184. ml_tools/ML_models_pytab.py +0 -14
  185. ml_tools/ML_optimization.py +0 -14
  186. ml_tools/ML_optimization_pareto.py +0 -8
  187. ml_tools/ML_scaler.py +0 -8
  188. ml_tools/ML_sequence_datasetmaster.py +0 -8
  189. ml_tools/ML_sequence_evaluation.py +0 -10
  190. ml_tools/ML_sequence_inference.py +0 -8
  191. ml_tools/ML_sequence_models.py +0 -8
  192. ml_tools/ML_trainer.py +0 -12
  193. ml_tools/ML_vision_datasetmaster.py +0 -12
  194. ml_tools/ML_vision_evaluation.py +0 -10
  195. ml_tools/ML_vision_inference.py +0 -8
  196. ml_tools/ML_vision_models.py +0 -18
  197. ml_tools/SQL.py +0 -8
  198. ml_tools/_core/_ETL_cleaning.py +0 -694
  199. ml_tools/_core/_IO_tools.py +0 -498
  200. ml_tools/_core/_ML_callbacks.py +0 -702
  201. ml_tools/_core/_ML_configuration.py +0 -1332
  202. ml_tools/_core/_ML_configuration_pytab.py +0 -102
  203. ml_tools/_core/_ML_evaluation.py +0 -867
  204. ml_tools/_core/_ML_evaluation_multi.py +0 -544
  205. ml_tools/_core/_ML_inference.py +0 -646
  206. ml_tools/_core/_ML_models.py +0 -668
  207. ml_tools/_core/_ML_models_pytab.py +0 -693
  208. ml_tools/_core/_ML_trainer.py +0 -2323
  209. ml_tools/_core/_ML_utilities.py +0 -886
  210. ml_tools/_core/_ML_vision_models.py +0 -644
  211. ml_tools/_core/_data_exploration.py +0 -1909
  212. ml_tools/_core/_optimization_tools.py +0 -493
  213. ml_tools/_core/_schema.py +0 -359
  214. ml_tools/plot_fonts.py +0 -8
  215. ml_tools/schema.py +0 -12
  216. {dragon_ml_toolbox-19.14.0.dist-info → dragon_ml_toolbox-20.0.0.dist-info}/WHEEL +0 -0
  217. {dragon_ml_toolbox-19.14.0.dist-info → dragon_ml_toolbox-20.0.0.dist-info}/licenses/LICENSE +0 -0
  218. {dragon_ml_toolbox-19.14.0.dist-info → dragon_ml_toolbox-20.0.0.dist-info}/licenses/LICENSE-THIRD-PARTY.md +0 -0
  219. {dragon_ml_toolbox-19.14.0.dist-info → dragon_ml_toolbox-20.0.0.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,13 @@
1
- from typing import Union, Dict, Type, Callable, Optional, Any, List, Literal, Tuple
1
+ from typing import Union, Type, Callable, Any
2
2
  from PIL import ImageOps, Image
3
3
  from torchvision import transforms
4
4
  from pathlib import Path
5
5
  import json
6
6
  import random
7
7
 
8
- from ._logger import get_logger
9
- from ._script_info import _script_info
10
- from ._keys import VisionTransformRecipeKeys
11
- from ._path_manager import make_fullpath
8
+ from .._core import get_logger
9
+ from ..keys._keys import VisionTransformRecipeKeys
10
+ from ..path_manager import make_fullpath
12
11
 
13
12
 
14
13
  _LOGGER = get_logger("Transformers")
@@ -20,7 +19,8 @@ __all__ = [
20
19
  "LetterboxResize",
21
20
  "HistogramEqualization",
22
21
  "RandomHistogramEqualization",
23
- "create_offline_augmentations"
22
+ "_save_recipe",
23
+ "_load_recipe_and_build_transform",
24
24
  ]
25
25
 
26
26
  # --- Custom Vision Transform Class ---
@@ -82,7 +82,7 @@ class LetterboxResize:
82
82
  """
83
83
  def __init__(
84
84
  self,
85
- target_size: Union[int, Tuple[int, int]],
85
+ target_size: Union[int, tuple[int, int]],
86
86
  pad_color: Union[str, int] = "black"
87
87
  ) -> None:
88
88
 
@@ -189,7 +189,7 @@ class RandomHistogramEqualization:
189
189
 
190
190
  #############################################################
191
191
  #NOTE: Add custom transforms.
192
- TRANSFORM_REGISTRY: Dict[str, Type[Callable]] = {
192
+ TRANSFORM_REGISTRY: dict[str, Type[Callable]] = {
193
193
  "ResizeAspectFill": ResizeAspectFill,
194
194
  "LetterboxResize": LetterboxResize,
195
195
  "HistogramEqualization": HistogramEqualization,
@@ -198,153 +198,12 @@ TRANSFORM_REGISTRY: Dict[str, Type[Callable]] = {
198
198
  #############################################################
199
199
 
200
200
 
201
- def create_offline_augmentations(
202
- input_directory: Union[str, Path],
203
- output_directory: Union[str, Path],
204
- results_per_image: int,
205
- recipe: Optional[Dict[str, Any]] = None,
206
- save_format: Literal["WEBP", "JPEG", "PNG", "BMP", "TIF"] = "WEBP",
207
- save_quality: int = 80
208
- ) -> None:
209
- """
210
- Reads all valid images from an input directory, applies augmentations,
211
- and saves the new images to an output directory (offline augmentation).
212
-
213
- Skips subdirectories in the input path.
214
-
215
- Args:
216
- input_directory (Union[str, Path]): Path to the directory of source images.
217
- output_directory (Union[str, Path]): Path to save the augmented images.
218
- results_per_image (int): The number of augmented versions to create
219
- for each source image.
220
- recipe (Optional[Dict[str, Any]]): A transform recipe dictionary. If None,
221
- a default set of strong, random
222
- augmentations will be used.
223
- save_format (str): The format to save images (e.g., "WEBP", "JPEG", "PNG").
224
- Defaults to "WEBP" for good compression.
225
- save_quality (int): The quality for lossy formats (1-100). Defaults to 80.
226
- """
227
- VALID_IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.bmp', '.webp', '.tif', '.tiff')
228
-
229
- # --- 1. Validate Paths ---
230
- in_path = make_fullpath(input_directory, enforce="directory")
231
- out_path = make_fullpath(output_directory, make=True, enforce="directory")
232
-
233
- _LOGGER.info(f"Starting offline augmentation:\n\tInput: {in_path}\n\tOutput: {out_path}")
234
-
235
- # --- 2. Find Images ---
236
- image_files = [
237
- f for f in in_path.iterdir()
238
- if f.is_file() and f.suffix.lower() in VALID_IMG_EXTENSIONS
239
- ]
240
-
241
- if not image_files:
242
- _LOGGER.warning(f"No valid image files found in {in_path}.")
243
- return
244
-
245
- _LOGGER.info(f"Found {len(image_files)} images to process.")
246
-
247
- # --- 3. Define Transform Pipeline ---
248
- transform_pipeline: transforms.Compose
249
-
250
- if recipe:
251
- _LOGGER.info("Building transformations from provided recipe.")
252
- try:
253
- transform_pipeline = _build_transform_from_recipe(recipe)
254
- except Exception as e:
255
- _LOGGER.error(f"Failed to build transform from recipe: {e}")
256
- return
257
- else:
258
- _LOGGER.info("No recipe provided. Using default random augmentation pipeline.")
259
- # Default "random" pipeline
260
- transform_pipeline = transforms.Compose([
261
- transforms.RandomResizedCrop(256, scale=(0.4, 1.0)),
262
- transforms.RandomHorizontalFlip(p=0.5),
263
- transforms.RandomRotation(degrees=90),
264
- transforms.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3, hue=0.15),
265
- transforms.RandomPerspective(distortion_scale=0.2, p=0.4),
266
- transforms.RandomAffine(degrees=0, translate=(0.1, 0.1)),
267
- transforms.RandomApply([
268
- transforms.GaussianBlur(kernel_size=3)
269
- ], p=0.3)
270
- ])
271
-
272
- # --- 4. Process Images ---
273
- total_saved = 0
274
- format_upper = save_format.upper()
275
-
276
- for img_path in image_files:
277
- _LOGGER.debug(f"Processing {img_path.name}...")
278
- try:
279
- original_image = Image.open(img_path).convert("RGB")
280
-
281
- for i in range(results_per_image):
282
- new_stem = f"{img_path.stem}_aug_{i+1:03d}"
283
- output_path = out_path / f"{new_stem}.{format_upper.lower()}"
284
-
285
- # Apply transform
286
- transformed_image = transform_pipeline(original_image)
287
-
288
- # Save
289
- transformed_image.save(
290
- output_path,
291
- format=format_upper,
292
- quality=save_quality,
293
- optimize=True # Add optimize flag
294
- )
295
- total_saved += 1
296
-
297
- except Exception as e:
298
- _LOGGER.warning(f"Failed to process or save augmentations for {img_path.name}: {e}")
299
-
300
- _LOGGER.info(f"Offline augmentation complete. Saved {total_saved} new images.")
301
-
302
-
303
- def _build_transform_from_recipe(recipe: Dict[str, Any]) -> transforms.Compose:
304
- """Internal helper to build a transform pipeline from a recipe dict."""
305
- pipeline_steps: List[Callable] = []
306
-
307
- if VisionTransformRecipeKeys.PIPELINE not in recipe:
308
- _LOGGER.error("Recipe dict is invalid: missing 'pipeline' key.")
309
- raise ValueError("Invalid recipe format.")
310
-
311
- for step in recipe[VisionTransformRecipeKeys.PIPELINE]:
312
- t_name = step.get(VisionTransformRecipeKeys.NAME)
313
- t_kwargs = step.get(VisionTransformRecipeKeys.KWARGS, {})
314
-
315
- if not t_name:
316
- _LOGGER.error(f"Invalid transform step, missing 'name': {step}")
317
- continue
318
-
319
- transform_class: Any = None
320
-
321
- # 1. Check standard torchvision transforms
322
- if hasattr(transforms, t_name):
323
- transform_class = getattr(transforms, t_name)
324
- # 2. Check custom transforms
325
- elif t_name in TRANSFORM_REGISTRY:
326
- transform_class = TRANSFORM_REGISTRY[t_name]
327
- # 3. Not found
328
- else:
329
- _LOGGER.error(f"Unknown transform '{t_name}' in recipe. Not found in torchvision.transforms or TRANSFORM_REGISTRY.")
330
- raise ValueError(f"Unknown transform name: {t_name}")
331
-
332
- # Instantiate the transform
333
- try:
334
- pipeline_steps.append(transform_class(**t_kwargs))
335
- except Exception as e:
336
- _LOGGER.error(f"Failed to instantiate transform '{t_name}' with kwargs {t_kwargs}: {e}")
337
- raise
338
-
339
- return transforms.Compose(pipeline_steps)
340
-
341
-
342
- def _save_recipe(recipe: Dict[str, Any], filepath: Path) -> None:
201
+ def _save_recipe(recipe: dict[str, Any], filepath: Path) -> None:
343
202
  """
344
203
  Saves a transform recipe dictionary to a JSON file.
345
204
 
346
205
  Args:
347
- recipe (Dict[str, Any]): The recipe dictionary to save.
206
+ recipe (dict[str, Any]): The recipe dictionary to save.
348
207
  filepath (str): The path to the output .json file.
349
208
  """
350
209
  final_filepath = filepath.with_suffix(".json")
@@ -383,7 +242,7 @@ def _load_recipe_and_build_transform(filepath: Union[str,Path]) -> transforms.Co
383
242
  _LOGGER.error(f"Failed to load recipe from '{final_filepath}': {e}")
384
243
  raise
385
244
 
386
- pipeline_steps: List[Callable] = []
245
+ pipeline_steps: list[Callable] = []
387
246
 
388
247
  if VisionTransformRecipeKeys.PIPELINE not in recipe:
389
248
  _LOGGER.error("Recipe file is invalid: missing 'pipeline' key.")
@@ -416,6 +275,3 @@ def _load_recipe_and_build_transform(filepath: Union[str,Path]) -> transforms.Co
416
275
  _LOGGER.info(f"Successfully loaded and built transform pipeline from '{final_filepath.name}'.")
417
276
  return transforms.Compose(pipeline_steps)
418
277
 
419
-
420
- def info():
421
- _script_info(__all__)
@@ -0,0 +1,14 @@
1
+ from .._core import _imprimir_disponibles
2
+
3
+ _GRUPOS = [
4
+ # Custom Transforms
5
+ "ResizeAspectFill",
6
+ "LetterboxResize",
7
+ "HistogramEqualization",
8
+ "RandomHistogramEqualization",
9
+ # Offline Augmentation
10
+ "create_offline_augmentations",
11
+ ]
12
+
13
+ def info():
14
+ _imprimir_disponibles(_GRUPOS)
@@ -0,0 +1,159 @@
1
+ from typing import Union, Callable, Optional, Any, Literal
2
+ from PIL import Image
3
+ from torchvision import transforms
4
+ from pathlib import Path
5
+
6
+ from .._core import get_logger
7
+ from ..keys._keys import VisionTransformRecipeKeys
8
+ from ..path_manager import make_fullpath
9
+
10
+ from ._core_transforms import TRANSFORM_REGISTRY
11
+
12
+
13
+ _LOGGER = get_logger("Offline Augmentation")
14
+
15
+
16
+ __all__ = [
17
+ "create_offline_augmentations"
18
+ ]
19
+
20
+ def create_offline_augmentations(
21
+ input_directory: Union[str, Path],
22
+ output_directory: Union[str, Path],
23
+ results_per_image: int,
24
+ recipe: Optional[dict[str, Any]] = None,
25
+ save_format: Literal["WEBP", "JPEG", "PNG", "BMP", "TIF"] = "WEBP",
26
+ save_quality: int = 80
27
+ ) -> None:
28
+ """
29
+ Reads all valid images from an input directory, applies augmentations,
30
+ and saves the new images to an output directory (offline augmentation).
31
+
32
+ Skips subdirectories in the input path.
33
+
34
+ Args:
35
+ input_directory (Union[str, Path]): Path to the directory of source images.
36
+ output_directory (Union[str, Path]): Path to save the augmented images.
37
+ results_per_image (int): The number of augmented versions to create
38
+ for each source image.
39
+ recipe (Optional[Dict[str, Any]]): A transform recipe dictionary. If None,
40
+ a default set of strong, random
41
+ augmentations will be used.
42
+ save_format (str): The format to save images (e.g., "WEBP", "JPEG", "PNG").
43
+ Defaults to "WEBP" for good compression.
44
+ save_quality (int): The quality for lossy formats (1-100). Defaults to 80.
45
+ """
46
+ VALID_IMG_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.bmp', '.webp', '.tif', '.tiff')
47
+
48
+ # --- 1. Validate Paths ---
49
+ in_path = make_fullpath(input_directory, enforce="directory")
50
+ out_path = make_fullpath(output_directory, make=True, enforce="directory")
51
+
52
+ _LOGGER.info(f"Starting offline augmentation:\n\tInput: {in_path}\n\tOutput: {out_path}")
53
+
54
+ # --- 2. Find Images ---
55
+ image_files = [
56
+ f for f in in_path.iterdir()
57
+ if f.is_file() and f.suffix.lower() in VALID_IMG_EXTENSIONS
58
+ ]
59
+
60
+ if not image_files:
61
+ _LOGGER.warning(f"No valid image files found in {in_path}.")
62
+ return
63
+
64
+ _LOGGER.info(f"Found {len(image_files)} images to process.")
65
+
66
+ # --- 3. Define Transform Pipeline ---
67
+ transform_pipeline: transforms.Compose
68
+
69
+ if recipe:
70
+ _LOGGER.info("Building transformations from provided recipe.")
71
+ try:
72
+ transform_pipeline = _build_transform_from_recipe(recipe)
73
+ except Exception as e:
74
+ _LOGGER.error(f"Failed to build transform from recipe: {e}")
75
+ return
76
+ else:
77
+ _LOGGER.info("No recipe provided. Using default random augmentation pipeline.")
78
+ # Default "random" pipeline
79
+ transform_pipeline = transforms.Compose([
80
+ transforms.RandomResizedCrop(256, scale=(0.4, 1.0)),
81
+ transforms.RandomHorizontalFlip(p=0.5),
82
+ transforms.RandomRotation(degrees=90),
83
+ transforms.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3, hue=0.15),
84
+ transforms.RandomPerspective(distortion_scale=0.2, p=0.4),
85
+ transforms.RandomAffine(degrees=0, translate=(0.1, 0.1)),
86
+ transforms.RandomApply([
87
+ transforms.GaussianBlur(kernel_size=3)
88
+ ], p=0.3)
89
+ ])
90
+
91
+ # --- 4. Process Images ---
92
+ total_saved = 0
93
+ format_upper = save_format.upper()
94
+
95
+ for img_path in image_files:
96
+ _LOGGER.debug(f"Processing {img_path.name}...")
97
+ try:
98
+ original_image = Image.open(img_path).convert("RGB")
99
+
100
+ for i in range(results_per_image):
101
+ new_stem = f"{img_path.stem}_aug_{i+1:03d}"
102
+ output_path = out_path / f"{new_stem}.{format_upper.lower()}"
103
+
104
+ # Apply transform
105
+ transformed_image = transform_pipeline(original_image)
106
+
107
+ # Save
108
+ transformed_image.save(
109
+ output_path,
110
+ format=format_upper,
111
+ quality=save_quality,
112
+ optimize=True # Add optimize flag
113
+ )
114
+ total_saved += 1
115
+
116
+ except Exception as e:
117
+ _LOGGER.warning(f"Failed to process or save augmentations for {img_path.name}: {e}")
118
+
119
+ _LOGGER.info(f"Offline augmentation complete. Saved {total_saved} new images.")
120
+
121
+
122
+ def _build_transform_from_recipe(recipe: dict[str, Any]) -> transforms.Compose:
123
+ """Internal helper to build a transform pipeline from a recipe dict."""
124
+ pipeline_steps: list[Callable] = []
125
+
126
+ if VisionTransformRecipeKeys.PIPELINE not in recipe:
127
+ _LOGGER.error("Recipe dict is invalid: missing 'pipeline' key.")
128
+ raise ValueError("Invalid recipe format.")
129
+
130
+ for step in recipe[VisionTransformRecipeKeys.PIPELINE]:
131
+ t_name = step.get(VisionTransformRecipeKeys.NAME)
132
+ t_kwargs = step.get(VisionTransformRecipeKeys.KWARGS, {})
133
+
134
+ if not t_name:
135
+ _LOGGER.error(f"Invalid transform step, missing 'name': {step}")
136
+ continue
137
+
138
+ transform_class: Any = None
139
+
140
+ # 1. Check standard torchvision transforms
141
+ if hasattr(transforms, t_name):
142
+ transform_class = getattr(transforms, t_name)
143
+ # 2. Check custom transforms
144
+ elif t_name in TRANSFORM_REGISTRY:
145
+ transform_class = TRANSFORM_REGISTRY[t_name]
146
+ # 3. Not found
147
+ else:
148
+ _LOGGER.error(f"Unknown transform '{t_name}' in recipe. Not found in torchvision.transforms or TRANSFORM_REGISTRY.")
149
+ raise ValueError(f"Unknown transform name: {t_name}")
150
+
151
+ # Instantiate the transform
152
+ try:
153
+ pipeline_steps.append(transform_class(**t_kwargs))
154
+ except Exception as e:
155
+ _LOGGER.error(f"Failed to instantiate transform '{t_name}' with kwargs {t_kwargs}: {e}")
156
+ raise
157
+
158
+ return transforms.Compose(pipeline_steps)
159
+
@@ -1,21 +1,21 @@
1
1
  import numpy as np
2
+ import pandas as pd
2
3
  from pathlib import Path
3
4
  import xgboost as xgb
4
5
  import lightgbm as lgb
5
- from typing import Literal, Union, Tuple, Dict, Optional
6
+ from typing import Literal, Union, Optional
6
7
  from copy import deepcopy
7
8
  import torch
8
9
  from tqdm import trange
9
10
  from contextlib import nullcontext
10
11
 
11
- from ._serde import deserialize_object
12
- from ._math_utilities import threshold_binary_values, threshold_binary_values_batch
13
- from ._path_manager import sanitize_filename, make_fullpath, list_files_by_extension
14
- from ._logger import get_logger
15
- from ._keys import EnsembleKeys
16
- from ._script_info import _script_info
17
- from ._SQL import DragonSQL
18
- from ._optimization_tools import _save_result
12
+ from ..serde import deserialize_object
13
+ from ..SQL import DragonSQL
14
+
15
+ from ..math_utilities import threshold_binary_values, threshold_binary_values_batch
16
+ from ..keys._keys import EnsembleKeys
17
+ from ..path_manager import sanitize_filename, make_fullpath, list_files_by_extension
18
+ from .._core import get_logger
19
19
 
20
20
 
21
21
  _LOGGER = get_logger("PSO")
@@ -247,7 +247,7 @@ def run_pso(lower_boundaries: list[float],
247
247
  swarm_size: int=200,
248
248
  max_iterations: int=3000,
249
249
  random_state: int=101,
250
- post_hoc_analysis: Optional[int]=20) -> Optional[Tuple[Dict[str, float], Dict[str, float]]]:
250
+ post_hoc_analysis: Optional[int]=20) -> Optional[tuple[dict[str, float], dict[str, float]]]:
251
251
  """
252
252
  Executes Particle Swarm Optimization (PSO) to optimize a given objective function and saves the results as a CSV file.
253
253
 
@@ -384,6 +384,54 @@ def run_pso(lower_boundaries: list[float],
384
384
  return None
385
385
 
386
386
 
387
+ def _save_result(
388
+ result_dict: dict,
389
+ save_format: Literal['csv', 'sqlite', 'both'],
390
+ csv_path: Path,
391
+ db_manager: Optional[DragonSQL] = None,
392
+ db_table_name: Optional[str] = None,
393
+ categorical_mappings: Optional[dict[str, dict[str, int]]] = None
394
+ ):
395
+ """
396
+ Private helper to handle saving a single result to CSV, SQLite, or both.
397
+
398
+ If `categorical_mappings` is provided, it will reverse-map integer values
399
+ to their string representations before saving.
400
+ """
401
+ # --- Reverse Mapping Logic ---
402
+ # Create a copy to hold the values to be saved
403
+ save_dict = result_dict.copy()
404
+
405
+ if categorical_mappings:
406
+ for feature_name, mapping in categorical_mappings.items():
407
+ if feature_name in save_dict:
408
+ # Create a reverse map {0: 'Category_A', 1: 'Category_B'}
409
+ reverse_map = {idx: name for name, idx in mapping.items()}
410
+
411
+ # Get the integer value from the results (e.g., 0)
412
+ int_value = save_dict[feature_name]
413
+
414
+ # Find the corresponding string (e.g., 'Category_A')
415
+ # Use .get() for safety, defaulting to the original value if not found
416
+ string_value = reverse_map.get(int_value, int_value)
417
+
418
+ # Update the dictionary that will be saved
419
+ save_dict[feature_name] = string_value
420
+
421
+ # Save to CSV
422
+ if save_format in ['csv', 'both']:
423
+ df_row = pd.DataFrame([save_dict])
424
+ file_exists = csv_path.exists()
425
+ df_row.to_csv(csv_path, mode='a', index=False, header=not file_exists)
426
+
427
+ # Save to SQLite
428
+ if save_format in ['sqlite', 'both']:
429
+ if db_manager and db_table_name:
430
+ db_manager.insert_row(db_table_name, save_dict)
431
+ else:
432
+ _LOGGER.warning("SQLite saving requested but db_manager or table_name not provided.")
433
+
434
+
387
435
  def _pso(func: ObjectiveFunction,
388
436
  lb: np.ndarray,
389
437
  ub: np.ndarray,
@@ -536,8 +584,3 @@ def _pso(func: ObjectiveFunction,
536
584
  else:
537
585
  return best_position, best_score
538
586
 
539
-
540
-
541
-
542
- def info():
543
- _script_info(__all__)
@@ -1,10 +1,12 @@
1
- from ._core._PSO_optimization import (
1
+ from ._PSO import (
2
2
  ObjectiveFunction,
3
3
  multiple_objective_functions_from_dir,
4
- run_pso,
5
- info
4
+ run_pso
6
5
  )
7
6
 
7
+ from ._imprimir import info
8
+
9
+
8
10
  __all__ = [
9
11
  "ObjectiveFunction",
10
12
  "multiple_objective_functions_from_dir",
@@ -0,0 +1,10 @@
1
+ from .._core import _imprimir_disponibles
2
+
3
+ _GRUPOS = [
4
+ "ObjectiveFunction",
5
+ "multiple_objective_functions_from_dir",
6
+ "run_pso"
7
+ ]
8
+
9
+ def info():
10
+ _imprimir_disponibles(_GRUPOS)
@@ -0,0 +1,7 @@
1
+ from ._dragon_SQL import DragonSQL
2
+
3
+ from ._imprimir import info
4
+
5
+ __all__ = [
6
+ "DragonSQL",
7
+ ]
@@ -1,11 +1,10 @@
1
1
  import sqlite3
2
2
  import pandas as pd
3
3
  from pathlib import Path
4
- from typing import Union, Dict, Any, Optional, List, Literal
4
+ from typing import Union, Any, Optional, Literal
5
5
 
6
- from ._logger import get_logger
7
- from ._script_info import _script_info
8
- from ._path_manager import make_fullpath, sanitize_filename
6
+ from .._core import get_logger
7
+ from ..path_manager import make_fullpath, sanitize_filename
9
8
 
10
9
 
11
10
  _LOGGER = get_logger("DragonSQL")
@@ -80,7 +79,7 @@ class DragonSQL:
80
79
  self.conn.close()
81
80
  _LOGGER.info(f"Database connection closed: {self.db_path.name}")
82
81
 
83
- def create_table(self, table_name: str, schema: Dict[str, str], if_not_exists: bool = True):
82
+ def create_table(self, table_name: str, schema: dict[str, str], if_not_exists: bool = True):
84
83
  """
85
84
  Creates a new table in the database based on a provided schema.
86
85
 
@@ -109,7 +108,7 @@ class DragonSQL:
109
108
  _LOGGER.info(f"➡️ Executing: {query}")
110
109
  self.cursor.execute(query)
111
110
 
112
- def insert_row(self, table_name: str, data: Dict[str, Any]):
111
+ def insert_row(self, table_name: str, data: dict[str, Any]):
113
112
  """
114
113
  Inserts a single row of data into the specified table.
115
114
 
@@ -175,7 +174,7 @@ class DragonSQL:
175
174
 
176
175
  self.cursor.execute(query, params if params else ())
177
176
 
178
- def insert_many(self, table_name: str, data: List[Dict[str, Any]]):
177
+ def insert_many(self, table_name: str, data: list[dict[str, Any]]):
179
178
  """
180
179
  Inserts multiple rows into the specified table in a single, efficient transaction.
181
180
 
@@ -239,7 +238,7 @@ class DragonSQL:
239
238
  )
240
239
  _LOGGER.info(f"➡️ Wrote {len(df)} rows from DataFrame to table '{table_name}' using mode '{if_exists}'.")
241
240
 
242
- def list_tables(self) -> List[str]:
241
+ def list_tables(self) -> list[str]:
243
242
  """Returns a list of all table names in the database."""
244
243
  if not self.cursor:
245
244
  _LOGGER.error("Database connection is not open.")
@@ -300,6 +299,3 @@ class DragonSQL:
300
299
  else:
301
300
  _LOGGER.error("Cannot commit: Database connection is not open.")
302
301
 
303
-
304
- def info():
305
- _script_info(__all__)
@@ -0,0 +1,8 @@
1
+ from .._core import _imprimir_disponibles
2
+
3
+ _GRUPOS = [
4
+ "DragonSQL",
5
+ ]
6
+
7
+ def info():
8
+ _imprimir_disponibles(_GRUPOS)
@@ -7,10 +7,10 @@ from statsmodels.tools.tools import add_constant
7
7
  import warnings
8
8
  from pathlib import Path
9
9
 
10
- from ._utilities import yield_dataframes_from_dir, save_dataframe_filename
11
- from ._path_manager import sanitize_filename, make_fullpath
12
- from ._logger import get_logger
13
- from ._script_info import _script_info
10
+ from ..utilities import yield_dataframes_from_dir, save_dataframe_filename
11
+
12
+ from ..path_manager import sanitize_filename, make_fullpath
13
+ from .._core import get_logger
14
14
 
15
15
 
16
16
  _LOGGER = get_logger("VIF")
@@ -31,7 +31,7 @@ def compute_vif(
31
31
  save_dir: Optional[Union[str,Path]] = None,
32
32
  filename: Optional[str] = None,
33
33
  fontsize: int = 14,
34
- show_plot: bool = True
34
+ show_plot: bool = False
35
35
  ) -> pd.DataFrame:
36
36
  """
37
37
  Computes Variance Inflation Factors (VIF) for numeric columns in a DataFrame. Optionally, generates a bar plot of VIF values.
@@ -234,6 +234,3 @@ def compute_vif_multi(input_directory: Union[str, Path],
234
234
  if len(dropped_cols) > 0:
235
235
  save_dataframe_filename(df=result_df, save_dir=output_dataset_path, filename=new_filename)
236
236
 
237
-
238
- def info():
239
- _script_info(__all__)
@@ -1,10 +1,12 @@
1
- from ._core._VIF_factor import (
1
+ from ._VIF_factor import (
2
2
  compute_vif,
3
3
  drop_vif_based,
4
4
  compute_vif_multi,
5
- info
6
5
  )
7
6
 
7
+ from ._imprimir import info
8
+
9
+
8
10
  __all__ = [
9
11
  "compute_vif",
10
12
  "drop_vif_based",
@@ -0,0 +1,10 @@
1
+ from .._core import _imprimir_disponibles
2
+
3
+ _GRUPOS = [
4
+ "compute_vif",
5
+ "drop_vif_based",
6
+ "compute_vif_multi"
7
+ ]
8
+
9
+ def info():
10
+ _imprimir_disponibles(_GRUPOS)
@@ -1 +1,7 @@
1
- __all__ = []
1
+ from ._script_info import _imprimir_disponibles
2
+ from ._logger import get_logger
3
+
4
+ __all__ = [
5
+ "_imprimir_disponibles",
6
+ "get_logger"
7
+ ]