mostlyai-engine 2.0.1__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.
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/PKG-INFO +1 -1
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/__init__.py +1 -1
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_tabular/interface.py +129 -29
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/pyproject.toml +1 -1
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/.gitignore +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/LICENSE +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/README.md +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_common.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_dtypes.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/__init__.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/language/__init__.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/language/categorical.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/language/datetime.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/language/numeric.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/language/text.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/__init__.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/categorical.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/character.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/datetime.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/itt.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/lat_long.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/numeric.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/__init__.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/common.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/encoding.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/engine/__init__.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/engine/base.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/engine/hf_engine.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/engine/vllm_engine.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/generation.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/interface.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/lstm.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/tokenizer_utils.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/training.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/xgrammar_utils.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_memory.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_tabular/__init__.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_tabular/argn.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_tabular/common.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_tabular/encoding.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_tabular/fairness.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_tabular/generation.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_tabular/training.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_training_utils.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_workspace.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/analysis.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/domain.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/encoding.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/generation.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/logging.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/random_state.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/splitting.py +0 -0
- {mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/training.py +0 -0
|
@@ -34,7 +34,7 @@ __all__ = [
|
|
|
34
34
|
"TabularARGN",
|
|
35
35
|
"LanguageModel",
|
|
36
36
|
]
|
|
37
|
-
__version__ = "2.0
|
|
37
|
+
__version__ = "2.1.0"
|
|
38
38
|
|
|
39
39
|
# suppress specific warning related to os.fork() in multi-threaded processes
|
|
40
40
|
warnings.filterwarnings("ignore", category=DeprecationWarning, message=".*multi-threaded.*fork.*")
|
|
@@ -30,13 +30,30 @@ import pandas as pd
|
|
|
30
30
|
import torch
|
|
31
31
|
from sklearn.base import BaseEstimator
|
|
32
32
|
|
|
33
|
-
from mostlyai.engine._common import
|
|
33
|
+
from mostlyai.engine._common import (
|
|
34
|
+
ensure_dataframe,
|
|
35
|
+
list_fn,
|
|
36
|
+
load_generated_data,
|
|
37
|
+
mean_fn,
|
|
38
|
+
median_fn,
|
|
39
|
+
mode_fn,
|
|
40
|
+
)
|
|
41
|
+
from mostlyai.engine._encoding_types.tabular.categorical import (
|
|
42
|
+
encode_categorical,
|
|
43
|
+
)
|
|
44
|
+
from mostlyai.engine._encoding_types.tabular.numeric import (
|
|
45
|
+
NUMERIC_BINNED_MAX_TOKEN,
|
|
46
|
+
NUMERIC_BINNED_MIN_TOKEN,
|
|
47
|
+
NUMERIC_BINNED_UNKNOWN_TOKEN,
|
|
48
|
+
encode_numeric,
|
|
49
|
+
)
|
|
34
50
|
from mostlyai.engine._workspace import Workspace
|
|
35
51
|
from mostlyai.engine.analysis import analyze
|
|
36
52
|
from mostlyai.engine.domain import (
|
|
37
53
|
DifferentialPrivacyConfig,
|
|
38
54
|
FairnessConfig,
|
|
39
55
|
ImputationConfig,
|
|
56
|
+
ModelEncodingType,
|
|
40
57
|
ModelType,
|
|
41
58
|
RareCategoryReplacementMethod,
|
|
42
59
|
RebalancingConfig,
|
|
@@ -446,6 +463,13 @@ class TabularARGN(BaseEstimator):
|
|
|
446
463
|
|
|
447
464
|
return X_imputed
|
|
448
465
|
|
|
466
|
+
def _get_column_stats(self) -> dict:
|
|
467
|
+
"""Get column statistics from workspace."""
|
|
468
|
+
workspace_dir = self._get_workspace_dir()
|
|
469
|
+
workspace = Workspace(workspace_dir)
|
|
470
|
+
stats = workspace.tgt_stats.read()
|
|
471
|
+
return stats.get("columns", {})
|
|
472
|
+
|
|
449
473
|
def _get_target_encoding_type(self, target_column: str | None = None) -> str | None:
|
|
450
474
|
"""Get the encoding type of the target column from workspace stats."""
|
|
451
475
|
if not self._fitted:
|
|
@@ -455,10 +479,7 @@ class TabularARGN(BaseEstimator):
|
|
|
455
479
|
if target_col is None:
|
|
456
480
|
return None
|
|
457
481
|
|
|
458
|
-
|
|
459
|
-
workspace = Workspace(workspace_dir)
|
|
460
|
-
stats = workspace.tgt_stats.read()
|
|
461
|
-
columns = stats.get("columns", {})
|
|
482
|
+
columns = self._get_column_stats()
|
|
462
483
|
if target_col in columns:
|
|
463
484
|
return columns[target_col].get("encoding_type")
|
|
464
485
|
return None
|
|
@@ -597,13 +618,18 @@ class TabularARGN(BaseEstimator):
|
|
|
597
618
|
ctx_data: pd.DataFrame | None = None,
|
|
598
619
|
n_draws: int = 1,
|
|
599
620
|
**kwargs,
|
|
600
|
-
) ->
|
|
621
|
+
) -> pd.DataFrame:
|
|
601
622
|
"""
|
|
602
623
|
Predict class probabilities for samples in X.
|
|
603
624
|
|
|
604
625
|
This method generates synthetic samples conditioned on the input features and computes
|
|
605
626
|
the probability of each class based on the frequency across multiple draws.
|
|
606
627
|
|
|
628
|
+
Supported encoding types:
|
|
629
|
+
- tabular_categorical: Multi-class categorical variables
|
|
630
|
+
- tabular_numeric_discrete: Discrete numeric variables
|
|
631
|
+
- tabular_numeric_binned: Binned numeric variables
|
|
632
|
+
|
|
607
633
|
Args:
|
|
608
634
|
X: Input samples. Can be array-like or pd.DataFrame of shape (n_samples, n_features).
|
|
609
635
|
target: Name of the target column to predict. If None, uses the target column from fit().
|
|
@@ -612,8 +638,15 @@ class TabularARGN(BaseEstimator):
|
|
|
612
638
|
**kwargs: Additional arguments passed to sample() method.
|
|
613
639
|
|
|
614
640
|
Returns:
|
|
615
|
-
|
|
616
|
-
|
|
641
|
+
pd.DataFrame with shape (n_samples, n_classes) where columns are named by class labels.
|
|
642
|
+
Column names are derived from encoding stats:
|
|
643
|
+
- Binned: Special tokens (e.g., "<<NULL>>"), min value, bin ranges (e.g., "<10000", ">=50000"), and max value (e.g., "0", ..., "99999")
|
|
644
|
+
- Categorical: All category names including special tokens (e.g., "_RARE_", "<<NULL>>", "male", "female")
|
|
645
|
+
- Discrete: All numeric values including special tokens (e.g., "_RARE_", "<<NULL>>", "1", "2", "3")
|
|
646
|
+
Each row contains probability distribution that sums to 1.0.
|
|
647
|
+
|
|
648
|
+
Raises:
|
|
649
|
+
ValueError: If target column has unsupported encoding type.
|
|
617
650
|
"""
|
|
618
651
|
if not self._fitted:
|
|
619
652
|
raise ValueError("Model must be fitted before prediction. Call fit() first.")
|
|
@@ -625,33 +658,100 @@ class TabularARGN(BaseEstimator):
|
|
|
625
658
|
"Target column must be specified for prediction. Provide 'target' parameter or fit with y."
|
|
626
659
|
)
|
|
627
660
|
|
|
661
|
+
# Get target column stats and validate encoding type
|
|
662
|
+
columns = self._get_column_stats()
|
|
663
|
+
if target_column not in columns:
|
|
664
|
+
raise ValueError(f"Target column '{target_column}' not found in model statistics")
|
|
665
|
+
|
|
666
|
+
target_stats = columns[target_column]
|
|
667
|
+
encoding_type = target_stats.get("encoding_type")
|
|
668
|
+
if not encoding_type:
|
|
669
|
+
raise ValueError(f"Target column '{target_column}' has no encoding type")
|
|
670
|
+
|
|
628
671
|
X_df = ensure_dataframe(X, columns=self._feature_names)
|
|
629
672
|
|
|
630
673
|
# Exclude target column from seed if present
|
|
631
674
|
if target_column in X_df.columns:
|
|
632
675
|
X_df = X_df.drop(columns=[target_column])
|
|
633
676
|
|
|
634
|
-
#
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
#
|
|
644
|
-
|
|
677
|
+
# Repeat X_df n_draws times for batch sampling
|
|
678
|
+
n_samples = len(X_df)
|
|
679
|
+
X_df_repeated = pd.concat([X_df] * n_draws, ignore_index=True)
|
|
680
|
+
|
|
681
|
+
# Generate all samples in a single batch
|
|
682
|
+
samples = self.sample(seed_data=X_df_repeated, ctx_data=ctx_data, **kwargs)
|
|
683
|
+
if target_column not in samples.columns:
|
|
684
|
+
raise ValueError(f"Target column '{target_column}' not found in generated samples")
|
|
685
|
+
|
|
686
|
+
# Re-encode the sampled values using the same encoding logic as the generator
|
|
687
|
+
sampled_values = samples[target_column]
|
|
688
|
+
|
|
689
|
+
if encoding_type == ModelEncodingType.tabular_numeric_binned:
|
|
690
|
+
encoded_df = encode_numeric(sampled_values, target_stats)
|
|
691
|
+
codes = encoded_df["bin"].values
|
|
692
|
+
elif encoding_type == ModelEncodingType.tabular_numeric_discrete:
|
|
693
|
+
encoded_df = encode_numeric(sampled_values, target_stats)
|
|
694
|
+
codes = encoded_df["cat"].values
|
|
695
|
+
elif encoding_type == ModelEncodingType.tabular_categorical:
|
|
696
|
+
encoded_df = encode_categorical(sampled_values, target_stats)
|
|
697
|
+
codes = encoded_df["cat"].values
|
|
698
|
+
else:
|
|
699
|
+
raise ValueError(
|
|
700
|
+
f"Target column '{target_column}' has unsupported encoding type '{encoding_type}'. "
|
|
701
|
+
f"Only categorical, discrete numeric, and binned numeric columns are supported."
|
|
702
|
+
)
|
|
645
703
|
|
|
646
|
-
#
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
704
|
+
# Reshape codes to (n_samples, n_draws)
|
|
705
|
+
codes_array = codes.reshape(n_samples, n_draws)
|
|
706
|
+
|
|
707
|
+
# Build class labels with their corresponding code values
|
|
708
|
+
codes = target_stats["codes"]
|
|
709
|
+
class_labels = []
|
|
710
|
+
class_code_values = []
|
|
711
|
+
|
|
712
|
+
# For binned: replace <<MIN>>/<<MAX>> tokens with actual bin values and reorder
|
|
713
|
+
if encoding_type == ModelEncodingType.tabular_numeric_binned:
|
|
714
|
+
bins = target_stats["bins"]
|
|
715
|
+
min_code_value = None
|
|
716
|
+
max_code_value = None
|
|
717
|
+
|
|
718
|
+
# First add special tokens (except <<UNK>>, <<MIN>>, <<MAX>>)
|
|
719
|
+
for code_name, code_value in codes.items():
|
|
720
|
+
if code_name == NUMERIC_BINNED_UNKNOWN_TOKEN:
|
|
721
|
+
continue # Skip <<UNK>>
|
|
722
|
+
elif code_name == NUMERIC_BINNED_MIN_TOKEN:
|
|
723
|
+
min_code_value = code_value # Save for later
|
|
724
|
+
elif code_name == NUMERIC_BINNED_MAX_TOKEN:
|
|
725
|
+
max_code_value = code_value # Save for later
|
|
726
|
+
else:
|
|
727
|
+
class_labels.append(code_name)
|
|
728
|
+
class_code_values.append(code_value)
|
|
729
|
+
|
|
730
|
+
# Add MIN value if present
|
|
731
|
+
if min_code_value is not None:
|
|
732
|
+
class_labels.append(str(bins[0]))
|
|
733
|
+
class_code_values.append(min_code_value)
|
|
734
|
+
|
|
735
|
+
# Add bin range labels
|
|
736
|
+
codes_bin_offset = len(codes)
|
|
737
|
+
for i in range(len(bins) - 1):
|
|
738
|
+
lower_bound = bins[i]
|
|
739
|
+
upper_bound = bins[i + 1]
|
|
740
|
+
label = f">={lower_bound}" if i == len(bins) - 2 else f"<{upper_bound}"
|
|
741
|
+
class_labels.append(label)
|
|
742
|
+
class_code_values.append(i + codes_bin_offset)
|
|
743
|
+
|
|
744
|
+
# Add MAX value at the end if present
|
|
745
|
+
if max_code_value is not None:
|
|
746
|
+
class_labels.append(str(bins[-1]))
|
|
747
|
+
class_code_values.append(max_code_value)
|
|
748
|
+
else:
|
|
749
|
+
# For discrete and categorical: use code names as-is
|
|
750
|
+
class_labels = list(codes.keys())
|
|
751
|
+
class_code_values = list(codes.values())
|
|
650
752
|
|
|
651
|
-
#
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
proba[:, i] = np.mean(predictions_array == cls, axis=1)
|
|
753
|
+
# Calculate probabilities for all classes at once
|
|
754
|
+
proba_list = [np.mean(codes_array == code_value, axis=1) for code_value in class_code_values]
|
|
755
|
+
proba = np.column_stack(proba_list)
|
|
655
756
|
|
|
656
|
-
|
|
657
|
-
return proba
|
|
757
|
+
return pd.DataFrame(proba, columns=class_labels)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/language/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/language/datetime.py
RENAMED
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/language/numeric.py
RENAMED
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/language/text.py
RENAMED
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/character.py
RENAMED
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/datetime.py
RENAMED
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/itt.py
RENAMED
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/lat_long.py
RENAMED
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_encoding_types/tabular/numeric.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/engine/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/engine/hf_engine.py
RENAMED
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/engine/vllm_engine.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyai_engine-2.0.1 → mostlyai_engine-2.1.0}/mostlyai/engine/_language/tokenizer_utils.py
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
|