dragon-ml-toolbox 3.11.0__tar.gz → 3.12.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.
- {dragon_ml_toolbox-3.11.0/dragon_ml_toolbox.egg-info → dragon_ml_toolbox-3.12.0}/PKG-INFO +1 -1
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0/dragon_ml_toolbox.egg-info}/PKG-INFO +1 -1
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/GUI_tools.py +147 -17
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/pyproject.toml +1 -1
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/LICENSE +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/LICENSE-THIRD-PARTY.md +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/README.md +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/dragon_ml_toolbox.egg-info/SOURCES.txt +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/dragon_ml_toolbox.egg-info/dependency_links.txt +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/dragon_ml_toolbox.egg-info/requires.txt +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/dragon_ml_toolbox.egg-info/top_level.txt +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/ETL_engineering.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/MICE_imputation.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/ML_callbacks.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/ML_evaluation.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/ML_trainer.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/ML_tutorial.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/PSO_optimization.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/RNN_forecast.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/VIF_factor.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/__init__.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/_pytorch_models.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/data_exploration.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/datasetmaster.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/ensemble_learning.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/handle_excel.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/keys.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/logger.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/path_manager.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/ml_tools/utilities.py +0 -0
- {dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/setup.cfg +0 -0
|
@@ -3,7 +3,7 @@ from pathlib import Path
|
|
|
3
3
|
import traceback
|
|
4
4
|
import FreeSimpleGUI as sg
|
|
5
5
|
from functools import wraps
|
|
6
|
-
from typing import Any, Dict, Tuple, List, Literal, Union,
|
|
6
|
+
from typing import Any, Dict, Tuple, List, Literal, Union, Optional, Callable
|
|
7
7
|
from .utilities import _script_info
|
|
8
8
|
import numpy as np
|
|
9
9
|
from .logger import _LOGGER
|
|
@@ -104,11 +104,13 @@ class ConfigManager:
|
|
|
104
104
|
'max_size': ''
|
|
105
105
|
}
|
|
106
106
|
config['Layout'] = {
|
|
107
|
-
'; Default size for continuous input boxes (width,height in characters).': '',
|
|
107
|
+
'; Default size for continuous input boxes (width,height in characters/rows).': '',
|
|
108
108
|
'input_size_cont': '16,1',
|
|
109
|
-
'; Default size for combo/binary boxes (width,height in characters).': '',
|
|
109
|
+
'; Default size for combo/binary boxes (width,height in characters/rows).': '',
|
|
110
110
|
'input_size_binary': '14,1',
|
|
111
|
-
';
|
|
111
|
+
'; Size for multiselect listboxes (width,height in characters/rows).': '',
|
|
112
|
+
'input_size_multi': '14,4',
|
|
113
|
+
'; Default size for buttons (width,height in characters/rows).': '',
|
|
112
114
|
'button_size': '15,2'
|
|
113
115
|
}
|
|
114
116
|
config['Fonts'] = {
|
|
@@ -303,6 +305,57 @@ class GUIFactory:
|
|
|
303
305
|
|
|
304
306
|
# Default to 'grid' layout
|
|
305
307
|
return [columns[i:i + features_per_column] for i in range(0, len(columns), features_per_column)]
|
|
308
|
+
|
|
309
|
+
def generate_multiselect_layout(
|
|
310
|
+
self,
|
|
311
|
+
data_dict: Dict[str, Union[List[Any], Tuple[Any, ...]]],
|
|
312
|
+
layout_mode: Literal["grid", "row"] = 'grid',
|
|
313
|
+
features_per_column: int = 4
|
|
314
|
+
) -> List[List[sg.Column]]:
|
|
315
|
+
"""
|
|
316
|
+
Generates a layout for features using Listbox elements for multiple selections.
|
|
317
|
+
|
|
318
|
+
This allows the user to select zero or more options from a list without
|
|
319
|
+
being able to input custom text.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
data_dict (dict): Keys are feature names, values are lists of options.
|
|
323
|
+
layout_mode (str): 'grid' for a multi-row grid layout, or 'row' for a single horizontal row.
|
|
324
|
+
features_per_column (int): Number of features per column when `layout_mode` is 'grid'.
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
A list of lists of sg.Column elements, ready to be used in a window layout.
|
|
328
|
+
"""
|
|
329
|
+
cfg = self.config
|
|
330
|
+
bg_color = sg.theme_background_color()
|
|
331
|
+
label_font = (cfg.fonts.font_family, cfg.fonts.label_size, cfg.fonts.label_style) # type: ignore
|
|
332
|
+
|
|
333
|
+
columns = []
|
|
334
|
+
for name, values in data_dict.items():
|
|
335
|
+
label = sg.Text(name, font=label_font, background_color=bg_color, key=f"_text_{name}")
|
|
336
|
+
|
|
337
|
+
# Use sg.Listbox for multiple selections.
|
|
338
|
+
element = sg.Listbox(
|
|
339
|
+
values,
|
|
340
|
+
key=name,
|
|
341
|
+
select_mode=sg.LISTBOX_SELECT_MODE_MULTIPLE,
|
|
342
|
+
size=cfg.layout.input_size_multi, # type: ignore
|
|
343
|
+
no_scrollbar=False
|
|
344
|
+
)
|
|
345
|
+
# -------------------
|
|
346
|
+
|
|
347
|
+
layout = [[label], [element]]
|
|
348
|
+
# Add a small spacer for consistent vertical alignment.
|
|
349
|
+
layout.append([sg.Text(" ", font=(cfg.fonts.font_family, 2), background_color=bg_color)]) # type: ignore
|
|
350
|
+
|
|
351
|
+
# Each feature is wrapped in a Column element for proper alignment.
|
|
352
|
+
columns.append(sg.Column(layout, background_color=bg_color))
|
|
353
|
+
|
|
354
|
+
if layout_mode == 'row':
|
|
355
|
+
return [columns] # A single row containing all columns
|
|
356
|
+
|
|
357
|
+
# Default to 'grid' layout
|
|
358
|
+
return [columns[i:i + features_per_column] for i in range(0, len(columns), features_per_column)]
|
|
306
359
|
|
|
307
360
|
# --- Window Creation ---
|
|
308
361
|
def create_window(self, title: str, layout: List[List[sg.Element]], **kwargs) -> sg.Window:
|
|
@@ -384,6 +437,7 @@ class FeatureMaster:
|
|
|
384
437
|
targets: Dict[str, str],
|
|
385
438
|
continuous_features: Optional[Dict[str, Tuple[str, float, float]]] = None,
|
|
386
439
|
binary_features: Optional[Dict[str, str]] = None,
|
|
440
|
+
multi_binary_features: Optional[Dict[str, Dict[str, str]]] = None,
|
|
387
441
|
one_hot_features: Optional[Dict[str, Dict[str, str]]] = None,
|
|
388
442
|
categorical_features: Optional[List[Tuple[str, str, Dict[str, int]]]] = None) -> None:
|
|
389
443
|
"""
|
|
@@ -410,6 +464,14 @@ class FeatureMaster:
|
|
|
410
464
|
A dictionary for binary (True/False) features.
|
|
411
465
|
- **key** (str): The name to be displayed in the GUI (e.g., for a checkbox).
|
|
412
466
|
- **value** (str): The model's internal feature name.
|
|
467
|
+
|
|
468
|
+
multi_binary_features (Dict[str, Dict[str, str]]):
|
|
469
|
+
A dictionary for features where multiple binary-like options can be
|
|
470
|
+
selected at once (e.g., from a multi-select listbox).
|
|
471
|
+
- **key** (str): The name for the group to be displayed in the GUI.
|
|
472
|
+
- **value** (Dict[str, str]): A nested dictionary where:
|
|
473
|
+
- key (str): The user-selectable option.
|
|
474
|
+
- value (str): The corresponding model's internal feature name.
|
|
413
475
|
|
|
414
476
|
one_hot_features (Dict[str, Dict[str, str]]):
|
|
415
477
|
A dictionary for features that will be one-hot encoded from a single
|
|
@@ -418,8 +480,7 @@ class FeatureMaster:
|
|
|
418
480
|
for a dropdown menu).
|
|
419
481
|
- **value** (Dict[str, str]): A nested dictionary where:
|
|
420
482
|
- key (str): The user-selectable option (e.g., 'Category A').
|
|
421
|
-
- value (str): The corresponding model column name
|
|
422
|
-
set to 1.
|
|
483
|
+
- value (str): The corresponding model column name.
|
|
423
484
|
|
|
424
485
|
categorical_features (List[Tuple[str, str, Dict[str, int]]]):
|
|
425
486
|
A list for ordinal or label-encoded categorical features.
|
|
@@ -431,7 +492,7 @@ class FeatureMaster:
|
|
|
431
492
|
options to their corresponding integer values.
|
|
432
493
|
"""
|
|
433
494
|
# Validation
|
|
434
|
-
if continuous_features is None and binary_features is None and one_hot_features is None and categorical_features is None:
|
|
495
|
+
if continuous_features is None and binary_features is None and one_hot_features is None and categorical_features is None and multi_binary_features is None:
|
|
435
496
|
raise ValueError("No features provided.")
|
|
436
497
|
|
|
437
498
|
# Targets
|
|
@@ -454,6 +515,15 @@ class FeatureMaster:
|
|
|
454
515
|
else:
|
|
455
516
|
self._binary_values, self._binary_mapping = None, None
|
|
456
517
|
self.has_binary = False
|
|
518
|
+
|
|
519
|
+
# multi-binary features
|
|
520
|
+
if multi_binary_features is not None:
|
|
521
|
+
self._multi_binary_values = self._handle_multi_binary_features(multi_binary_features)
|
|
522
|
+
self._multi_binary_mapping = multi_binary_features
|
|
523
|
+
self.has_multi_binary = True
|
|
524
|
+
else:
|
|
525
|
+
self._multi_binary_values, self._multi_binary_mapping = None, None
|
|
526
|
+
self.has_multi_binary = False
|
|
457
527
|
|
|
458
528
|
# one-hot features
|
|
459
529
|
if one_hot_features is not None:
|
|
@@ -493,6 +563,14 @@ class FeatureMaster:
|
|
|
493
563
|
gui_values: dict[str, tuple[Literal["False"],Literal["True"]]] = {gui_key: ("False", "True") for gui_key in binary_features.keys()}
|
|
494
564
|
# Map GUI name to Model name (same as input)
|
|
495
565
|
return gui_values
|
|
566
|
+
|
|
567
|
+
def _handle_multi_binary_features(self, multi_binary_features: Dict[str, Dict[str, str]]):
|
|
568
|
+
# Make dictionary GUI name: range values
|
|
569
|
+
gui_values: dict[str, tuple[str,...]] = {
|
|
570
|
+
gui_key: tuple(nested_dict.keys())
|
|
571
|
+
for gui_key, nested_dict in multi_binary_features.items()}
|
|
572
|
+
# Map GUI name to Model name and preserve internal mapping (same as input)
|
|
573
|
+
return gui_values
|
|
496
574
|
|
|
497
575
|
def _handle_one_hot_features(self, one_hot_features: Dict[str, Dict[str,str]]):
|
|
498
576
|
# Make dictionary GUI name: range values
|
|
@@ -514,6 +592,8 @@ class FeatureMaster:
|
|
|
514
592
|
all_dict.update(self._continuous_mapping)
|
|
515
593
|
if self._binary_mapping is not None:
|
|
516
594
|
all_dict.update(self._binary_mapping)
|
|
595
|
+
if self._multi_binary_mapping is not None:
|
|
596
|
+
all_dict.update(self._multi_binary_mapping)
|
|
517
597
|
if self._one_hot_mapping is not None:
|
|
518
598
|
all_dict.update(self._one_hot_mapping)
|
|
519
599
|
if self._categorical_mapping is not None:
|
|
@@ -595,6 +675,28 @@ class FeatureMaster:
|
|
|
595
675
|
"""
|
|
596
676
|
if self._binary_values is not None:
|
|
597
677
|
return self._binary_values
|
|
678
|
+
|
|
679
|
+
@property
|
|
680
|
+
def multi_binary(self):
|
|
681
|
+
"""
|
|
682
|
+
The mapping for multi-binary features.
|
|
683
|
+
|
|
684
|
+
Structure:
|
|
685
|
+
{"GUI NAME": {"GUI OPTION 1": "model_column"}}
|
|
686
|
+
"""
|
|
687
|
+
if self._multi_binary_mapping is not None:
|
|
688
|
+
return self._multi_binary_mapping
|
|
689
|
+
|
|
690
|
+
@property
|
|
691
|
+
def multi_binary_gui(self):
|
|
692
|
+
"""
|
|
693
|
+
The GUI options for multi-binary feature groups.
|
|
694
|
+
|
|
695
|
+
Structure:
|
|
696
|
+
Dict[str, Tuple[str, ...]]
|
|
697
|
+
"""
|
|
698
|
+
if self._multi_binary_values is not None:
|
|
699
|
+
return self._multi_binary_values
|
|
598
700
|
|
|
599
701
|
@property
|
|
600
702
|
def one_hot(self):
|
|
@@ -697,7 +799,7 @@ class GUIHandler:
|
|
|
697
799
|
Maps GUI name to model expected name and casts the value to float.
|
|
698
800
|
"""
|
|
699
801
|
try:
|
|
700
|
-
model_name = self.master.continuous[gui_feature]
|
|
802
|
+
model_name = self.master.continuous[gui_feature] # type: ignore
|
|
701
803
|
float_value = float(chosen_value)
|
|
702
804
|
except KeyError as e:
|
|
703
805
|
_LOGGER.error(f"No matching name for '{gui_feature}' defined as continuous.")
|
|
@@ -713,8 +815,8 @@ class GUIHandler:
|
|
|
713
815
|
Maps GUI name to model expected name and casts the value to binary (0,1).
|
|
714
816
|
"""
|
|
715
817
|
try:
|
|
716
|
-
model_name = self.master.binary[gui_feature]
|
|
717
|
-
binary_mapping_keys = self.master.binary_gui[gui_feature]
|
|
818
|
+
model_name = self.master.binary[gui_feature] # type: ignore
|
|
819
|
+
binary_mapping_keys = self.master.binary_gui[gui_feature] # type: ignore
|
|
718
820
|
except KeyError as e:
|
|
719
821
|
_LOGGER.error(f"No matching name for '{gui_feature}' defined as binary.")
|
|
720
822
|
raise e
|
|
@@ -725,13 +827,36 @@ class GUIHandler:
|
|
|
725
827
|
}
|
|
726
828
|
result = mapping_dict[chosen_value]
|
|
727
829
|
return model_name, result
|
|
830
|
+
|
|
831
|
+
def _process_multi_binary(self, gui_feature: str, chosen_values: list[str]) -> dict[str, int]:
|
|
832
|
+
"""
|
|
833
|
+
Maps GUI names to model expected names and casts values to multi-binary encoding.
|
|
834
|
+
|
|
835
|
+
For a given feature group, this sets all selected options to 1 and all
|
|
836
|
+
unselected options to 0.
|
|
837
|
+
"""
|
|
838
|
+
try:
|
|
839
|
+
# Get the mapping for the group
|
|
840
|
+
multi_binary_mapping = self.master.multi_binary[gui_feature] # type: ignore
|
|
841
|
+
except KeyError as e:
|
|
842
|
+
_LOGGER.error(f"No matching name for '{gui_feature}' defined as multi-binary.")
|
|
843
|
+
raise e
|
|
844
|
+
else:
|
|
845
|
+
# Start with all possible features for this group set to 0 (unselected)
|
|
846
|
+
results = {model_key: 0 for model_key in multi_binary_mapping.values()}
|
|
847
|
+
# Set the features for the chosen options to 1
|
|
848
|
+
for chosen_option in chosen_values:
|
|
849
|
+
model_name = multi_binary_mapping[chosen_option]
|
|
850
|
+
results[model_name] = 1
|
|
851
|
+
|
|
852
|
+
return results
|
|
728
853
|
|
|
729
854
|
def _process_one_hot(self, gui_feature: str, chosen_value: str) -> Dict[str,int]:
|
|
730
855
|
"""
|
|
731
856
|
Maps GUI names to model expected names and casts values to one-hot encoding.
|
|
732
857
|
"""
|
|
733
858
|
try:
|
|
734
|
-
one_hot_mapping = self.master.one_hot[gui_feature]
|
|
859
|
+
one_hot_mapping = self.master.one_hot[gui_feature] # type: ignore
|
|
735
860
|
except KeyError as e:
|
|
736
861
|
_LOGGER.error(f"No matching name for '{gui_feature}' defined as one-hot.")
|
|
737
862
|
raise e
|
|
@@ -748,7 +873,7 @@ class GUIHandler:
|
|
|
748
873
|
Maps GUI name to model expected name and casts the value to a categorical number.
|
|
749
874
|
"""
|
|
750
875
|
try:
|
|
751
|
-
categorical_tuple = self.master.categorical[gui_feature]
|
|
876
|
+
categorical_tuple = self.master.categorical[gui_feature] # type: ignore
|
|
752
877
|
except KeyError as e:
|
|
753
878
|
_LOGGER.error(f"No matching name for '{gui_feature}' defined as categorical.")
|
|
754
879
|
raise e
|
|
@@ -804,25 +929,31 @@ class GUIHandler:
|
|
|
804
929
|
|
|
805
930
|
if self.master.has_continuous:
|
|
806
931
|
processed_subset = self._call_subprocess(window_values=window_values,
|
|
807
|
-
master_feature=self.master.continuous,
|
|
932
|
+
master_feature=self.master.continuous, # type: ignore
|
|
808
933
|
processor=self._process_continuous)
|
|
809
934
|
processed_features.update(processed_subset)
|
|
810
935
|
|
|
811
936
|
if self.master.has_binary:
|
|
812
937
|
processed_subset = self._call_subprocess(window_values=window_values,
|
|
813
|
-
master_feature=self.master.binary,
|
|
938
|
+
master_feature=self.master.binary, # type: ignore
|
|
814
939
|
processor=self._process_binary)
|
|
815
940
|
processed_features.update(processed_subset)
|
|
941
|
+
|
|
942
|
+
if self.master.has_multi_binary:
|
|
943
|
+
processed_subset = self._call_subprocess(window_values=window_values,
|
|
944
|
+
master_feature=self.master.multi_binary, # type: ignore
|
|
945
|
+
processor=self._process_multi_binary)
|
|
946
|
+
processed_features.update(processed_subset)
|
|
816
947
|
|
|
817
948
|
if self.master.has_one_hot:
|
|
818
949
|
processed_subset = self._call_subprocess(window_values=window_values,
|
|
819
|
-
master_feature=self.master.one_hot,
|
|
950
|
+
master_feature=self.master.one_hot, # type: ignore
|
|
820
951
|
processor=self._process_one_hot)
|
|
821
952
|
processed_features.update(processed_subset)
|
|
822
953
|
|
|
823
954
|
if self.master.has_categorical:
|
|
824
955
|
processed_subset = self._call_subprocess(window_values=window_values,
|
|
825
|
-
master_feature=self.master.categorical,
|
|
956
|
+
master_feature=self.master.categorical, # type: ignore
|
|
826
957
|
processor=self._process_categorical)
|
|
827
958
|
processed_features.update(processed_subset)
|
|
828
959
|
|
|
@@ -836,7 +967,6 @@ class GUIHandler:
|
|
|
836
967
|
raise RuntimeError(f"Configuration Error: Implemented methods failed to generate the required model feature: '{e}'")
|
|
837
968
|
|
|
838
969
|
return np.array(final_vector, dtype=np.float32)
|
|
839
|
-
|
|
840
970
|
|
|
841
971
|
def info():
|
|
842
972
|
_script_info(__all__)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/dragon_ml_toolbox.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/dragon_ml_toolbox.egg-info/requires.txt
RENAMED
|
File without changes
|
{dragon_ml_toolbox-3.11.0 → dragon_ml_toolbox-3.12.0}/dragon_ml_toolbox.egg-info/top_level.txt
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|