upgini 1.2.165a4244.dev2__tar.gz → 1.2.166a4253.dev1__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.
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/PKG-INFO +1 -1
- upgini-1.2.166a4253.dev1/src/upgini/__about__.py +1 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/features_enricher.py +375 -203
- upgini-1.2.165a4244.dev2/src/upgini/__about__.py +0 -1
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/.gitignore +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/LICENSE +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/README.md +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/pyproject.toml +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/__init__.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/ads.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/ads_management/__init__.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/ads_management/ads_manager.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/__init__.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/all_operators.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/binary.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/date.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/feature.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/groupby.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/operand.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/operator.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/__init__.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/base.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/cross.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/delta.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/lag.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/numpy_kernels.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/roll.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/trend.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/volatility.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/unary.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/vector.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/data_source/__init__.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/data_source/data_source_publisher.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/dataset.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/errors.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/http.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/mdc/__init__.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/mdc/context.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/metadata.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/metrics.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/normalizer/__init__.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/normalizer/normalize_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/resource_bundle/__init__.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/resource_bundle/exceptions.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/resource_bundle/strings.properties +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/resource_bundle/strings_widget.properties +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/sampler/__init__.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/sampler/base.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/sampler/random_under_sampler.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/sampler/utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/search_task.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/spinner.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/Roboto-Regular.ttf +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/__init__.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/base_search_key_detector.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/blocked_time_series.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/config.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/country_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/cpu_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/custom_loss_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/cv_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/datetime_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/deduplicate_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/display_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/email_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/fallback_progress_bar.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/feature_info.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/features_validator.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/format.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/hash_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/ip_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/mstats.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/one_hot_encoder.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/phone_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/postal_code_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/progress_bar.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/psi.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/pyarrow_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/sample_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/search_key_derivations.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/sklearn_ext.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/sort.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/target_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/track_info.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/ts_utils.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/warning_counter.py +0 -0
- {upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/version_validator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: upgini
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.166a4253.dev1
|
|
4
4
|
Summary: Intelligent data search & enrichment for Machine Learning
|
|
5
5
|
Project-URL: Bug Reports, https://github.com/upgini/upgini/issues
|
|
6
6
|
Project-URL: Homepage, https://upgini.com/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.2.166.a4253.dev1"
|
|
@@ -132,6 +132,8 @@ DEMO_DATASET_HASHES = [
|
|
|
132
132
|
"2519c9077c559f8975fdcdb5c50e9daae8d50b1d8a3ec72296c65ea7276f8812", # demo_salary transform
|
|
133
133
|
]
|
|
134
134
|
|
|
135
|
+
MATCH_HASH = "_match_hash"
|
|
136
|
+
|
|
135
137
|
|
|
136
138
|
class FeaturesEnricher(TransformerMixin):
|
|
137
139
|
"""Retrieve external features via Upgini that are most relevant to predict your target.
|
|
@@ -1135,7 +1137,7 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
1135
1137
|
enriched_estimator = None
|
|
1136
1138
|
ensemble_score_column = self._get_ensemble_score_column(fitting_X, fitting_enriched_X)
|
|
1137
1139
|
if set(fitting_X.columns) != set(fitting_enriched_X.columns):
|
|
1138
|
-
if ensemble_score_column is not None:
|
|
1140
|
+
if self.baseline_score_column is not None and ensemble_score_column is not None:
|
|
1139
1141
|
self.logger.info(
|
|
1140
1142
|
f"Only ensemble model returned; calculate enriched {metric} via roc_auc "
|
|
1141
1143
|
f"on ensemble score column: {ensemble_score_column}"
|
|
@@ -1755,6 +1757,7 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
1755
1757
|
def __enrich_df_with_fit_features(
|
|
1756
1758
|
self,
|
|
1757
1759
|
rows_to_drop: pd.DataFrame | None = None,
|
|
1760
|
+
left_columns: list[str] | None = None,
|
|
1758
1761
|
) -> tuple[pd.DataFrame, list[str], dict[str, SearchKey]] | None:
|
|
1759
1762
|
if self.df_with_original_index is None or self._search_task is None:
|
|
1760
1763
|
return None
|
|
@@ -1772,8 +1775,17 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
1772
1775
|
]
|
|
1773
1776
|
self.logger.info(f"After dropping target outliers size: {len(fit_features)}")
|
|
1774
1777
|
|
|
1778
|
+
left = self.df_with_original_index
|
|
1779
|
+
if left_columns is not None:
|
|
1780
|
+
left = left.loc[:, left_columns]
|
|
1781
|
+
join_keys = {ENTITY_SYSTEM_RECORD_ID, SYSTEM_RECORD_ID, EVAL_SET_INDEX}
|
|
1782
|
+
client_cols = set(self.df_with_original_index.columns) - join_keys
|
|
1783
|
+
right_keep = [c for c in fit_features.columns if c not in client_cols]
|
|
1784
|
+
if len(right_keep) < len(fit_features.columns):
|
|
1785
|
+
fit_features = fit_features.loc[:, right_keep]
|
|
1786
|
+
|
|
1775
1787
|
enriched_Xy = self.__enrich(
|
|
1776
|
-
|
|
1788
|
+
left,
|
|
1777
1789
|
fit_features,
|
|
1778
1790
|
how="inner",
|
|
1779
1791
|
drop_system_record_id=False,
|
|
@@ -1783,6 +1795,125 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
1783
1795
|
search_keys = {self.fit_columns_renaming.get(k, k): v for k, v in self.fit_search_keys.items()}
|
|
1784
1796
|
return enriched_Xy, generated_features, search_keys
|
|
1785
1797
|
|
|
1798
|
+
@staticmethod
|
|
1799
|
+
def __transform_match_columns(search_keys: dict[str, SearchKey], features_for_transform: list[str]) -> list[str]:
|
|
1800
|
+
return sorted(dict.fromkeys(list(search_keys.keys()) + list(features_for_transform)))
|
|
1801
|
+
|
|
1802
|
+
def __align_match_frame(self, source: pd.DataFrame, target: pd.DataFrame, cols: list[str]) -> pd.DataFrame | None:
|
|
1803
|
+
missing = [c for c in cols if c not in source.columns or c not in target.columns]
|
|
1804
|
+
if missing:
|
|
1805
|
+
self.logger.info(f"Match columns missing for fit reuse: {missing}")
|
|
1806
|
+
return None
|
|
1807
|
+
needs_cast = any(source[c].dtype != target[c].dtype for c in cols)
|
|
1808
|
+
# List indexing already materializes the subset; copy only when we have to astype.
|
|
1809
|
+
out = source[cols].copy() if needs_cast else source[cols]
|
|
1810
|
+
try:
|
|
1811
|
+
if needs_cast:
|
|
1812
|
+
for c in cols:
|
|
1813
|
+
if out[c].dtype != target[c].dtype:
|
|
1814
|
+
out[c] = out[c].astype(target[c].dtype)
|
|
1815
|
+
except (TypeError, ValueError) as e:
|
|
1816
|
+
self.logger.info(f"Failed to align match column dtypes for fit reuse: {e}")
|
|
1817
|
+
return None
|
|
1818
|
+
return out
|
|
1819
|
+
|
|
1820
|
+
@staticmethod
|
|
1821
|
+
def __dedupe_on(df: pd.DataFrame, subset: list[str]) -> pd.DataFrame:
|
|
1822
|
+
duplicated = df.duplicated(subset=subset)
|
|
1823
|
+
if not duplicated.any():
|
|
1824
|
+
return df
|
|
1825
|
+
return df.loc[~duplicated]
|
|
1826
|
+
|
|
1827
|
+
def __fit_feature_lookup(
|
|
1828
|
+
self,
|
|
1829
|
+
df_transform: pd.DataFrame,
|
|
1830
|
+
match_columns_hashed: list[str],
|
|
1831
|
+
feature_cols: list[str],
|
|
1832
|
+
enriched_Xy: pd.DataFrame,
|
|
1833
|
+
) -> pd.DataFrame | None:
|
|
1834
|
+
if self.df_with_original_index is None or enriched_Xy is None or len(enriched_Xy) == 0:
|
|
1835
|
+
return None
|
|
1836
|
+
if not match_columns_hashed or not feature_cols:
|
|
1837
|
+
return None
|
|
1838
|
+
if ENTITY_SYSTEM_RECORD_ID not in enriched_Xy.columns:
|
|
1839
|
+
return None
|
|
1840
|
+
if ENTITY_SYSTEM_RECORD_ID not in self.df_with_original_index.columns:
|
|
1841
|
+
return None
|
|
1842
|
+
|
|
1843
|
+
ads_cols = [c for c in feature_cols if c in enriched_Xy.columns]
|
|
1844
|
+
if not ads_cols:
|
|
1845
|
+
return None
|
|
1846
|
+
|
|
1847
|
+
key_cols = [c for c in match_columns_hashed if c in self.df_with_original_index.columns]
|
|
1848
|
+
if len(key_cols) != len(match_columns_hashed):
|
|
1849
|
+
return None
|
|
1850
|
+
|
|
1851
|
+
ads = self.__dedupe_on(enriched_Xy.loc[:, [ENTITY_SYSTEM_RECORD_ID] + ads_cols], [ENTITY_SYSTEM_RECORD_ID])
|
|
1852
|
+
covered_ids = ads[ENTITY_SYSTEM_RECORD_ID].to_numpy()
|
|
1853
|
+
|
|
1854
|
+
fit_keys = self.df_with_original_index.loc[:, key_cols + [ENTITY_SYSTEM_RECORD_ID]]
|
|
1855
|
+
covered_mask = fit_keys[ENTITY_SYSTEM_RECORD_ID].isin(covered_ids)
|
|
1856
|
+
if not covered_mask.all():
|
|
1857
|
+
fit_keys = fit_keys.loc[covered_mask]
|
|
1858
|
+
fit_keys = self.__dedupe_on(fit_keys, [ENTITY_SYSTEM_RECORD_ID])
|
|
1859
|
+
if len(fit_keys) == 0:
|
|
1860
|
+
return None
|
|
1861
|
+
|
|
1862
|
+
aligned = self.__align_match_frame(fit_keys, df_transform, match_columns_hashed)
|
|
1863
|
+
if aligned is None:
|
|
1864
|
+
return None
|
|
1865
|
+
|
|
1866
|
+
match_hash = pd.util.hash_pandas_object(aligned, index=False).astype("float64")
|
|
1867
|
+
lookup = ads.set_index(ENTITY_SYSTEM_RECORD_ID).reindex(fit_keys[ENTITY_SYSTEM_RECORD_ID].to_numpy())
|
|
1868
|
+
lookup[MATCH_HASH] = match_hash.to_numpy()
|
|
1869
|
+
lookup.reset_index(drop=True, inplace=True)
|
|
1870
|
+
return self.__dedupe_on(lookup, [MATCH_HASH])
|
|
1871
|
+
|
|
1872
|
+
def __unmatched_transform_mask(self, df: pd.DataFrame, lookup: pd.DataFrame | None) -> np.ndarray:
|
|
1873
|
+
if lookup is None or len(lookup) == 0 or MATCH_HASH not in lookup.columns:
|
|
1874
|
+
return np.ones(len(df), dtype=bool)
|
|
1875
|
+
return ~df[ENTITY_SYSTEM_RECORD_ID].isin(lookup[MATCH_HASH].to_numpy()).to_numpy()
|
|
1876
|
+
|
|
1877
|
+
def __attach_fit_lookup(
|
|
1878
|
+
self,
|
|
1879
|
+
dest: pd.DataFrame,
|
|
1880
|
+
lookup: pd.DataFrame,
|
|
1881
|
+
exclude_features_sources: list[str] | None,
|
|
1882
|
+
) -> pd.DataFrame:
|
|
1883
|
+
feature_lookup = lookup.set_index(MATCH_HASH)
|
|
1884
|
+
overlap = [c for c in feature_lookup.columns if c in dest.columns]
|
|
1885
|
+
if overlap:
|
|
1886
|
+
feature_lookup = feature_lookup.drop(columns=overlap)
|
|
1887
|
+
if exclude_features_sources:
|
|
1888
|
+
feature_lookup = feature_lookup.drop(columns=exclude_features_sources, errors="ignore")
|
|
1889
|
+
keys = dest[ENTITY_SYSTEM_RECORD_ID]
|
|
1890
|
+
for col in feature_lookup.columns:
|
|
1891
|
+
dest[col] = keys.map(feature_lookup[col])
|
|
1892
|
+
return dest
|
|
1893
|
+
|
|
1894
|
+
def __check_transform_quota(self, row_count: int) -> bool:
|
|
1895
|
+
"""Return False when transform should abort because of quota."""
|
|
1896
|
+
if row_count <= 0:
|
|
1897
|
+
return True
|
|
1898
|
+
transform_usage = self.rest_client.get_current_transform_usage(self._get_trace_id())
|
|
1899
|
+
self.logger.info(f"Current transform usage: {transform_usage}. Transforming {row_count} rows")
|
|
1900
|
+
if not transform_usage.has_limit:
|
|
1901
|
+
return True
|
|
1902
|
+
if row_count > transform_usage.rest_rows:
|
|
1903
|
+
rest_rows = max(transform_usage.rest_rows, 0)
|
|
1904
|
+
bundle_msg = (
|
|
1905
|
+
"transform_usage_warning_registered" if self.__is_registered else "transform_usage_warning_demo"
|
|
1906
|
+
)
|
|
1907
|
+
msg = self.bundle.get(bundle_msg).format(rest_rows, row_count)
|
|
1908
|
+
self.logger.warning(msg)
|
|
1909
|
+
print(msg)
|
|
1910
|
+
show_request_quote_button(is_registered=self.__is_registered)
|
|
1911
|
+
return False
|
|
1912
|
+
msg = self.bundle.get("transform_usage_info").format(transform_usage.limit, transform_usage.transformed_rows)
|
|
1913
|
+
self.logger.info(msg)
|
|
1914
|
+
print(msg)
|
|
1915
|
+
return True
|
|
1916
|
+
|
|
1786
1917
|
def __finalize_transform_result(
|
|
1787
1918
|
self,
|
|
1788
1919
|
result: pd.DataFrame,
|
|
@@ -1840,13 +1971,15 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
1840
1971
|
keep_input: bool,
|
|
1841
1972
|
add_fit_system_record_id: bool,
|
|
1842
1973
|
metrics_calculation: bool = False,
|
|
1974
|
+
enriched: tuple[pd.DataFrame, list[str], dict[str, SearchKey]] | None = None,
|
|
1843
1975
|
) -> tuple[pd.DataFrame, dict[str, str], list[str], dict[str, SearchKey]] | None:
|
|
1844
1976
|
"""Reuse fit enrichment for transform when X was already sent on fit.
|
|
1845
1977
|
|
|
1846
1978
|
Returns None when coverage is incomplete (sampling/dedup) so the caller can
|
|
1847
1979
|
fall back to a normal validation search.
|
|
1848
1980
|
"""
|
|
1849
|
-
enriched
|
|
1981
|
+
if enriched is None:
|
|
1982
|
+
enriched = self.__enrich_df_with_fit_features()
|
|
1850
1983
|
if enriched is None:
|
|
1851
1984
|
return None
|
|
1852
1985
|
enriched_Xy, generated_features, search_keys = enriched
|
|
@@ -1992,9 +2125,6 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
1992
2125
|
return self.baseline_score_column
|
|
1993
2126
|
|
|
1994
2127
|
def _get_ensemble_score_column(self, fitting_X: pd.DataFrame, fitting_enriched_X: pd.DataFrame) -> str | None:
|
|
1995
|
-
"""Ensemble score column when baseline_score_column is set and it is the only returned extra feature."""
|
|
1996
|
-
if self.baseline_score_column is None:
|
|
1997
|
-
return None
|
|
1998
2128
|
renaming = self.fit_columns_renaming or {}
|
|
1999
2129
|
generated_aliases = self._column_name_aliases(self.fit_generated_features or [], renaming)
|
|
2000
2130
|
new_external = [
|
|
@@ -3284,6 +3414,15 @@ if response.status_code == 200:
|
|
|
3284
3414
|
self.__display_support_link(msg)
|
|
3285
3415
|
return None, {}, [], search_keys
|
|
3286
3416
|
|
|
3417
|
+
fit_left_columns = [ENTITY_SYSTEM_RECORD_ID]
|
|
3418
|
+
if self.df_with_original_index is not None:
|
|
3419
|
+
if EVAL_SET_INDEX in self.df_with_original_index.columns:
|
|
3420
|
+
fit_left_columns.append(EVAL_SET_INDEX)
|
|
3421
|
+
for col in self.fit_generated_features or []:
|
|
3422
|
+
if col in self.df_with_original_index.columns:
|
|
3423
|
+
fit_left_columns.append(col)
|
|
3424
|
+
fit_enriched = self.__enrich_df_with_fit_features(left_columns=fit_left_columns)
|
|
3425
|
+
|
|
3287
3426
|
# Reuse fit enrichment when transforming the same train / eval / OOT object
|
|
3288
3427
|
# that was already uploaded on fit (avoids a second backend search + quota use).
|
|
3289
3428
|
fit_dataset_index = self._find_fit_dataset_index(X)
|
|
@@ -3296,6 +3435,7 @@ if response.status_code == 200:
|
|
|
3296
3435
|
keep_input,
|
|
3297
3436
|
add_fit_system_record_id,
|
|
3298
3437
|
metrics_calculation=metrics_calculation,
|
|
3438
|
+
enriched=fit_enriched,
|
|
3299
3439
|
)
|
|
3300
3440
|
if from_fit is not None:
|
|
3301
3441
|
return from_fit
|
|
@@ -3310,27 +3450,6 @@ if response.status_code == 200:
|
|
|
3310
3450
|
print(msg)
|
|
3311
3451
|
self.display_transactional_transform_api(only_online_sources=True)
|
|
3312
3452
|
|
|
3313
|
-
if not metrics_calculation:
|
|
3314
|
-
transform_usage = self.rest_client.get_current_transform_usage(self._get_trace_id())
|
|
3315
|
-
self.logger.info(f"Current transform usage: {transform_usage}. Transforming {len(X)} rows")
|
|
3316
|
-
if transform_usage.has_limit:
|
|
3317
|
-
if len(X) > transform_usage.rest_rows:
|
|
3318
|
-
rest_rows = max(transform_usage.rest_rows, 0)
|
|
3319
|
-
bundle_msg = (
|
|
3320
|
-
"transform_usage_warning_registered" if self.__is_registered else "transform_usage_warning_demo"
|
|
3321
|
-
)
|
|
3322
|
-
msg = self.bundle.get(bundle_msg).format(rest_rows, len(X))
|
|
3323
|
-
self.logger.warning(msg)
|
|
3324
|
-
print(msg)
|
|
3325
|
-
show_request_quote_button(is_registered=self.__is_registered)
|
|
3326
|
-
return None, {}, [], {}
|
|
3327
|
-
else:
|
|
3328
|
-
msg = self.bundle.get("transform_usage_info").format(
|
|
3329
|
-
transform_usage.limit, transform_usage.transformed_rows
|
|
3330
|
-
)
|
|
3331
|
-
self.logger.info(msg)
|
|
3332
|
-
print(msg)
|
|
3333
|
-
|
|
3334
3453
|
is_demo_dataset = hash_input(df) in DEMO_DATASET_HASHES
|
|
3335
3454
|
|
|
3336
3455
|
columns_to_drop = [
|
|
@@ -3448,7 +3567,7 @@ if response.status_code == 200:
|
|
|
3448
3567
|
runtime_parameters.properties["features_for_embeddings"] = ",".join(features_for_embeddings)
|
|
3449
3568
|
features_for_transform = [f for f in features_for_transform if f not in search_keys.keys()]
|
|
3450
3569
|
|
|
3451
|
-
columns_for_system_record_id =
|
|
3570
|
+
columns_for_system_record_id = self.__transform_match_columns(search_keys, features_for_transform)
|
|
3452
3571
|
|
|
3453
3572
|
df[ENTITY_SYSTEM_RECORD_ID] = pd.util.hash_pandas_object(df[columns_for_system_record_id], index=False).astype(
|
|
3454
3573
|
"float64"
|
|
@@ -3471,212 +3590,265 @@ if response.status_code == 200:
|
|
|
3471
3590
|
df = df.rename(columns={SYSTEM_RECORD_ID: SORT_ID})
|
|
3472
3591
|
features_not_to_pass.append(SORT_ID)
|
|
3473
3592
|
|
|
3593
|
+
lookup = None
|
|
3594
|
+
unmatched_mask = np.ones(len(df), dtype=bool)
|
|
3595
|
+
if fit_enriched is not None:
|
|
3596
|
+
enriched_Xy, fit_generated, _ = fit_enriched
|
|
3597
|
+
lookup_exclude = {
|
|
3598
|
+
TARGET,
|
|
3599
|
+
EVAL_SET_INDEX,
|
|
3600
|
+
SYSTEM_RECORD_ID,
|
|
3601
|
+
ENTITY_SYSTEM_RECORD_ID,
|
|
3602
|
+
SORT_ID,
|
|
3603
|
+
DateTimeConverter.DATETIME_COL,
|
|
3604
|
+
MATCH_HASH,
|
|
3605
|
+
}
|
|
3606
|
+
generated_set = set(fit_generated)
|
|
3607
|
+
feature_cols = [c for c in enriched_Xy.columns if c not in lookup_exclude and c not in generated_set]
|
|
3608
|
+
lookup = self.__fit_feature_lookup(df, columns_for_system_record_id, feature_cols, enriched_Xy)
|
|
3609
|
+
if lookup is not None and len(lookup) > 0:
|
|
3610
|
+
unmatched_mask = self.__unmatched_transform_mask(df, lookup)
|
|
3611
|
+
del enriched_Xy
|
|
3612
|
+
del fit_enriched
|
|
3613
|
+
|
|
3614
|
+
reused_count = int((~unmatched_mask).sum())
|
|
3615
|
+
unmatched_count = int(unmatched_mask.sum())
|
|
3616
|
+
self.logger.info(f"Fit enrichment reuse: reused={reused_count}, send_to_transform={unmatched_count}")
|
|
3617
|
+
|
|
3618
|
+
if not metrics_calculation and unmatched_count > 0:
|
|
3619
|
+
if not self.__check_transform_quota(unmatched_count):
|
|
3620
|
+
return None, {}, [], {}
|
|
3621
|
+
|
|
3474
3622
|
system_columns_with_original_index = [ENTITY_SYSTEM_RECORD_ID] + generated_features
|
|
3475
3623
|
if add_fit_system_record_id:
|
|
3476
3624
|
system_columns_with_original_index.append(SORT_ID)
|
|
3477
3625
|
|
|
3478
|
-
df_before_explode = df[system_columns_with_original_index]
|
|
3626
|
+
df_before_explode = df[system_columns_with_original_index]
|
|
3479
3627
|
|
|
3480
|
-
|
|
3481
|
-
|
|
3628
|
+
result_features = None
|
|
3629
|
+
unnest_search_keys: dict[str, list[str]] = {}
|
|
3630
|
+
if unmatched_count > 0:
|
|
3631
|
+
work_df = df if unmatched_mask.all() else df.iloc[unmatched_mask].copy()
|
|
3482
3632
|
|
|
3483
|
-
|
|
3633
|
+
# Explode multiple search keys
|
|
3634
|
+
work_df, unnest_search_keys = self._explode_multiple_search_keys(work_df, search_keys, columns_renaming)
|
|
3484
3635
|
|
|
3485
|
-
|
|
3486
|
-
hem_column = self._get_hem_column(search_keys)
|
|
3487
|
-
if email_column:
|
|
3488
|
-
converter = EmailSearchKeyConverter(
|
|
3489
|
-
email_column,
|
|
3490
|
-
hem_column,
|
|
3491
|
-
search_keys,
|
|
3492
|
-
columns_renaming,
|
|
3493
|
-
list(unnest_search_keys.keys()),
|
|
3494
|
-
self.logger,
|
|
3495
|
-
)
|
|
3496
|
-
df = converter.convert(df)
|
|
3636
|
+
# Convert search keys and generate features on them
|
|
3497
3637
|
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3638
|
+
email_column = self._get_email_column(search_keys)
|
|
3639
|
+
hem_column = self._get_hem_column(search_keys)
|
|
3640
|
+
if email_column:
|
|
3641
|
+
converter = EmailSearchKeyConverter(
|
|
3642
|
+
email_column,
|
|
3643
|
+
hem_column,
|
|
3644
|
+
search_keys,
|
|
3645
|
+
columns_renaming,
|
|
3646
|
+
list(unnest_search_keys.keys()),
|
|
3647
|
+
self.logger,
|
|
3648
|
+
)
|
|
3649
|
+
work_df = converter.convert(work_df)
|
|
3650
|
+
|
|
3651
|
+
ip_column = self._get_ip_column(search_keys)
|
|
3652
|
+
if ip_column:
|
|
3653
|
+
converter = IpSearchKeyConverter(
|
|
3654
|
+
ip_column,
|
|
3655
|
+
search_keys,
|
|
3656
|
+
columns_renaming,
|
|
3657
|
+
list(unnest_search_keys.keys()),
|
|
3658
|
+
self.bundle,
|
|
3659
|
+
self.logger,
|
|
3660
|
+
)
|
|
3661
|
+
work_df = converter.convert(work_df)
|
|
3662
|
+
|
|
3663
|
+
date_features = []
|
|
3664
|
+
for col in features_for_transform:
|
|
3665
|
+
if DateTimeConverter(col).is_datetime(work_df):
|
|
3666
|
+
work_df[col] = DateTimeConverter(col).to_date_string(work_df)
|
|
3667
|
+
date_features.append(col)
|
|
3668
|
+
|
|
3669
|
+
meaning_types = {}
|
|
3670
|
+
meaning_types.update(
|
|
3671
|
+
{
|
|
3672
|
+
col: FileColumnMeaningType.FEATURE
|
|
3673
|
+
for col in features_for_transform
|
|
3674
|
+
if col not in date_features and col not in generated_features
|
|
3675
|
+
}
|
|
3507
3676
|
)
|
|
3508
|
-
|
|
3677
|
+
meaning_types.update({col: FileColumnMeaningType.GENERATED_FEATURE for col in generated_features})
|
|
3678
|
+
meaning_types.update({col: FileColumnMeaningType.DATE_FEATURE for col in date_features})
|
|
3679
|
+
meaning_types.update({col: key.value for col, key in search_keys.items()})
|
|
3509
3680
|
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3681
|
+
features_not_to_pass.extend(
|
|
3682
|
+
[
|
|
3683
|
+
c
|
|
3684
|
+
for c in work_df.columns
|
|
3685
|
+
if c not in search_keys.keys()
|
|
3686
|
+
and c not in features_for_transform
|
|
3687
|
+
and c not in [ENTITY_SYSTEM_RECORD_ID, SEARCH_KEY_UNNEST]
|
|
3688
|
+
]
|
|
3689
|
+
)
|
|
3515
3690
|
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
{
|
|
3519
|
-
col: FileColumnMeaningType.FEATURE
|
|
3520
|
-
for col in features_for_transform
|
|
3521
|
-
if col not in date_features and col not in generated_features
|
|
3522
|
-
}
|
|
3523
|
-
)
|
|
3524
|
-
meaning_types.update({col: FileColumnMeaningType.GENERATED_FEATURE for col in generated_features})
|
|
3525
|
-
meaning_types.update({col: FileColumnMeaningType.DATE_FEATURE for col in date_features})
|
|
3526
|
-
meaning_types.update({col: key.value for col, key in search_keys.items()})
|
|
3691
|
+
if DateTimeConverter.DATETIME_COL in work_df.columns:
|
|
3692
|
+
work_df = work_df.drop(columns=DateTimeConverter.DATETIME_COL)
|
|
3527
3693
|
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3694
|
+
# search keys might be changed after explode
|
|
3695
|
+
columns_for_system_record_id = self.__transform_match_columns(search_keys, features_for_transform)
|
|
3696
|
+
work_df[SYSTEM_RECORD_ID] = pd.util.hash_pandas_object(
|
|
3697
|
+
work_df[columns_for_system_record_id], index=False
|
|
3698
|
+
).astype("float64")
|
|
3699
|
+
meaning_types[SYSTEM_RECORD_ID] = FileColumnMeaningType.SYSTEM_RECORD_ID
|
|
3700
|
+
meaning_types[ENTITY_SYSTEM_RECORD_ID] = FileColumnMeaningType.ENTITY_SYSTEM_RECORD_ID
|
|
3701
|
+
if SEARCH_KEY_UNNEST in work_df.columns:
|
|
3702
|
+
meaning_types[SEARCH_KEY_UNNEST] = FileColumnMeaningType.UNNEST_KEY
|
|
3537
3703
|
|
|
3538
|
-
|
|
3539
|
-
df = df.drop(columns=DateTimeConverter.DATETIME_COL)
|
|
3704
|
+
work_df = work_df.reset_index(drop=True)
|
|
3540
3705
|
|
|
3541
|
-
|
|
3542
|
-
columns_for_system_record_id = sorted(list(search_keys.keys()) + features_for_transform)
|
|
3543
|
-
df[SYSTEM_RECORD_ID] = pd.util.hash_pandas_object(df[columns_for_system_record_id], index=False).astype(
|
|
3544
|
-
"float64"
|
|
3545
|
-
)
|
|
3546
|
-
meaning_types[SYSTEM_RECORD_ID] = FileColumnMeaningType.SYSTEM_RECORD_ID
|
|
3547
|
-
meaning_types[ENTITY_SYSTEM_RECORD_ID] = FileColumnMeaningType.ENTITY_SYSTEM_RECORD_ID
|
|
3548
|
-
if SEARCH_KEY_UNNEST in df.columns:
|
|
3549
|
-
meaning_types[SEARCH_KEY_UNNEST] = FileColumnMeaningType.UNNEST_KEY
|
|
3706
|
+
combined_search_keys = combine_search_keys(search_keys.keys())
|
|
3550
3707
|
|
|
3551
|
-
|
|
3708
|
+
df_without_features = work_df.drop(columns=features_not_to_pass, errors="ignore")
|
|
3552
3709
|
|
|
3553
|
-
|
|
3710
|
+
df_without_features, full_duplicates_warning = clean_full_duplicates(
|
|
3711
|
+
df_without_features, is_transform=True, logger=self.logger, bundle=self.bundle
|
|
3712
|
+
)
|
|
3713
|
+
if not silent_mode and full_duplicates_warning:
|
|
3714
|
+
self.__log_warning(full_duplicates_warning)
|
|
3554
3715
|
|
|
3555
|
-
|
|
3716
|
+
del work_df
|
|
3717
|
+
gc.collect()
|
|
3556
3718
|
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3719
|
+
def invoke_validation(validation_df: pd.DataFrame):
|
|
3720
|
+
|
|
3721
|
+
dataset = Dataset(
|
|
3722
|
+
"sample_" + str(uuid.uuid4()),
|
|
3723
|
+
df=validation_df,
|
|
3724
|
+
meaning_types=meaning_types,
|
|
3725
|
+
search_keys=combined_search_keys,
|
|
3726
|
+
unnest_search_keys=unnest_search_keys,
|
|
3727
|
+
id_columns=self.__get_renamed_id_columns(columns_renaming),
|
|
3728
|
+
date_column=self._get_date_column(search_keys),
|
|
3729
|
+
date_format=self.date_format,
|
|
3730
|
+
sample_config=self.sample_config,
|
|
3731
|
+
rest_client=self.rest_client,
|
|
3732
|
+
logger=self.logger,
|
|
3733
|
+
bundle=self.bundle,
|
|
3734
|
+
warning_callback=self.__log_warning,
|
|
3735
|
+
)
|
|
3736
|
+
dataset.columns_renaming = columns_renaming
|
|
3562
3737
|
|
|
3563
|
-
|
|
3564
|
-
|
|
3738
|
+
validation_task = self._search_task.validation(
|
|
3739
|
+
self._get_trace_id(),
|
|
3740
|
+
dataset,
|
|
3741
|
+
start_time=start_time,
|
|
3742
|
+
extract_features=True,
|
|
3743
|
+
runtime_parameters=runtime_parameters,
|
|
3744
|
+
exclude_features_sources=exclude_features_sources,
|
|
3745
|
+
metrics_calculation=metrics_calculation,
|
|
3746
|
+
silent_mode=silent_mode,
|
|
3747
|
+
progress_bar=progress_bar,
|
|
3748
|
+
progress_callback=progress_callback,
|
|
3749
|
+
)
|
|
3565
3750
|
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
dataset = Dataset(
|
|
3569
|
-
"sample_" + str(uuid.uuid4()),
|
|
3570
|
-
df=df,
|
|
3571
|
-
meaning_types=meaning_types,
|
|
3572
|
-
search_keys=combined_search_keys,
|
|
3573
|
-
unnest_search_keys=unnest_search_keys,
|
|
3574
|
-
id_columns=self.__get_renamed_id_columns(columns_renaming),
|
|
3575
|
-
date_column=self._get_date_column(search_keys),
|
|
3576
|
-
date_format=self.date_format,
|
|
3577
|
-
sample_config=self.sample_config,
|
|
3578
|
-
rest_client=self.rest_client,
|
|
3579
|
-
logger=self.logger,
|
|
3580
|
-
bundle=self.bundle,
|
|
3581
|
-
warning_callback=self.__log_warning,
|
|
3582
|
-
)
|
|
3583
|
-
dataset.columns_renaming = columns_renaming
|
|
3584
|
-
|
|
3585
|
-
validation_task = self._search_task.validation(
|
|
3586
|
-
self._get_trace_id(),
|
|
3587
|
-
dataset,
|
|
3588
|
-
start_time=start_time,
|
|
3589
|
-
extract_features=True,
|
|
3590
|
-
runtime_parameters=runtime_parameters,
|
|
3591
|
-
exclude_features_sources=exclude_features_sources,
|
|
3592
|
-
metrics_calculation=metrics_calculation,
|
|
3593
|
-
silent_mode=silent_mode,
|
|
3594
|
-
progress_bar=progress_bar,
|
|
3595
|
-
progress_callback=progress_callback,
|
|
3596
|
-
)
|
|
3751
|
+
del validation_df, dataset
|
|
3752
|
+
gc.collect()
|
|
3597
3753
|
|
|
3598
|
-
|
|
3599
|
-
|
|
3754
|
+
if not silent_mode:
|
|
3755
|
+
print(self.bundle.get("polling_transform_task").format(validation_task.search_task_id))
|
|
3756
|
+
if not self.__is_registered:
|
|
3757
|
+
print(self.bundle.get("polling_unregister_information"))
|
|
3600
3758
|
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
if not
|
|
3604
|
-
|
|
3759
|
+
progress = self.get_progress(validation_task)
|
|
3760
|
+
progress.recalculate_eta(time.time() - start_time)
|
|
3761
|
+
if progress_bar is not None:
|
|
3762
|
+
progress_bar.progress = progress.to_progress_bar()
|
|
3763
|
+
if progress_callback is not None:
|
|
3764
|
+
progress_callback(progress)
|
|
3765
|
+
prev_progress: SearchProgress | None = None
|
|
3766
|
+
polling_period_seconds = 1
|
|
3767
|
+
try:
|
|
3768
|
+
while progress.stage != ProgressStage.DOWNLOADING.value:
|
|
3769
|
+
if prev_progress is None or prev_progress.percent != progress.percent:
|
|
3770
|
+
progress.recalculate_eta(time.time() - start_time)
|
|
3771
|
+
else:
|
|
3772
|
+
progress.update_eta(prev_progress.eta - polling_period_seconds)
|
|
3773
|
+
prev_progress = progress
|
|
3774
|
+
if progress_bar is not None:
|
|
3775
|
+
progress_bar.progress = progress.to_progress_bar()
|
|
3776
|
+
if progress_callback is not None:
|
|
3777
|
+
progress_callback(progress)
|
|
3778
|
+
if progress.stage == ProgressStage.FAILED.value:
|
|
3779
|
+
raise Exception(progress.error_message)
|
|
3780
|
+
time.sleep(polling_period_seconds)
|
|
3781
|
+
progress = self.get_progress(validation_task)
|
|
3782
|
+
except KeyboardInterrupt as e:
|
|
3783
|
+
print(self.bundle.get("search_stopping"))
|
|
3784
|
+
self.rest_client.stop_search_task_v2(self._get_trace_id(), validation_task.search_task_id)
|
|
3785
|
+
self.logger.warning(f"Search {validation_task.search_task_id} stopped by user")
|
|
3786
|
+
print(self.bundle.get("search_stopped"))
|
|
3787
|
+
raise e
|
|
3605
3788
|
|
|
3606
|
-
|
|
3607
|
-
progress.recalculate_eta(time.time() - start_time)
|
|
3608
|
-
if progress_bar is not None:
|
|
3609
|
-
progress_bar.progress = progress.to_progress_bar()
|
|
3610
|
-
if progress_callback is not None:
|
|
3611
|
-
progress_callback(progress)
|
|
3612
|
-
prev_progress: SearchProgress | None = None
|
|
3613
|
-
polling_period_seconds = 1
|
|
3614
|
-
try:
|
|
3615
|
-
while progress.stage != ProgressStage.DOWNLOADING.value:
|
|
3616
|
-
if prev_progress is None or prev_progress.percent != progress.percent:
|
|
3617
|
-
progress.recalculate_eta(time.time() - start_time)
|
|
3618
|
-
else:
|
|
3619
|
-
progress.update_eta(prev_progress.eta - polling_period_seconds)
|
|
3620
|
-
prev_progress = progress
|
|
3621
|
-
if progress_bar is not None:
|
|
3622
|
-
progress_bar.progress = progress.to_progress_bar()
|
|
3623
|
-
if progress_callback is not None:
|
|
3624
|
-
progress_callback(progress)
|
|
3625
|
-
if progress.stage == ProgressStage.FAILED.value:
|
|
3626
|
-
raise Exception(progress.error_message)
|
|
3627
|
-
time.sleep(polling_period_seconds)
|
|
3628
|
-
progress = self.get_progress(validation_task)
|
|
3629
|
-
except KeyboardInterrupt as e:
|
|
3630
|
-
print(self.bundle.get("search_stopping"))
|
|
3631
|
-
self.rest_client.stop_search_task_v2(self._get_trace_id(), validation_task.search_task_id)
|
|
3632
|
-
self.logger.warning(f"Search {validation_task.search_task_id} stopped by user")
|
|
3633
|
-
print(self.bundle.get("search_stopped"))
|
|
3634
|
-
raise e
|
|
3789
|
+
validation_task.poll_result(self._get_trace_id(), quiet=True)
|
|
3635
3790
|
|
|
3636
|
-
|
|
3791
|
+
seconds_left = time.time() - start_time
|
|
3792
|
+
progress = SearchProgress(97.0, ProgressStage.DOWNLOADING, seconds_left)
|
|
3793
|
+
if progress_bar is not None:
|
|
3794
|
+
progress_bar.progress = progress.to_progress_bar()
|
|
3795
|
+
if progress_callback is not None:
|
|
3796
|
+
progress_callback(progress)
|
|
3637
3797
|
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
if progress_bar is not None:
|
|
3641
|
-
progress_bar.progress = progress.to_progress_bar()
|
|
3642
|
-
if progress_callback is not None:
|
|
3643
|
-
progress_callback(progress)
|
|
3798
|
+
if not silent_mode:
|
|
3799
|
+
print(self.bundle.get("transform_start"))
|
|
3644
3800
|
|
|
3645
|
-
|
|
3646
|
-
print(self.bundle.get("transform_start"))
|
|
3801
|
+
return validation_task.get_all_validation_raw_features(self._get_trace_id(), metrics_calculation)
|
|
3647
3802
|
|
|
3648
|
-
|
|
3803
|
+
if len(df_without_features) <= Dataset.MAX_ROWS:
|
|
3804
|
+
result_features = invoke_validation(df_without_features)
|
|
3805
|
+
else:
|
|
3806
|
+
self.logger.warning(
|
|
3807
|
+
f"Dataset has more than {Dataset.MAX_ROWS} rows: {len(df_without_features)}, "
|
|
3808
|
+
f"splitting into chunks of {Dataset.MAX_ROWS} rows"
|
|
3809
|
+
)
|
|
3810
|
+
result_features_list = []
|
|
3649
3811
|
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
f"Dataset has more than {Dataset.MAX_ROWS} rows: {len(df_without_features)}, "
|
|
3655
|
-
f"splitting into chunks of {Dataset.MAX_ROWS} rows"
|
|
3656
|
-
)
|
|
3657
|
-
result_features_list = []
|
|
3812
|
+
for i in range(0, len(df_without_features), Dataset.MAX_ROWS):
|
|
3813
|
+
chunk = df_without_features.iloc[i : i + Dataset.MAX_ROWS]
|
|
3814
|
+
result_features_list.append(invoke_validation(chunk))
|
|
3815
|
+
result_features = pd.concat(result_features_list)
|
|
3658
3816
|
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
result_features_list.append(invoke_validation(chunk))
|
|
3662
|
-
result_features = pd.concat(result_features_list)
|
|
3817
|
+
del df
|
|
3818
|
+
gc.collect()
|
|
3663
3819
|
|
|
3664
|
-
#
|
|
3665
|
-
df_before_explode
|
|
3820
|
+
# Attach generated ids without a second full-width copy of validated_Xy.
|
|
3821
|
+
df_before_explode.rename(columns=columns_renaming, inplace=True)
|
|
3666
3822
|
generated_features = [columns_renaming.get(c, c) for c in generated_features]
|
|
3667
|
-
combined_df =
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3823
|
+
combined_df = validated_Xy.copy()
|
|
3824
|
+
for col in df_before_explode.columns:
|
|
3825
|
+
combined_df[col] = df_before_explode[col].to_numpy()
|
|
3826
|
+
del df_before_explode
|
|
3827
|
+
|
|
3828
|
+
unmatched_part = None
|
|
3829
|
+
if unmatched_count > 0:
|
|
3830
|
+
unmatched_part = self.__enrich(
|
|
3831
|
+
combined_df.iloc[unmatched_mask],
|
|
3832
|
+
result_features,
|
|
3833
|
+
how="left",
|
|
3834
|
+
)
|
|
3835
|
+
|
|
3836
|
+
if unmatched_mask.all() and unmatched_part is not None:
|
|
3837
|
+
result = unmatched_part
|
|
3838
|
+
else:
|
|
3839
|
+
base_cols = set(combined_df.columns)
|
|
3840
|
+
if reused_count > 0 and lookup is not None:
|
|
3841
|
+
self.__attach_fit_lookup(combined_df, lookup, exclude_features_sources)
|
|
3842
|
+
if unmatched_part is not None:
|
|
3843
|
+
ads_cols = [c for c in unmatched_part.columns if c not in base_cols]
|
|
3844
|
+
pos = np.flatnonzero(unmatched_mask)
|
|
3845
|
+
for col in ads_cols:
|
|
3846
|
+
if col not in combined_df.columns:
|
|
3847
|
+
combined_df[col] = np.nan
|
|
3848
|
+
combined_df.iloc[pos, combined_df.columns.get_loc(col)] = unmatched_part[col].to_numpy()
|
|
3849
|
+
result = combined_df
|
|
3850
|
+
result.index = validated_Xy.index
|
|
3851
|
+
result.index.name = validated_Xy.index.name
|
|
3680
3852
|
|
|
3681
3853
|
return self.__finalize_transform_result(
|
|
3682
3854
|
result,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.2.165.a4244.dev2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/ads_management/ads_manager.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
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/numpy_kernels.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/autofe/timeseries/volatility.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
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/normalizer/normalize_utils.py
RENAMED
|
File without changes
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/resource_bundle/__init__.py
RENAMED
|
File without changes
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/resource_bundle/exceptions.py
RENAMED
|
File without changes
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/resource_bundle/strings.properties
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/sampler/random_under_sampler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/base_search_key_detector.py
RENAMED
|
File without changes
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/blocked_time_series.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
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/fallback_progress_bar.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/features_validator.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
|
{upgini-1.2.165a4244.dev2 → upgini-1.2.166a4253.dev1}/src/upgini/utils/search_key_derivations.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
|