upgini 1.2.167a4220.dev8__tar.gz → 1.2.167a4220.dev10__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.167a4220.dev8 → upgini-1.2.167a4220.dev10}/PKG-INFO +1 -1
- upgini-1.2.167a4220.dev10/src/upgini/__about__.py +1 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/features_enricher.py +120 -69
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/metadata.py +2 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/report/assemble.py +231 -36
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/report/data.py +6 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/report/html.py +19 -5
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/report/template.html +8 -4
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/search_task.py +25 -0
- upgini-1.2.167a4220.dev8/src/upgini/__about__.py +0 -1
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/.gitignore +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/LICENSE +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/README.md +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/pyproject.toml +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/ads.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/ads_management/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/ads_management/ads_manager.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/all_operators.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/binary.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/date.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/feature.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/groupby.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/operand.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/operator.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/base.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/cross.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/delta.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/lag.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/numpy_kernels.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/roll.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/trend.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/volatility.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/unary.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/vector.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/data_source/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/data_source/data_source_publisher.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/dataset.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/errors.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/http.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/mdc/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/mdc/context.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/metrics.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/normalizer/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/normalizer/normalize_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/report/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/report/stats.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/exceptions.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/strings.properties +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/strings_widget.properties +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/sampler/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/sampler/base.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/sampler/random_under_sampler.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/sampler/utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/spinner.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/Roboto-Regular.ttf +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/__init__.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/base_search_key_detector.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/blocked_time_series.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/config.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/country_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/cpu_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/custom_loss_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/cv_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/datetime_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/deduplicate_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/display_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/email_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/fallback_progress_bar.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/feature_info.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/features_validator.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/format.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/hash_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/ip_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/mstats.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/one_hot_encoder.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/phone_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/postal_code_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/progress_bar.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/psi.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/pyarrow_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/sample_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/search_key_derivations.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/sklearn_ext.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/sort.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/target_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/track_info.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/ts_utils.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/warning_counter.py +0 -0
- {upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/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.167a4220.
|
|
3
|
+
Version: 1.2.167a4220.dev10
|
|
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.167.a4220.dev10"
|
|
@@ -64,6 +64,7 @@ from upgini.metadata import (
|
|
|
64
64
|
FeaturesMetadataV2,
|
|
65
65
|
FileColumnMeaningType,
|
|
66
66
|
FileColumnMetadata,
|
|
67
|
+
GeneratedFeatureMetadata,
|
|
67
68
|
ModelTaskType,
|
|
68
69
|
RuntimeParameters,
|
|
69
70
|
SearchKey,
|
|
@@ -98,7 +99,14 @@ from upgini.utils.deduplicate_utils import (
|
|
|
98
99
|
clean_full_duplicates,
|
|
99
100
|
remove_fintech_duplicates,
|
|
100
101
|
)
|
|
101
|
-
from upgini.report.assemble import
|
|
102
|
+
from upgini.report.assemble import (
|
|
103
|
+
_fold_model_nodes,
|
|
104
|
+
_generated_feature_names,
|
|
105
|
+
_parse_generated_feature,
|
|
106
|
+
assemble_report_data,
|
|
107
|
+
autofe_rows_from_description,
|
|
108
|
+
build_search_results,
|
|
109
|
+
)
|
|
102
110
|
from upgini.report.html import generate_html_report
|
|
103
111
|
from upgini.report.stats import make_report_frame
|
|
104
112
|
from upgini.utils.display_utils import (
|
|
@@ -2479,11 +2487,14 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
2479
2487
|
generated_names=self._column_name_aliases(
|
|
2480
2488
|
self.fit_generated_features or [], self.fit_columns_renaming or {}
|
|
2481
2489
|
),
|
|
2490
|
+
generated_features=self._search_task.get_all_generated_features() if self._search_task else [],
|
|
2491
|
+
joined_ads_features_count=(
|
|
2492
|
+
self._search_task.get_joined_ads_features_count() if self._search_task else None
|
|
2493
|
+
),
|
|
2494
|
+
joined_ads_count=self._search_task.get_joined_ads_count() if self._search_task else None,
|
|
2482
2495
|
)
|
|
2483
|
-
autofe =
|
|
2496
|
+
autofe = autofe_rows_from_description(
|
|
2484
2497
|
self.get_autofe_features_description(features_meta=features_meta),
|
|
2485
|
-
features_meta,
|
|
2486
|
-
self._is_ensemble_feature,
|
|
2487
2498
|
self.bundle,
|
|
2488
2499
|
)
|
|
2489
2500
|
return features, sources, model_shap, summary, autofe
|
|
@@ -2503,15 +2514,57 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
2503
2514
|
return False
|
|
2504
2515
|
return bool(aliases & self._column_name_aliases(list(ensemble_names), renaming))
|
|
2505
2516
|
|
|
2517
|
+
@staticmethod
|
|
2518
|
+
def _match_autofe_meta_by_names(
|
|
2519
|
+
names: set[str],
|
|
2520
|
+
features_meta: list[FeaturesMetadataV2],
|
|
2521
|
+
used_names: set[str],
|
|
2522
|
+
) -> FeaturesMetadataV2 | None:
|
|
2523
|
+
available = [meta for meta in features_meta or [] if meta.name not in used_names]
|
|
2524
|
+
by_name = {meta.name: meta for meta in available}
|
|
2525
|
+
for name in names:
|
|
2526
|
+
matched = by_name.get(name)
|
|
2527
|
+
if matched is not None:
|
|
2528
|
+
return matched
|
|
2529
|
+
return None
|
|
2530
|
+
|
|
2531
|
+
def _add_autofe_description(
|
|
2532
|
+
self,
|
|
2533
|
+
descriptions: list[dict],
|
|
2534
|
+
used_names: set[str],
|
|
2535
|
+
feature_meta: FeaturesMetadataV2 | None,
|
|
2536
|
+
source_names: list[str],
|
|
2537
|
+
operand_names: Iterable[str],
|
|
2538
|
+
) -> None:
|
|
2539
|
+
if feature_meta is None or not feature_meta.shap_value:
|
|
2540
|
+
return
|
|
2541
|
+
description: dict = {}
|
|
2542
|
+
description["shap"] = feature_meta.shap_value
|
|
2543
|
+
source = feature_meta.data_source or ""
|
|
2544
|
+
description[self.bundle.get("autofe_descriptions_sources")] = source.replace(
|
|
2545
|
+
"AutoFE: features from ", ""
|
|
2546
|
+
).replace("AutoFE: feature from ", "")
|
|
2547
|
+
description[self.bundle.get("autofe_descriptions_feature_name")] = feature_meta.name
|
|
2548
|
+
feature_idx = 1
|
|
2549
|
+
for hashed in source_names:
|
|
2550
|
+
description[self.bundle.get("autofe_descriptions_feature").format(feature_idx)] = hashed
|
|
2551
|
+
feature_idx += 1
|
|
2552
|
+
# Don't show features with more than 2 base columns
|
|
2553
|
+
if feature_idx > 3:
|
|
2554
|
+
return
|
|
2555
|
+
description[self.bundle.get("autofe_descriptions_function")] = ",".join(sorted(operand_names))
|
|
2556
|
+
used_names.add(feature_meta.name)
|
|
2557
|
+
descriptions.append(description)
|
|
2558
|
+
|
|
2506
2559
|
def _ensemble_generated_metadata(self):
|
|
2507
2560
|
autofe_meta = self._search_task.get_autofe_metadata() if self._search_task else None
|
|
2508
2561
|
if not autofe_meta:
|
|
2509
2562
|
return []
|
|
2510
2563
|
matched = []
|
|
2511
2564
|
for meta in autofe_meta:
|
|
2512
|
-
|
|
2513
|
-
if
|
|
2514
|
-
matched.append((meta, op))
|
|
2565
|
+
feature = _parse_generated_feature(meta)
|
|
2566
|
+
if feature is not None and isinstance(feature.op, EnsembleModel):
|
|
2567
|
+
matched.append((meta, feature.op))
|
|
2515
2568
|
return matched
|
|
2516
2569
|
|
|
2517
2570
|
def _ensemble_feature_names_from_metadata(self) -> set[str]:
|
|
@@ -5864,6 +5917,7 @@ if response.status_code == 200:
|
|
|
5864
5917
|
|
|
5865
5918
|
selected_features_meta.sort(key=lambda m: (-m.shap_value, m.name))
|
|
5866
5919
|
psi_keepers = self._psi_stability_keepers() if self.psi_values is not None else set()
|
|
5920
|
+
single_ensemble = len(self._ensemble_generated_metadata()) == 1
|
|
5867
5921
|
|
|
5868
5922
|
for feature_meta in selected_features_meta:
|
|
5869
5923
|
original_name = original_names_dict.get(feature_meta.name, feature_meta.name)
|
|
@@ -5873,6 +5927,10 @@ if response.status_code == 200:
|
|
|
5873
5927
|
) or original_name in generated_aliases
|
|
5874
5928
|
is_client_feature = original_name in clients_features_df.columns and not is_generated_feature
|
|
5875
5929
|
|
|
5930
|
+
# Model-input ads/AutoFE rows are only for the HTML report; the selected output is the score.
|
|
5931
|
+
if single_ensemble and not is_client_feature and not self._is_ensemble_feature(feature_meta.name):
|
|
5932
|
+
continue
|
|
5933
|
+
|
|
5876
5934
|
if not is_client_feature and not is_generated_feature:
|
|
5877
5935
|
self.external_source_feature_names.append(original_name)
|
|
5878
5936
|
|
|
@@ -5887,8 +5945,6 @@ if response.status_code == 200:
|
|
|
5887
5945
|
if original_name in self.unstable_features or feature_meta.name in self.unstable_features:
|
|
5888
5946
|
continue
|
|
5889
5947
|
|
|
5890
|
-
# TODO make a decision about selected features based on special flag from mlb
|
|
5891
|
-
|
|
5892
5948
|
if original_shaps.get(feature_meta.name, 0.0) == 0.0 and not self._should_show_client_feature_in_report(
|
|
5893
5949
|
is_client_feature, feature_meta.name
|
|
5894
5950
|
):
|
|
@@ -5961,75 +6017,68 @@ if response.status_code == 200:
|
|
|
5961
6017
|
elif features_meta is None:
|
|
5962
6018
|
features_meta = self._search_task.get_all_features_metadata_v2()
|
|
5963
6019
|
|
|
5964
|
-
def get_feature_by_name(name: str):
|
|
5965
|
-
if not name or not features_meta:
|
|
5966
|
-
return None
|
|
5967
|
-
for candidate in features_meta:
|
|
5968
|
-
if candidate.name == name:
|
|
5969
|
-
return candidate
|
|
5970
|
-
return None
|
|
5971
|
-
|
|
5972
6020
|
descriptions = []
|
|
6021
|
+
used_names: set[str] = set()
|
|
5973
6022
|
for m in autofe_meta:
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
.
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
6023
|
+
try:
|
|
6024
|
+
orig_to_hashed = {
|
|
6025
|
+
base_column.original_name: base_column.hashed_name for base_column in m.base_columns
|
|
6026
|
+
}
|
|
6027
|
+
parsed = Feature.from_formula(m.formula)
|
|
6028
|
+
if not isinstance(parsed, Feature):
|
|
6029
|
+
continue
|
|
6030
|
+
autofe_feature = (
|
|
6031
|
+
parsed.set_display_index(m.display_index or None)
|
|
6032
|
+
.set_alias(m.alias)
|
|
6033
|
+
.set_op_params(m.operator_params or {})
|
|
6034
|
+
.rename_columns(orig_to_hashed)
|
|
6035
|
+
)
|
|
6036
|
+
except Exception:
|
|
6037
|
+
self.logger.exception(f"Failed to parse AutoFE formula: {m.formula}")
|
|
5987
6038
|
continue
|
|
5988
6039
|
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6040
|
+
fold_autofe = [
|
|
6041
|
+
child
|
|
6042
|
+
for fold in _fold_model_nodes(autofe_feature)
|
|
6043
|
+
for child in fold.children
|
|
6044
|
+
if isinstance(child, Feature)
|
|
6045
|
+
]
|
|
6046
|
+
if fold_autofe:
|
|
6047
|
+
hashed_to_orig = {hashed: orig for orig, hashed in orig_to_hashed.items()}
|
|
6048
|
+
for node in fold_autofe:
|
|
6049
|
+
is_ts = isinstance(node.op, TimeSeriesBase)
|
|
6050
|
+
source_names = [
|
|
6051
|
+
hashed
|
|
6052
|
+
for hashed in node.get_columns()
|
|
6053
|
+
if not is_ts or hashed_to_orig.get(hashed, hashed) not in self.fit_search_keys
|
|
6054
|
+
]
|
|
6055
|
+
name = node.get_display_name(shorten=True, unhash=True, cache=False)
|
|
6056
|
+
self._add_autofe_description(
|
|
6057
|
+
descriptions,
|
|
6058
|
+
used_names,
|
|
6059
|
+
self._match_autofe_meta_by_names({name} if name else set(), features_meta, used_names),
|
|
6060
|
+
source_names,
|
|
6061
|
+
node.get_all_operand_names(),
|
|
6062
|
+
)
|
|
6009
6063
|
continue
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
"AutoFE: features from ", ""
|
|
6014
|
-
).replace("AutoFE: feature from ", "")
|
|
6015
|
-
description[self.bundle.get("autofe_descriptions_feature_name")] = feature_meta.name
|
|
6016
|
-
|
|
6017
|
-
feature_idx = 1
|
|
6018
|
-
for bc in m.base_columns:
|
|
6019
|
-
if not is_ts or bc.original_name not in self.fit_search_keys:
|
|
6020
|
-
description[self.bundle.get("autofe_descriptions_feature").format(feature_idx)] = bc.hashed_name
|
|
6021
|
-
feature_idx += 1
|
|
6022
|
-
|
|
6023
|
-
# Don't show features with more than 2 base columns
|
|
6024
|
-
if feature_idx > 3:
|
|
6064
|
+
|
|
6065
|
+
is_ts = isinstance(autofe_feature.op, TimeSeriesBase)
|
|
6066
|
+
if autofe_feature.op.is_vector and not is_ts:
|
|
6025
6067
|
continue
|
|
6026
6068
|
|
|
6027
|
-
|
|
6028
|
-
|
|
6069
|
+
source_names = [
|
|
6070
|
+
bc.hashed_name
|
|
6071
|
+
for bc in m.base_columns
|
|
6072
|
+
if not is_ts or bc.original_name not in self.fit_search_keys
|
|
6073
|
+
]
|
|
6074
|
+
self._add_autofe_description(
|
|
6075
|
+
descriptions,
|
|
6076
|
+
used_names,
|
|
6077
|
+
self._match_autofe_meta_by_names(_generated_feature_names(m), features_meta, used_names),
|
|
6078
|
+
source_names,
|
|
6079
|
+
autofe_feature.get_all_operand_names(),
|
|
6029
6080
|
)
|
|
6030
6081
|
|
|
6031
|
-
descriptions.append(description)
|
|
6032
|
-
|
|
6033
6082
|
if len(descriptions) == 0:
|
|
6034
6083
|
return None
|
|
6035
6084
|
|
|
@@ -6206,6 +6255,8 @@ if response.status_code == 200:
|
|
|
6206
6255
|
display_html_dataframe(self.metrics, self.metrics, msg)
|
|
6207
6256
|
|
|
6208
6257
|
def __show_selected_features(self):
|
|
6258
|
+
if self._has_single_ensemble_score():
|
|
6259
|
+
return
|
|
6209
6260
|
try:
|
|
6210
6261
|
_ = get_ipython() # type: ignore
|
|
6211
6262
|
|
|
@@ -346,6 +346,8 @@ class ProviderTaskMetadataV2(BaseModel):
|
|
|
346
346
|
zero_hit_rate_search_keys: Optional[List[str]] = None
|
|
347
347
|
features_used_for_embeddings: Optional[List[str]] = None
|
|
348
348
|
shuffle_kfold: Optional[bool] = None
|
|
349
|
+
joined_ads_features_count: Optional[int] = None
|
|
350
|
+
joined_ads_count: Optional[int] = None
|
|
349
351
|
generated_features: Optional[List[GeneratedFeatureMetadata]] = None
|
|
350
352
|
|
|
351
353
|
|
|
@@ -7,7 +7,9 @@ from typing import Callable, Optional
|
|
|
7
7
|
import pandas as pd
|
|
8
8
|
|
|
9
9
|
from upgini.__about__ import __version__
|
|
10
|
-
from upgini.
|
|
10
|
+
from upgini.autofe.feature import Column, Feature
|
|
11
|
+
from upgini.autofe.vector import CatboostModel, EnsembleModel, OnnxModel
|
|
12
|
+
from upgini.metadata import BaseColumnMetadata, FeaturesMetadataV2, GeneratedFeatureMetadata
|
|
11
13
|
from upgini.report.data import (
|
|
12
14
|
FeatureRow,
|
|
13
15
|
ModelFeatureShap,
|
|
@@ -101,6 +103,9 @@ def build_search_results(
|
|
|
101
103
|
features_meta: list[FeaturesMetadataV2],
|
|
102
104
|
is_ensemble: Callable[[str], bool],
|
|
103
105
|
generated_names: Optional[set[str]] = None,
|
|
106
|
+
generated_features: Optional[list[GeneratedFeatureMetadata]] = None,
|
|
107
|
+
joined_ads_features_count: Optional[int] = None,
|
|
108
|
+
joined_ads_count: Optional[int] = None,
|
|
104
109
|
) -> tuple[list[FeatureRow], list[SourceRow], list[ModelFeatureShap], SearchResultsSummary]:
|
|
105
110
|
generated_names = generated_names or set()
|
|
106
111
|
model_rows: list[FeatureRow] = []
|
|
@@ -123,44 +128,19 @@ def build_search_results(
|
|
|
123
128
|
for index, row in enumerate(model_rows, start=1)
|
|
124
129
|
]
|
|
125
130
|
sources = _source_rows(found_rows)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
131
|
+
summary = _overview_summary(
|
|
132
|
+
features_meta=features_meta,
|
|
133
|
+
model_rows=model_rows,
|
|
134
|
+
found_rows=found_rows,
|
|
135
|
+
sources=sources,
|
|
136
|
+
is_ensemble=is_ensemble,
|
|
137
|
+
generated_features=generated_features or [],
|
|
138
|
+
joined_ads_features_count=joined_ads_features_count,
|
|
139
|
+
joined_ads_count=joined_ads_count,
|
|
135
140
|
)
|
|
136
141
|
return model_rows, sources, model_shap, summary
|
|
137
142
|
|
|
138
143
|
|
|
139
|
-
def autofe_rows_for_report(
|
|
140
|
-
df: Optional[pd.DataFrame],
|
|
141
|
-
features_meta: list[FeaturesMetadataV2],
|
|
142
|
-
is_ensemble: Callable[[str], bool],
|
|
143
|
-
bundle: ResourceBundle,
|
|
144
|
-
) -> list[dict[str, str]]:
|
|
145
|
-
rows = autofe_rows_from_description(df, bundle)
|
|
146
|
-
listed = {row["generatedFeature"] for row in rows if row.get("generatedFeature")}
|
|
147
|
-
for meta in features_meta:
|
|
148
|
-
if is_ensemble(meta.name) or meta.source != "generated":
|
|
149
|
-
continue
|
|
150
|
-
if not _has_nonzero_shap_value(meta.shap_value) or meta.name in listed:
|
|
151
|
-
continue
|
|
152
|
-
row = _feature_row(meta.name, meta)
|
|
153
|
-
rows.append(
|
|
154
|
-
{
|
|
155
|
-
"sources": row.source,
|
|
156
|
-
"generatedFeature": row.name,
|
|
157
|
-
"sourceFeatures": "",
|
|
158
|
-
"functions": "",
|
|
159
|
-
}
|
|
160
|
-
)
|
|
161
|
-
return rows
|
|
162
|
-
|
|
163
|
-
|
|
164
144
|
def autofe_rows_from_description(df: Optional[pd.DataFrame], bundle: ResourceBundle) -> list[dict[str, str]]:
|
|
165
145
|
if df is None or df.empty:
|
|
166
146
|
return []
|
|
@@ -275,11 +255,20 @@ def _feature_row(
|
|
|
275
255
|
drift=meta.drift_score,
|
|
276
256
|
coverage=meta.hit_rate,
|
|
277
257
|
provider=info.internal_provider,
|
|
278
|
-
source=info.internal_source,
|
|
258
|
+
source=_feature_source(meta, is_generated, info.internal_source),
|
|
279
259
|
stability_status=_psi_status(meta.psi_value),
|
|
280
260
|
)
|
|
281
261
|
|
|
282
262
|
|
|
263
|
+
def _feature_source(meta: FeaturesMetadataV2, is_generated: bool, fallback: str) -> str:
|
|
264
|
+
if is_generated:
|
|
265
|
+
if meta.data_source:
|
|
266
|
+
return meta.data_source
|
|
267
|
+
if meta.data_sources:
|
|
268
|
+
return ", ".join(meta.data_sources)
|
|
269
|
+
return fallback
|
|
270
|
+
|
|
271
|
+
|
|
283
272
|
def _source_rows(rows: list[FeatureRow]) -> list[SourceRow]:
|
|
284
273
|
grouped: dict[tuple[str, str], list[FeatureRow]] = {}
|
|
285
274
|
for row in rows:
|
|
@@ -311,3 +300,209 @@ def _psi_status(psi: Optional[float]) -> Optional[str]:
|
|
|
311
300
|
|
|
312
301
|
def _has_nonzero_shap_value(shap: Optional[float]) -> bool:
|
|
313
302
|
return shap is not None and not pd.isna(shap) and shap != 0
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _overview_summary(
|
|
306
|
+
*,
|
|
307
|
+
features_meta: list[FeaturesMetadataV2],
|
|
308
|
+
model_rows: list[FeatureRow],
|
|
309
|
+
found_rows: list[FeatureRow],
|
|
310
|
+
sources: list[SourceRow],
|
|
311
|
+
is_ensemble: Callable[[str], bool],
|
|
312
|
+
generated_features: list[GeneratedFeatureMetadata],
|
|
313
|
+
joined_ads_features_count: Optional[int],
|
|
314
|
+
joined_ads_count: Optional[int],
|
|
315
|
+
) -> SearchResultsSummary:
|
|
316
|
+
top_level = _unique_fold_model_inputs(generated_features)
|
|
317
|
+
features_by_name = {meta.name: meta for meta in features_meta}
|
|
318
|
+
autofe_by_name = _autofe_generated_by_name(generated_features, is_ensemble)
|
|
319
|
+
columns_by_name = _base_columns_by_name(generated_features)
|
|
320
|
+
ads_ids = _contributed_ads_ids(generated_features, autofe_by_name)
|
|
321
|
+
if top_level:
|
|
322
|
+
counts = {"external": 0, "original": 0, "autofe": 0}
|
|
323
|
+
psis: list[Optional[float]] = []
|
|
324
|
+
for node in top_level:
|
|
325
|
+
kind = _top_level_kind(node, features_by_name, columns_by_name, autofe_by_name, is_ensemble)
|
|
326
|
+
counts[kind] += 1
|
|
327
|
+
meta = _feature_meta_for_node(node, features_by_name, columns_by_name)
|
|
328
|
+
psis.append(None if meta is None else meta.psi_value)
|
|
329
|
+
model_features = len(top_level)
|
|
330
|
+
external, original, autofe = counts["external"], counts["original"], counts["autofe"]
|
|
331
|
+
contributed = len(ads_ids or set())
|
|
332
|
+
else:
|
|
333
|
+
model_features = len(model_rows) or None
|
|
334
|
+
external = original = autofe = None
|
|
335
|
+
contributed = (
|
|
336
|
+
len(ads_ids)
|
|
337
|
+
if ads_ids is not None
|
|
338
|
+
else len({(row.provider, row.source) for row in found_rows if row.provider})
|
|
339
|
+
)
|
|
340
|
+
psis = [row.psi for row in model_rows]
|
|
341
|
+
share, stable, psi_count = _stability_from_psi(psis)
|
|
342
|
+
return SearchResultsSummary(
|
|
343
|
+
relevant_features=len(found_rows),
|
|
344
|
+
features_found=joined_ads_features_count if joined_ads_features_count is not None else len(found_rows),
|
|
345
|
+
model_features=model_features,
|
|
346
|
+
external_features=external,
|
|
347
|
+
original_features=original,
|
|
348
|
+
autofe_features=autofe,
|
|
349
|
+
data_sources=len(sources),
|
|
350
|
+
joined_sources=joined_ads_count if joined_ads_count is not None else len(sources),
|
|
351
|
+
stable_features_share=share,
|
|
352
|
+
contributed_sources=contributed,
|
|
353
|
+
stable_features=stable,
|
|
354
|
+
psi_features=psi_count,
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def _unique_fold_model_inputs(generated_features: list[GeneratedFeatureMetadata]) -> list[Column | Feature]:
|
|
359
|
+
unique: dict[str, Column | Feature] = {}
|
|
360
|
+
for meta in generated_features:
|
|
361
|
+
feature = _parse_generated_feature(meta)
|
|
362
|
+
if feature is None:
|
|
363
|
+
continue
|
|
364
|
+
for fold in _fold_model_nodes(feature):
|
|
365
|
+
for child in fold.children:
|
|
366
|
+
unique.setdefault(_top_level_key(child), child)
|
|
367
|
+
return list(unique.values())
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def _fold_model_nodes(feature: Feature) -> list[Feature]:
|
|
371
|
+
if isinstance(feature.op, (CatboostModel, OnnxModel)):
|
|
372
|
+
return [feature]
|
|
373
|
+
nodes: list[Feature] = []
|
|
374
|
+
for child in feature.children:
|
|
375
|
+
if isinstance(child, Feature):
|
|
376
|
+
nodes.extend(_fold_model_nodes(child))
|
|
377
|
+
return nodes
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def _top_level_key(node: Column | Feature) -> str:
|
|
381
|
+
if isinstance(node, Column):
|
|
382
|
+
return f"col:{node.name}"
|
|
383
|
+
return f"fe:{node.to_formula()}"
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def _base_columns_by_name(generated_features: list[GeneratedFeatureMetadata]) -> dict[str, BaseColumnMetadata]:
|
|
387
|
+
by_name: dict[str, BaseColumnMetadata] = {}
|
|
388
|
+
for meta in generated_features:
|
|
389
|
+
for column in meta.base_columns:
|
|
390
|
+
if column.hashed_name:
|
|
391
|
+
by_name.setdefault(column.hashed_name, column)
|
|
392
|
+
if column.original_name:
|
|
393
|
+
by_name.setdefault(column.original_name, column)
|
|
394
|
+
return by_name
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def _column_names(node: Column, columns_by_name: dict[str, BaseColumnMetadata]) -> list[str]:
|
|
398
|
+
names = [node.name]
|
|
399
|
+
column = columns_by_name.get(node.name)
|
|
400
|
+
if column is not None:
|
|
401
|
+
names.extend([column.hashed_name, column.original_name])
|
|
402
|
+
return [name for name in names if name]
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
def _feature_meta_for_node(
|
|
406
|
+
node: Column | Feature,
|
|
407
|
+
features_by_name: dict[str, FeaturesMetadataV2],
|
|
408
|
+
columns_by_name: dict[str, BaseColumnMetadata],
|
|
409
|
+
) -> Optional[FeaturesMetadataV2]:
|
|
410
|
+
if not isinstance(node, Column):
|
|
411
|
+
return None
|
|
412
|
+
return next(
|
|
413
|
+
(features_by_name[name] for name in _column_names(node, columns_by_name) if name in features_by_name),
|
|
414
|
+
None,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def _autofe_generated_by_name(
|
|
419
|
+
generated_features: list[GeneratedFeatureMetadata], is_ensemble: Callable[[str], bool]
|
|
420
|
+
) -> dict[str, GeneratedFeatureMetadata]:
|
|
421
|
+
by_name: dict[str, GeneratedFeatureMetadata] = {}
|
|
422
|
+
for meta in generated_features:
|
|
423
|
+
feature = _parse_generated_feature(meta)
|
|
424
|
+
if feature is None or isinstance(feature.op, (CatboostModel, EnsembleModel, OnnxModel)):
|
|
425
|
+
continue
|
|
426
|
+
name = feature.get_display_name(shorten=True, unhash=True, cache=False)
|
|
427
|
+
if name and not is_ensemble(name):
|
|
428
|
+
by_name.setdefault(name, meta)
|
|
429
|
+
return by_name
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def _parse_generated_feature(meta: GeneratedFeatureMetadata) -> Feature | None:
|
|
433
|
+
try:
|
|
434
|
+
parsed = Feature.from_formula(meta.formula)
|
|
435
|
+
if not isinstance(parsed, Feature):
|
|
436
|
+
return None
|
|
437
|
+
orig_to_hashed = {column.original_name: column.hashed_name for column in meta.base_columns}
|
|
438
|
+
return (
|
|
439
|
+
parsed.set_display_index(meta.display_index or None)
|
|
440
|
+
.set_alias(meta.alias)
|
|
441
|
+
.set_op_params(meta.operator_params or {})
|
|
442
|
+
.rename_columns(orig_to_hashed)
|
|
443
|
+
)
|
|
444
|
+
except Exception:
|
|
445
|
+
return None
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def _generated_feature_names(meta: GeneratedFeatureMetadata) -> set[str]:
|
|
449
|
+
feature = _parse_generated_feature(meta)
|
|
450
|
+
if feature is None:
|
|
451
|
+
return set()
|
|
452
|
+
return {feature.get_display_name(shorten=True, unhash=True, cache=False)}
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def _top_level_kind(
|
|
456
|
+
node: Column | Feature,
|
|
457
|
+
features_by_name: dict[str, FeaturesMetadataV2],
|
|
458
|
+
columns_by_name: dict[str, BaseColumnMetadata],
|
|
459
|
+
autofe_by_name: dict[str, GeneratedFeatureMetadata],
|
|
460
|
+
is_ensemble: Callable[[str], bool],
|
|
461
|
+
) -> str:
|
|
462
|
+
if isinstance(node, Feature):
|
|
463
|
+
return "autofe"
|
|
464
|
+
names = _column_names(node, columns_by_name)
|
|
465
|
+
if any(name in autofe_by_name for name in names):
|
|
466
|
+
return "autofe"
|
|
467
|
+
meta = next((features_by_name[name] for name in names if name in features_by_name), None)
|
|
468
|
+
if meta is not None and not is_ensemble(meta.name):
|
|
469
|
+
if meta.source == "generated":
|
|
470
|
+
return "autofe"
|
|
471
|
+
if meta.source == "ads":
|
|
472
|
+
return "external"
|
|
473
|
+
if meta.source == "etalon":
|
|
474
|
+
return "original"
|
|
475
|
+
column = next((columns_by_name[name] for name in names if name in columns_by_name), None)
|
|
476
|
+
if column is not None and column.ads_definition_id:
|
|
477
|
+
return "external"
|
|
478
|
+
return "original"
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def _contributed_ads_ids(
|
|
482
|
+
generated_features: list[GeneratedFeatureMetadata],
|
|
483
|
+
autofe_by_name: dict[str, GeneratedFeatureMetadata],
|
|
484
|
+
) -> Optional[set[str]]:
|
|
485
|
+
ads_ids: Optional[set[str]] = None
|
|
486
|
+
for meta in generated_features:
|
|
487
|
+
feature = _parse_generated_feature(meta)
|
|
488
|
+
if feature is None or not _fold_model_nodes(feature):
|
|
489
|
+
continue
|
|
490
|
+
if ads_ids is None:
|
|
491
|
+
ads_ids = set()
|
|
492
|
+
for column in meta.base_columns:
|
|
493
|
+
ads_ids.update(_leaf_ads_ids(column, autofe_by_name))
|
|
494
|
+
return ads_ids
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def _leaf_ads_ids(column: BaseColumnMetadata, autofe_by_name: dict[str, GeneratedFeatureMetadata]) -> set[str]:
|
|
498
|
+
autofe = autofe_by_name.get(column.hashed_name) or autofe_by_name.get(column.original_name)
|
|
499
|
+
leaves = autofe.base_columns if autofe is not None else [column]
|
|
500
|
+
return {leaf.ads_definition_id for leaf in leaves if leaf.ads_definition_id}
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def _stability_from_psi(psis: list[Optional[float]]) -> tuple[Optional[float], Optional[int], Optional[int]]:
|
|
504
|
+
values = [psi for psi in psis if psi is not None and not pd.isna(psi)]
|
|
505
|
+
if not values:
|
|
506
|
+
return None, None, None
|
|
507
|
+
stable = sum(1 for psi in values if psi < _STABILITY_PSI)
|
|
508
|
+
return stable / len(values), stable, len(values)
|
|
@@ -66,11 +66,17 @@ class SourceRow:
|
|
|
66
66
|
@dataclass
|
|
67
67
|
class SearchResultsSummary:
|
|
68
68
|
relevant_features: Optional[int] = None
|
|
69
|
+
features_found: Optional[int] = None
|
|
69
70
|
model_features: Optional[int] = None
|
|
71
|
+
external_features: Optional[int] = None
|
|
72
|
+
original_features: Optional[int] = None
|
|
73
|
+
autofe_features: Optional[int] = None
|
|
70
74
|
data_sources: Optional[int] = None
|
|
75
|
+
joined_sources: Optional[int] = None
|
|
71
76
|
stable_features_share: Optional[float] = None
|
|
72
77
|
contributed_sources: Optional[int] = None
|
|
73
78
|
stable_features: Optional[int] = None
|
|
79
|
+
psi_features: Optional[int] = None
|
|
74
80
|
|
|
75
81
|
|
|
76
82
|
@dataclass
|
|
@@ -145,16 +145,30 @@ def _summary_cards(summary: SearchResultsSummary) -> list[dict]:
|
|
|
145
145
|
if summary.contributed_sources is not None:
|
|
146
146
|
sources_caption = f"{summary.contributed_sources} contributed"
|
|
147
147
|
stability_caption = ""
|
|
148
|
-
if summary.stable_features is not None and summary.
|
|
149
|
-
stability_caption = f"{summary.stable_features} of {summary.
|
|
148
|
+
if summary.stable_features is not None and summary.psi_features is not None:
|
|
149
|
+
stability_caption = f"{summary.stable_features} of {summary.psi_features} are stable"
|
|
150
|
+
features_found = summary.features_found if summary.features_found is not None else summary.relevant_features
|
|
151
|
+
data_sources = summary.joined_sources if summary.joined_sources is not None else summary.data_sources
|
|
150
152
|
return [
|
|
151
|
-
{"label": "Features found", "value": _dash(
|
|
152
|
-
{"label": "Used in model", "value": _dash(summary.model_features), "caption":
|
|
153
|
-
{"label": "Data sources", "value": _dash(
|
|
153
|
+
{"label": "Features found", "value": _dash(features_found), "caption": ""},
|
|
154
|
+
{"label": "Used in model", "value": _dash(summary.model_features), "caption": _used_in_model_caption(summary)},
|
|
155
|
+
{"label": "Data sources", "value": _dash(data_sources), "caption": sources_caption},
|
|
154
156
|
{"label": "Stability", "value": _dash(stability), "caption": stability_caption},
|
|
155
157
|
]
|
|
156
158
|
|
|
157
159
|
|
|
160
|
+
def _used_in_model_caption(summary: SearchResultsSummary) -> str:
|
|
161
|
+
if summary.external_features is None and summary.original_features is None and summary.autofe_features is None:
|
|
162
|
+
return ""
|
|
163
|
+
return " · ".join(
|
|
164
|
+
[
|
|
165
|
+
f"{summary.external_features or 0} external",
|
|
166
|
+
f"{summary.original_features or 0} original",
|
|
167
|
+
f"{summary.autofe_features or 0} AutoFE",
|
|
168
|
+
]
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
158
172
|
def _features_payload(features: list[FeatureRow]) -> list[dict]:
|
|
159
173
|
return [
|
|
160
174
|
{
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
<style>
|
|
8
8
|
:root{--ink:#15211f;--muted:#6f7976;--line:#dce4e1;--paper:#fff;--bg:#f3f6f5;--blue:#1645ee;--green:#53cc61;--cyan:#20aab4;--warn:#e19132;--danger:#d45b5b;--shadow:0 18px 60px rgba(18,45,39,.08)}
|
|
9
9
|
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--bg);color:var(--ink);font-family:Inter,ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;font-size:14px;line-height:1.45}.shell{max-width:1440px;margin:auto;min-height:100vh}.topbar{height:72px;padding:0 42px;display:flex;align-items:center;gap:25px;background:rgba(255,255,255,.92);backdrop-filter:blur(16px);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:20}.brand{display:flex;align-items:center;gap:14px}.wordmark{font-size:25px;font-weight:800;letter-spacing:-.07em;line-height:1;background:linear-gradient(135deg,#0138f8,#5bd357);-webkit-background-clip:text;background-clip:text;color:transparent}.wordmark b{font-weight:850}.wordmark span{font-weight:650}.wordmark.small{font-size:20px;min-width:66px}.brand-divider{width:1px;height:25px;background:var(--line)}.brand-label{font-weight:700;color:#45514f}.top-meta{display:flex;gap:8px;margin-left:auto;align-items:center}.chip{background:#eef2f1;border:1px solid #e0e7e5;border-radius:999px;padding:7px 11px;color:#53605d;font-size:12px}.button{border:0;border-radius:10px;padding:10px 15px;font:inherit;font-weight:700;cursor:pointer;transition:.18s ease}.button:hover{transform:translateY(-1px)}.button.primary{background:var(--ink);color:white}.button.ghost{background:white;border:1px solid var(--line);color:var(--ink)}.layout{display:grid;grid-template-columns:210px minmax(0,1fr);gap:0}.sidenav{position:sticky;top:72px;height:calc(100vh - 72px);padding:30px 22px;border-right:1px solid var(--line);background:#f7f9f8}.nav-title{font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:#98a29f;margin:0 10px 12px}.nav-link{display:flex;align-items:center;gap:10px;color:#66716f;text-decoration:none;padding:10px;border-radius:9px;margin:2px 0;font-weight:600}.nav-link:hover,.nav-link.active{background:white;color:var(--ink);box-shadow:0 4px 18px rgba(25,49,43,.06)}.nav-dot{width:7px;height:7px;border-radius:50%;background:#c4cecb}.nav-link.active .nav-dot{background:linear-gradient(135deg,var(--blue),var(--green))}.run-note{position:absolute;bottom:24px;left:22px;right:22px;padding:14px;background:white;border:1px solid var(--line);border-radius:12px;font-size:11px;color:var(--muted)}.run-note strong{display:block;color:var(--ink);font-size:12px;margin-bottom:4px}.main{min-width:0;padding:38px 44px 80px}.eyebrow{display:flex;align-items:center;gap:8px;text-transform:uppercase;letter-spacing:.12em;color:#74807d;font-size:11px;font-weight:800}.status-dot{width:8px;height:8px;border-radius:50%;background:var(--green);box-shadow:0 0 0 4px #e7f8e9}.hero-title{display:flex;justify-content:space-between;align-items:flex-end;gap:30px;margin:12px 0 28px}.hero-title h1{font-size:36px;line-height:1.08;letter-spacing:-.04em;margin:0;max-width:720px}.hero-title p{color:var(--muted);margin:10px 0 0;max-width:690px}.run-stamp{text-align:right;min-width:190px;color:var(--muted);font-size:12px}.run-stamp strong{display:block;color:var(--ink);font-size:14px;margin-bottom:3px}.metric-hero{position:relative;overflow:hidden;background:#172421;color:white;border-radius:22px;padding:28px 30px;box-shadow:var(--shadow);margin-bottom:18px}.metric-hero:after{content:"";position:absolute;width:400px;height:400px;right:-150px;top:-250px;border-radius:50%;background:radial-gradient(circle,rgba(71,215,117,.24),transparent 68%)}.metric-head{position:relative;z-index:1;display:flex;justify-content:space-between;gap:20px}.metric-tabs{display:flex;gap:5px;background:rgba(255,255,255,.08);border-radius:11px;padding:4px}.metric-tab{border:0;background:transparent;color:#aebbb7;padding:8px 12px;border-radius:8px;font-weight:700;cursor:pointer}.metric-tab.active{background:white;color:#13201e}.scores{position:relative;z-index:1;display:grid;grid-template-columns:1fr 1fr 1.2fr;gap:25px;margin-top:32px;align-items:end}.score-label{text-transform:uppercase;letter-spacing:.11em;color:#8fa09b;font-size:10px;font-weight:800}.score-value{font-size:39px;line-height:1;margin-top:8px;font-variant-numeric:tabular-nums;letter-spacing:-.04em}.uplift .score-value{color:#73e57b}.uplift p{color:#aebcb8;margin:8px 0 0;font-size:12px}.summary-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:18px 0 34px}.summary{background:white;border:1px solid var(--line);border-radius:15px;padding:17px 18px}.summary .k{color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.09em;font-weight:800}.summary .v{font-size:23px;font-weight:750;margin-top:5px;letter-spacing:-.02em}.summary .d{font-size:11px;color:#88928f;margin-top:4px}.section{scroll-margin-top:94px;margin-top:36px}.section-head{display:flex;align-items:end;justify-content:space-between;gap:20px;margin-bottom:15px}.section-head h2{font-size:22px;letter-spacing:-.025em;margin:0}.section-head p{color:var(--muted);margin:5px 0 0;font-size:12px}.panel{background:white;border:1px solid var(--line);border-radius:17px;box-shadow:0 4px 20px rgba(18,45,39,.035)}.chart-panel{padding:20px}.chart-head{display:flex;justify-content:space-between;align-items:center;gap:16px;margin-bottom:10px}.legend{display:flex;gap:17px;flex-wrap:wrap;font-size:11px;color:var(--muted)}.legend i{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:6px}.control{border:1px solid var(--line);background:#fafcfb;color:var(--ink);border-radius:9px;padding:8px 10px;font:inherit;font-size:12px}.canvas-wrap{height:280px;position:relative}canvas{width:100%;height:100%}.callout{display:flex;gap:12px;align-items:flex-start;padding:14px 16px;background:#fff8ed;border:1px solid #f1dcc0;border-radius:13px;color:#6b4b20}.callout strong{display:block;color:#4c361a;margin-bottom:2px}.callout-icon{width:27px;height:27px;display:grid;place-items:center;background:#f4c77f;border-radius:8px;font-weight:900;color:#65410c;flex:none}.stability-grid{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(260px,.5fr);gap:14px}.heatmap{overflow:auto;padding:16px}.heat-table{border-collapse:separate;border-spacing:5px;width:100%;font-size:11px}.heat-table th{color:var(--muted);font-weight:600;padding:2px 6px;white-space:nowrap}.heat-table th:first-child{text-align:left}.heat-table td:first-child{font-weight:700;padding-right:12px;white-space:nowrap}.heat{height:30px;min-width:47px;text-align:center;border-radius:6px;font-weight:750}.s1{background:#dbf4de;color:#276b2f}.s2{background:#e9f4cf;color:#526826}.s3{background:#fff0c7;color:#7f641b}.s4{background:#f8d5c8;color:#914634}.stability-side{padding:20px}.donut{width:140px;height:140px;border-radius:50%;margin:8px auto 17px;background:conic-gradient(var(--green) 0 72%,#e6b556 72% 91%,#df7474 91%);position:relative}.donut:after{content:"";position:absolute;inset:25px;background:white;border-radius:50%}.donut-label{position:absolute;inset:0;z-index:1;display:grid;place-items:center;text-align:center;font-weight:800;font-size:21px}.donut-label small{display:block;color:var(--muted);font-size:10px;font-weight:600}.stat-list{display:grid;gap:8px}.stat-row{display:flex;justify-content:space-between;padding-top:8px;border-top:1px solid #edf1ef;color:var(--muted);font-size:12px}.stat-row b{color:var(--ink)}.toolbar{display:flex;gap:9px;flex-wrap:wrap}.search{min-width:230px;border:1px solid var(--line);background:white;border-radius:9px;padding:9px 11px;font:inherit}.table-wrap{overflow:auto}.data-table{width:100%;border-collapse:collapse;min-width:860px}.data-table th{text-align:left;padding:12px 14px;background:#f8faf9;color:#77827f;text-transform:uppercase;letter-spacing:.07em;font-size:10px;border-bottom:1px solid var(--line)}.data-table td{padding:13px 14px;border-bottom:1px solid #edf1ef;font-size:12px}.data-table tr:last-child td{border-bottom:0}.data-table tbody tr:hover{background:#f8fbfa}.feature-name{font-weight:750;color:#25312f}.source-name{color:#74807d}.bar{height:6px;width:90px;background:#edf1ef;border-radius:99px;overflow:hidden}.bar i{height:100%;display:block;background:linear-gradient(90deg,var(--blue),#43c878);border-radius:99px}.tag{display:inline-flex;align-items:center;border-radius:999px;padding:4px 8px;font-size:10px;font-weight:750}.tag.good{background:#e8f7ea;color:#337139}.tag.watch{background:#fff1d9;color:#855d18}.tag.risk{background:#fde7e4;color:#984a40}.source-cards{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}.source-card{padding:19px}.source-top{display:flex;justify-content:space-between;gap:12px}.source-icon{width:38px;height:38px;border-radius:11px;display:grid;place-items:center;background:linear-gradient(135deg,#e8eeff,#e8f9e8);font-weight:850;color:var(--blue)}.source-card h3{font-size:14px;margin:12px 0 4px}.source-card p{font-size:11px;color:var(--muted);margin:0}.source-metrics{display:flex;gap:18px;margin-top:17px;padding-top:13px;border-top:1px solid #edf1ef}.source-metrics b{display:block;font-size:16px}.source-metrics span{color:var(--muted);font-size:10px}.notebook{padding:0;overflow:hidden}.cell-head{background:#f8faf9;border-bottom:1px solid var(--line);padding:10px 14px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:#68736f;font-size:11px}.cell-output{padding:18px;display:flex;align-items:center;gap:25px;flex-wrap:wrap}.cell-quality{display:flex;gap:24px}.cell-quality span{font-size:11px;color:var(--muted)}.cell-quality b{font-size:17px;color:var(--ink);display:block}.footer{text-align:center;color:#8a9592;font-size:11px;padding:40px 0 10px}.empty{display:none;padding:24px;text-align:center;color:var(--muted)}
|
|
10
|
-
.sample-table{min-width:700px}.toggle-legend{margin-bottom:10px}.series-toggle{border:0;background:transparent;color:var(--muted);cursor:pointer;font:inherit;font-size:11px;padding:5px 7px;border-radius:6px}.series-toggle:not(.active){opacity:.35;text-decoration:line-through}.threshold-legend{display:flex;gap:8px;justify-content:flex-end;margin-bottom:10px}.shap-panel{padding:16px}.shap-row{display:grid;grid-template-columns:minmax(
|
|
10
|
+
.sample-table{min-width:700px}.toggle-legend{margin-bottom:10px}.series-toggle{border:0;background:transparent;color:var(--muted);cursor:pointer;font:inherit;font-size:11px;padding:5px 7px;border-radius:6px}.series-toggle:not(.active){opacity:.35;text-decoration:line-through}.threshold-legend{display:flex;gap:8px;justify-content:flex-end;margin-bottom:10px}.shap-panel{padding:16px}.shap-row{display:grid;grid-template-columns:fit-content(55%) minmax(90px,1fr) 64px;gap:12px;align-items:center;padding:9px 4px;border-bottom:1px solid #edf1ef}.shap-row:last-child{border:0}.shap-name{min-width:0;overflow-wrap:anywhere;word-break:break-word}.shap-value{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}.provider{display:inline-block;font-size:9px;margin-left:6px;padding:3px 7px;border-radius:8px;border:1px solid var(--line);color:var(--muted);line-height:1.3;text-align:center;vertical-align:middle;white-space:normal}.shap-track{height:10px;background:#edf1ef;border-radius:99px;overflow:hidden}.shap-fill{display:block;height:100%;border-radius:99px}.shap-fill.upgini{background:#1645ee}.shap-fill.user{background:#20aab4}.shap-fill.autofe{background:#53cc61}.shap-fill.external{background:#7b5cff}.result-tabs{display:flex;gap:4px;margin-bottom:12px}.result-tab{border:1px solid var(--line);background:#eef2f1;padding:9px 13px;border-radius:9px;font:inherit;cursor:pointer;color:var(--muted)}.result-tab.active{background:var(--ink);color:#fff}.result-tab b{font-size:10px;margin-left:5px}.result-pane{display:none}.result-pane.active{display:block}.table-actions{display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap;margin-bottom:10px}.chart-tooltip{position:absolute;display:none;pointer-events:none;background:#172421;color:white;padding:9px 11px;border-radius:8px;font-size:10px;box-shadow:var(--shadow);white-space:nowrap}.sidenav{overflow:auto}.run-note{position:static;margin-top:22px}.nav-link{font-size:12px;padding:8px 10px}
|
|
11
11
|
.metric-sample-table{position:relative;z-index:1;margin-top:26px}.metric-sample-head,.metric-sample-row{display:grid;grid-template-columns:minmax(140px,.9fr) 1fr 1fr .8fr .8fr;gap:18px;align-items:center}.metric-sample-ci{display:block;margin-top:6px;color:#8fa09b;font-size:11px;font-weight:600;font-variant-numeric:tabular-nums}.metric-note{color:#8fa09b;font-size:11px;margin-top:6px}.partner-logo{height:30px;width:auto;display:block}.metric-sample-head{padding:0 14px 8px;color:#8fa09b;text-transform:uppercase;letter-spacing:.11em;font-size:10px;font-weight:800}.metric-sample-row{padding:15px 14px;border-top:1px solid rgba(255,255,255,.12)}.metric-sample-name{display:flex;align-items:center;gap:10px;font-size:16px;font-weight:760}.metric-sample-name i{width:9px;height:9px;border-radius:50%;background:var(--blue);box-shadow:0 0 0 4px rgba(22,69,238,.18)}.metric-sample-row[data-sample="eval_1"] .metric-sample-name i{background:var(--cyan);box-shadow:0 0 0 4px rgba(32,170,180,.18)}.metric-sample-row[data-sample="eval_2"] .metric-sample-name i{background:var(--green);box-shadow:0 0 0 4px rgba(83,204,97,.18)}.metric-sample-name small{display:block;color:#8fa09b;font-size:10px;font-weight:650;margin-top:2px}.metric-sample-value{font-size:27px;line-height:1;font-variant-numeric:tabular-nums;letter-spacing:-.035em}.metric-sample-uplift .metric-sample-value{color:#73e57b}.metric-sample-uplift p{margin:5px 0 0;color:#aebcb8;font-size:11px}.tall-chart{height:340px}.chart-tooltip b{font-size:11px}.chart-tooltip .tip-label{color:#aebbb7}.canvas-wrap canvas{cursor:crosshair}.search-id-chip{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
12
|
+
@supports (grid-template-columns:subgrid){.shap-panel{display:grid;grid-template-columns:fit-content(55%) minmax(90px,1fr) 64px;column-gap:12px}.shap-row{grid-template-columns:subgrid;grid-column:1/-1;padding-left:0;padding-right:0}}
|
|
12
13
|
@media(max-width:980px){.layout{grid-template-columns:1fr}.sidenav{display:none}.main{padding:28px 22px 70px}.topbar{padding:0 22px}.scores{grid-template-columns:1fr 1fr}.uplift{grid-column:1/-1}.summary-grid{grid-template-columns:1fr 1fr}.stability-grid,.sample-grid{grid-template-columns:1fr}.source-cards{grid-template-columns:1fr 1fr}}
|
|
13
14
|
@media(max-width:650px){.top-meta .chip,.brand-divider,.brand-label{display:none}.topbar{gap:10px}.button{padding:9px 10px}.hero-title{display:block}.run-stamp{text-align:left;margin-top:16px}.hero-title h1{font-size:30px}.metric-head{display:block}.metric-tabs{margin-top:15px;width:max-content}.summary-grid,.source-cards{grid-template-columns:1fr}.scores{gap:14px}.score-value{font-size:32px}.metric-sample-head{display:none}.metric-sample-row{grid-template-columns:1fr 1fr;gap:14px;padding:16px 2px}.metric-sample-name{grid-column:1/-1}.metric-sample-value{font-size:24px}.metric-sample-row>div:not(.metric-sample-name):before{display:block;color:#8fa09b;text-transform:uppercase;letter-spacing:.08em;font-size:8px;font-weight:800;margin-bottom:6px}.metric-sample-row>div:nth-child(2):before{content:"Baseline"}.metric-sample-row>div:nth-child(3):before{content:"Enriched"}.metric-sample-row>div:nth-child(4):before{content:"Uplift, abs"}.metric-sample-row>div:nth-child(5):before{content:"Uplift, %"}.main{padding-left:15px;padding-right:15px}.cell-output{gap:14px}}
|
|
14
15
|
</style>
|
|
@@ -127,6 +128,9 @@ const REPORT_DATA = __REPORT_DATA__;
|
|
|
127
128
|
const pct1 = v => (v == null ? '—' : Number(v).toFixed(1) + '%');
|
|
128
129
|
const signed3 = v => (v >= 0 ? '+' : '') + Number(v).toFixed(3);
|
|
129
130
|
const setText = (id, text) => { const el = document.getElementById(id); if (el) el.textContent = text; };
|
|
131
|
+
const providerBadge = provider => provider
|
|
132
|
+
? `<span class="provider">${String(provider).replace(/,\s*/g, '<br>')}</span>`
|
|
133
|
+
: '';
|
|
130
134
|
function rgba(hex, alpha) {
|
|
131
135
|
const h = hex.replace('#', '');
|
|
132
136
|
const n = parseInt(h.length === 3 ? h.split('').map(x => x + x).join('') : h, 16);
|
|
@@ -507,9 +511,9 @@ const REPORT_DATA = __REPORT_DATA__;
|
|
|
507
511
|
const maxImportance = Math.max(...features.map(f => f.importance)) || 1;
|
|
508
512
|
const list = shapAll ? features : features.slice(0, (D.shap && D.shap.topN) || features.length);
|
|
509
513
|
document.getElementById('shapList').innerHTML = list.map((f, i) =>
|
|
510
|
-
`<div class="shap-row"><div><b>#${i + 1} ${f.name}</b>${f.provider
|
|
514
|
+
`<div class="shap-row"><div class="shap-name"><b>#${i + 1} ${f.name}</b>${providerBadge(f.provider)}</div>` +
|
|
511
515
|
`<div class="shap-track"><i class="shap-fill ${f.shapClass || 'upgini'}" style="width:${(f.importance / maxImportance * 100).toFixed(2)}%"></i></div>` +
|
|
512
|
-
`<b>${fmt3(Math.abs(f.shap))}</b></div>`).join('');
|
|
516
|
+
`<b class="shap-value">${fmt3(Math.abs(f.shap))}</b></div>`).join('');
|
|
513
517
|
document.getElementById('showAllShap').textContent = shapAll ? `Show top ${(D.shap && D.shap.topN) || features.length}` : `Show all ${features.length}`;
|
|
514
518
|
}
|
|
515
519
|
|
|
@@ -534,7 +538,7 @@ const REPORT_DATA = __REPORT_DATA__;
|
|
|
534
538
|
const body = document.getElementById('featureBody');
|
|
535
539
|
body.innerHTML = rows.map(f =>
|
|
536
540
|
`<tr data-name="${f.name}"><td><span class="feature-name" title="${f.name}">${f.name}</span></td>` +
|
|
537
|
-
`<td>${f.provider
|
|
541
|
+
`<td>${providerBadge(f.provider)}</td><td class="source-name">${f.source}</td>` +
|
|
538
542
|
`<td>${shapLabel(f.shap)}</td><td><span class="tag ${f.status}">${fmt2(f.psi)}</span></td>` +
|
|
539
543
|
`<td>${f.drift == null ? '—' : fmt2(f.drift)}</td><td>${pct1(f.coverage)}</td></tr>`).join('');
|
|
540
544
|
document.getElementById('emptyState').style.display = rows.length ? 'none' : 'block';
|
|
@@ -210,6 +210,31 @@ class SearchTask:
|
|
|
210
210
|
if meta.generated_features is not None:
|
|
211
211
|
return meta.generated_features
|
|
212
212
|
|
|
213
|
+
def get_all_generated_features(self) -> List[GeneratedFeatureMetadata]:
|
|
214
|
+
if self.provider_metadata_v2 is None:
|
|
215
|
+
return []
|
|
216
|
+
generated: List[GeneratedFeatureMetadata] = []
|
|
217
|
+
for meta in self.provider_metadata_v2:
|
|
218
|
+
if meta.generated_features:
|
|
219
|
+
generated.extend(meta.generated_features)
|
|
220
|
+
return generated
|
|
221
|
+
|
|
222
|
+
def get_joined_ads_features_count(self) -> Optional[int]:
|
|
223
|
+
if self.provider_metadata_v2 is None:
|
|
224
|
+
return None
|
|
225
|
+
for meta in self.provider_metadata_v2:
|
|
226
|
+
if meta.joined_ads_features_count is not None:
|
|
227
|
+
return meta.joined_ads_features_count
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
def get_joined_ads_count(self) -> Optional[int]:
|
|
231
|
+
if self.provider_metadata_v2 is None:
|
|
232
|
+
return None
|
|
233
|
+
for meta in self.provider_metadata_v2:
|
|
234
|
+
if meta.joined_ads_count is not None:
|
|
235
|
+
return meta.joined_ads_count
|
|
236
|
+
return None
|
|
237
|
+
|
|
213
238
|
@staticmethod
|
|
214
239
|
def _get_provider_summaries(summary: SearchTaskSummary) -> List[ProviderTaskSummary]:
|
|
215
240
|
if summary.status in {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.2.167.a4220.dev8"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/ads_management/__init__.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/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.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/cross.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/delta.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/numpy_kernels.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/trend.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/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
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/normalizer/normalize_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/__init__.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/exceptions.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/strings.properties
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/sampler/random_under_sampler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/base_search_key_detector.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/blocked_time_series.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/custom_loss_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/deduplicate_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/fallback_progress_bar.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/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
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/src/upgini/utils/postal_code_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev8 → upgini-1.2.167a4220.dev10}/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
|