upgini 1.2.167a4220.dev9__tar.gz → 1.2.167a4220.dev11__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.dev9 → upgini-1.2.167a4220.dev11}/PKG-INFO +1 -1
- upgini-1.2.167a4220.dev11/src/upgini/__about__.py +1 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/features_enricher.py +107 -33
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/report/assemble.py +91 -18
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/report/template.html +4 -3
- upgini-1.2.167a4220.dev9/src/upgini/__about__.py +0 -1
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/.gitignore +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/LICENSE +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/README.md +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/pyproject.toml +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/ads.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/ads_management/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/ads_management/ads_manager.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/all_operators.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/binary.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/date.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/feature.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/groupby.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/operand.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/operator.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/base.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/cross.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/delta.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/lag.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/numpy_kernels.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/roll.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/trend.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/volatility.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/unary.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/vector.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/data_source/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/data_source/data_source_publisher.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/dataset.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/errors.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/http.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/mdc/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/mdc/context.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/metadata.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/metrics.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/normalizer/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/normalizer/normalize_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/report/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/report/data.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/report/html.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/report/stats.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/resource_bundle/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/resource_bundle/exceptions.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/resource_bundle/strings.properties +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/resource_bundle/strings_widget.properties +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/sampler/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/sampler/base.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/sampler/random_under_sampler.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/sampler/utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/search_task.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/spinner.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/Roboto-Regular.ttf +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/base_search_key_detector.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/blocked_time_series.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/config.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/country_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/cpu_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/custom_loss_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/cv_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/datetime_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/deduplicate_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/display_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/email_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/fallback_progress_bar.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/feature_info.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/features_validator.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/format.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/hash_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/ip_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/mstats.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/one_hot_encoder.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/phone_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/postal_code_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/progress_bar.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/psi.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/pyarrow_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/sample_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/search_key_derivations.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/sklearn_ext.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/sort.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/target_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/track_info.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/ts_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/warning_counter.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/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.dev11
|
|
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.dev11"
|
|
@@ -100,6 +100,7 @@ from upgini.utils.deduplicate_utils import (
|
|
|
100
100
|
remove_fintech_duplicates,
|
|
101
101
|
)
|
|
102
102
|
from upgini.report.assemble import (
|
|
103
|
+
_fold_model_nodes,
|
|
103
104
|
_generated_feature_names,
|
|
104
105
|
_parse_generated_feature,
|
|
105
106
|
assemble_report_data,
|
|
@@ -2513,20 +2514,81 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
2513
2514
|
return False
|
|
2514
2515
|
return bool(aliases & self._column_name_aliases(list(ensemble_names), renaming))
|
|
2515
2516
|
|
|
2516
|
-
def
|
|
2517
|
+
def _match_autofe_node_meta(
|
|
2517
2518
|
self,
|
|
2518
|
-
|
|
2519
|
+
autofe_feature: Feature,
|
|
2520
|
+
features_meta: list[FeaturesMetadataV2],
|
|
2521
|
+
used_names: set[str],
|
|
2522
|
+
) -> FeaturesMetadataV2 | None:
|
|
2523
|
+
name = autofe_feature.get_display_name(shorten=True, unhash=True, cache=False)
|
|
2524
|
+
matched = self._match_autofe_meta_by_names({name} if name else set(), features_meta, used_names)
|
|
2525
|
+
if matched is not None or not name:
|
|
2526
|
+
return matched
|
|
2527
|
+
# Fold formulas omit display_index; FeaturesMetadata still uses the ordinary
|
|
2528
|
+
# get_display_name() with that index. Recover only the remainder after the
|
|
2529
|
+
# Feature-computed base name, then verify with get_display_name().
|
|
2530
|
+
prefix = name + "_"
|
|
2531
|
+
previous = autofe_feature.display_index
|
|
2532
|
+
try:
|
|
2533
|
+
for meta in features_meta or []:
|
|
2534
|
+
if meta.name in used_names or not meta.name.startswith(prefix):
|
|
2535
|
+
continue
|
|
2536
|
+
index = meta.name[len(prefix) :]
|
|
2537
|
+
if not index:
|
|
2538
|
+
continue
|
|
2539
|
+
if (
|
|
2540
|
+
autofe_feature.set_display_index(index).get_display_name(
|
|
2541
|
+
shorten=True, unhash=True, cache=False
|
|
2542
|
+
)
|
|
2543
|
+
== meta.name
|
|
2544
|
+
):
|
|
2545
|
+
return meta
|
|
2546
|
+
finally:
|
|
2547
|
+
autofe_feature.set_display_index(previous)
|
|
2548
|
+
return None
|
|
2549
|
+
|
|
2550
|
+
@staticmethod
|
|
2551
|
+
def _match_autofe_meta_by_names(
|
|
2552
|
+
names: set[str],
|
|
2519
2553
|
features_meta: list[FeaturesMetadataV2],
|
|
2520
2554
|
used_names: set[str],
|
|
2521
2555
|
) -> FeaturesMetadataV2 | None:
|
|
2522
2556
|
available = [meta for meta in features_meta or [] if meta.name not in used_names]
|
|
2523
2557
|
by_name = {meta.name: meta for meta in available}
|
|
2524
|
-
for name in
|
|
2558
|
+
for name in names:
|
|
2525
2559
|
matched = by_name.get(name)
|
|
2526
2560
|
if matched is not None:
|
|
2527
2561
|
return matched
|
|
2528
2562
|
return None
|
|
2529
2563
|
|
|
2564
|
+
def _add_autofe_description(
|
|
2565
|
+
self,
|
|
2566
|
+
descriptions: list[dict],
|
|
2567
|
+
used_names: set[str],
|
|
2568
|
+
feature_meta: FeaturesMetadataV2 | None,
|
|
2569
|
+
source_names: list[str],
|
|
2570
|
+
operand_names: Iterable[str],
|
|
2571
|
+
) -> None:
|
|
2572
|
+
if feature_meta is None or not feature_meta.shap_value:
|
|
2573
|
+
return
|
|
2574
|
+
description: dict = {}
|
|
2575
|
+
description["shap"] = feature_meta.shap_value
|
|
2576
|
+
source = feature_meta.data_source or ""
|
|
2577
|
+
description[self.bundle.get("autofe_descriptions_sources")] = source.replace(
|
|
2578
|
+
"AutoFE: features from ", ""
|
|
2579
|
+
).replace("AutoFE: feature from ", "")
|
|
2580
|
+
description[self.bundle.get("autofe_descriptions_feature_name")] = feature_meta.name
|
|
2581
|
+
feature_idx = 1
|
|
2582
|
+
for hashed in source_names:
|
|
2583
|
+
description[self.bundle.get("autofe_descriptions_feature").format(feature_idx)] = hashed
|
|
2584
|
+
feature_idx += 1
|
|
2585
|
+
# Don't show features with more than 2 base columns
|
|
2586
|
+
if feature_idx > 3:
|
|
2587
|
+
return
|
|
2588
|
+
description[self.bundle.get("autofe_descriptions_function")] = ",".join(sorted(operand_names))
|
|
2589
|
+
used_names.add(feature_meta.name)
|
|
2590
|
+
descriptions.append(description)
|
|
2591
|
+
|
|
2530
2592
|
def _ensemble_generated_metadata(self):
|
|
2531
2593
|
autofe_meta = self._search_task.get_autofe_metadata() if self._search_task else None
|
|
2532
2594
|
if not autofe_meta:
|
|
@@ -5995,9 +6057,11 @@ if response.status_code == 200:
|
|
|
5995
6057
|
orig_to_hashed = {
|
|
5996
6058
|
base_column.original_name: base_column.hashed_name for base_column in m.base_columns
|
|
5997
6059
|
}
|
|
6060
|
+
parsed = Feature.from_formula(m.formula)
|
|
6061
|
+
if not isinstance(parsed, Feature):
|
|
6062
|
+
continue
|
|
5998
6063
|
autofe_feature = (
|
|
5999
|
-
|
|
6000
|
-
.set_display_index(m.display_index or None)
|
|
6064
|
+
parsed.set_display_index(m.display_index or None)
|
|
6001
6065
|
.set_alias(m.alias)
|
|
6002
6066
|
.set_op_params(m.operator_params or {})
|
|
6003
6067
|
.rename_columns(orig_to_hashed)
|
|
@@ -6006,40 +6070,48 @@ if response.status_code == 200:
|
|
|
6006
6070
|
self.logger.exception(f"Failed to parse AutoFE formula: {m.formula}")
|
|
6007
6071
|
continue
|
|
6008
6072
|
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6073
|
+
fold_autofe = [
|
|
6074
|
+
child
|
|
6075
|
+
for fold in _fold_model_nodes(autofe_feature)
|
|
6076
|
+
for child in fold.children
|
|
6077
|
+
if isinstance(child, Feature)
|
|
6078
|
+
and (not child.op.is_vector or isinstance(child.op, TimeSeriesBase))
|
|
6079
|
+
]
|
|
6080
|
+
if fold_autofe:
|
|
6081
|
+
hashed_to_orig = {hashed: orig for orig, hashed in orig_to_hashed.items()}
|
|
6082
|
+
for node in fold_autofe:
|
|
6083
|
+
is_ts = isinstance(node.op, TimeSeriesBase)
|
|
6084
|
+
source_names = [
|
|
6085
|
+
hashed
|
|
6086
|
+
for hashed in node.get_columns()
|
|
6087
|
+
if not is_ts or hashed_to_orig.get(hashed, hashed) not in self.fit_search_keys
|
|
6088
|
+
]
|
|
6089
|
+
self._add_autofe_description(
|
|
6090
|
+
descriptions,
|
|
6091
|
+
used_names,
|
|
6092
|
+
self._match_autofe_node_meta(node, features_meta, used_names),
|
|
6093
|
+
source_names,
|
|
6094
|
+
node.get_all_operand_names(),
|
|
6095
|
+
)
|
|
6016
6096
|
continue
|
|
6017
6097
|
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
source = feature_meta.data_source or ""
|
|
6021
|
-
description[self.bundle.get("autofe_descriptions_sources")] = source.replace(
|
|
6022
|
-
"AutoFE: features from ", ""
|
|
6023
|
-
).replace("AutoFE: feature from ", "")
|
|
6024
|
-
description[self.bundle.get("autofe_descriptions_feature_name")] = feature_meta.name
|
|
6025
|
-
|
|
6026
|
-
feature_idx = 1
|
|
6027
|
-
for bc in m.base_columns:
|
|
6028
|
-
if not is_ts or bc.original_name not in self.fit_search_keys:
|
|
6029
|
-
description[self.bundle.get("autofe_descriptions_feature").format(feature_idx)] = bc.hashed_name
|
|
6030
|
-
feature_idx += 1
|
|
6031
|
-
|
|
6032
|
-
# Don't show features with more than 2 base columns
|
|
6033
|
-
if feature_idx > 3:
|
|
6098
|
+
is_ts = isinstance(autofe_feature.op, TimeSeriesBase)
|
|
6099
|
+
if autofe_feature.op.is_vector and not is_ts:
|
|
6034
6100
|
continue
|
|
6035
6101
|
|
|
6036
|
-
|
|
6037
|
-
|
|
6102
|
+
source_names = [
|
|
6103
|
+
bc.hashed_name
|
|
6104
|
+
for bc in m.base_columns
|
|
6105
|
+
if not is_ts or bc.original_name not in self.fit_search_keys
|
|
6106
|
+
]
|
|
6107
|
+
self._add_autofe_description(
|
|
6108
|
+
descriptions,
|
|
6109
|
+
used_names,
|
|
6110
|
+
self._match_autofe_meta_by_names(_generated_feature_names(m), features_meta, used_names),
|
|
6111
|
+
source_names,
|
|
6112
|
+
autofe_feature.get_all_operand_names(),
|
|
6038
6113
|
)
|
|
6039
6114
|
|
|
6040
|
-
used_names.add(feature_meta.name)
|
|
6041
|
-
descriptions.append(description)
|
|
6042
|
-
|
|
6043
6115
|
if len(descriptions) == 0:
|
|
6044
6116
|
return None
|
|
6045
6117
|
|
|
@@ -6216,6 +6288,8 @@ if response.status_code == 200:
|
|
|
6216
6288
|
display_html_dataframe(self.metrics, self.metrics, msg)
|
|
6217
6289
|
|
|
6218
6290
|
def __show_selected_features(self):
|
|
6291
|
+
if self._has_single_ensemble_score():
|
|
6292
|
+
return
|
|
6219
6293
|
try:
|
|
6220
6294
|
_ = get_ipython() # type: ignore
|
|
6221
6295
|
|
|
@@ -7,7 +7,7 @@ from typing import Callable, Optional
|
|
|
7
7
|
import pandas as pd
|
|
8
8
|
|
|
9
9
|
from upgini.__about__ import __version__
|
|
10
|
-
from upgini.autofe.feature import Feature
|
|
10
|
+
from upgini.autofe.feature import Column, Feature
|
|
11
11
|
from upgini.autofe.vector import CatboostModel, EnsembleModel, OnnxModel
|
|
12
12
|
from upgini.metadata import BaseColumnMetadata, FeaturesMetadataV2, GeneratedFeatureMetadata
|
|
13
13
|
from upgini.report.data import (
|
|
@@ -313,26 +313,30 @@ def _overview_summary(
|
|
|
313
313
|
joined_ads_features_count: Optional[int],
|
|
314
314
|
joined_ads_count: Optional[int],
|
|
315
315
|
) -> SearchResultsSummary:
|
|
316
|
-
top_level =
|
|
316
|
+
top_level = _unique_fold_model_inputs(generated_features)
|
|
317
317
|
features_by_name = {meta.name: meta for meta in features_meta}
|
|
318
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)
|
|
319
321
|
if top_level:
|
|
320
322
|
counts = {"external": 0, "original": 0, "autofe": 0}
|
|
321
|
-
ads_ids: set[str] = set()
|
|
322
323
|
psis: list[Optional[float]] = []
|
|
323
|
-
for
|
|
324
|
-
kind = _top_level_kind(
|
|
324
|
+
for node in top_level:
|
|
325
|
+
kind = _top_level_kind(node, features_by_name, columns_by_name, autofe_by_name, is_ensemble)
|
|
325
326
|
counts[kind] += 1
|
|
326
|
-
|
|
327
|
-
meta = features_by_name.get(column.hashed_name) or features_by_name.get(column.original_name)
|
|
327
|
+
meta = _feature_meta_for_node(node, features_by_name, columns_by_name)
|
|
328
328
|
psis.append(None if meta is None else meta.psi_value)
|
|
329
329
|
model_features = len(top_level)
|
|
330
330
|
external, original, autofe = counts["external"], counts["original"], counts["autofe"]
|
|
331
|
-
contributed = len(ads_ids)
|
|
331
|
+
contributed = len(ads_ids or set())
|
|
332
332
|
else:
|
|
333
333
|
model_features = len(model_rows) or None
|
|
334
334
|
external = original = autofe = None
|
|
335
|
-
contributed =
|
|
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
|
+
)
|
|
336
340
|
psis = [row.psi for row in model_rows]
|
|
337
341
|
share, stable, psi_count = _stability_from_psi(psis)
|
|
338
342
|
return SearchResultsSummary(
|
|
@@ -351,17 +355,66 @@ def _overview_summary(
|
|
|
351
355
|
)
|
|
352
356
|
|
|
353
357
|
|
|
354
|
-
def
|
|
355
|
-
unique: dict[str,
|
|
358
|
+
def _unique_fold_model_inputs(generated_features: list[GeneratedFeatureMetadata]) -> list[Column | Feature]:
|
|
359
|
+
unique: dict[str, Column | Feature] = {}
|
|
356
360
|
for meta in generated_features:
|
|
357
361
|
feature = _parse_generated_feature(meta)
|
|
358
|
-
if feature is None
|
|
362
|
+
if feature is None:
|
|
359
363
|
continue
|
|
360
|
-
for
|
|
361
|
-
|
|
364
|
+
for fold in _fold_model_nodes(feature):
|
|
365
|
+
for child in fold.children:
|
|
366
|
+
unique.setdefault(_top_level_key(child), child)
|
|
362
367
|
return list(unique.values())
|
|
363
368
|
|
|
364
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
|
+
|
|
365
418
|
def _autofe_generated_by_name(
|
|
366
419
|
generated_features: list[GeneratedFeatureMetadata], is_ensemble: Callable[[str], bool]
|
|
367
420
|
) -> dict[str, GeneratedFeatureMetadata]:
|
|
@@ -400,13 +453,16 @@ def _generated_feature_names(meta: GeneratedFeatureMetadata) -> set[str]:
|
|
|
400
453
|
|
|
401
454
|
|
|
402
455
|
def _top_level_kind(
|
|
403
|
-
|
|
456
|
+
node: Column | Feature,
|
|
404
457
|
features_by_name: dict[str, FeaturesMetadataV2],
|
|
458
|
+
columns_by_name: dict[str, BaseColumnMetadata],
|
|
405
459
|
autofe_by_name: dict[str, GeneratedFeatureMetadata],
|
|
406
460
|
is_ensemble: Callable[[str], bool],
|
|
407
461
|
) -> str:
|
|
408
|
-
|
|
409
|
-
|
|
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):
|
|
410
466
|
return "autofe"
|
|
411
467
|
meta = next((features_by_name[name] for name in names if name in features_by_name), None)
|
|
412
468
|
if meta is not None and not is_ensemble(meta.name):
|
|
@@ -416,11 +472,28 @@ def _top_level_kind(
|
|
|
416
472
|
return "external"
|
|
417
473
|
if meta.source == "etalon":
|
|
418
474
|
return "original"
|
|
419
|
-
if
|
|
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:
|
|
420
477
|
return "external"
|
|
421
478
|
return "original"
|
|
422
479
|
|
|
423
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
|
+
|
|
424
497
|
def _leaf_ads_ids(column: BaseColumnMetadata, autofe_by_name: dict[str, GeneratedFeatureMetadata]) -> set[str]:
|
|
425
498
|
autofe = autofe_by_name.get(column.hashed_name) or autofe_by_name.get(column.original_name)
|
|
426
499
|
leaves = autofe.base_columns if autofe is not None else [column]
|
|
@@ -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>
|
|
@@ -510,9 +511,9 @@ const REPORT_DATA = __REPORT_DATA__;
|
|
|
510
511
|
const maxImportance = Math.max(...features.map(f => f.importance)) || 1;
|
|
511
512
|
const list = shapAll ? features : features.slice(0, (D.shap && D.shap.topN) || features.length);
|
|
512
513
|
document.getElementById('shapList').innerHTML = list.map((f, i) =>
|
|
513
|
-
`<div class="shap-row"><div><b>#${i + 1} ${f.name}</b>${providerBadge(f.provider)}</div>` +
|
|
514
|
+
`<div class="shap-row"><div class="shap-name"><b>#${i + 1} ${f.name}</b>${providerBadge(f.provider)}</div>` +
|
|
514
515
|
`<div class="shap-track"><i class="shap-fill ${f.shapClass || 'upgini'}" style="width:${(f.importance / maxImportance * 100).toFixed(2)}%"></i></div>` +
|
|
515
|
-
`<b>${fmt3(Math.abs(f.shap))}</b></div>`).join('');
|
|
516
|
+
`<b class="shap-value">${fmt3(Math.abs(f.shap))}</b></div>`).join('');
|
|
516
517
|
document.getElementById('showAllShap').textContent = shapAll ? `Show top ${(D.shap && D.shap.topN) || features.length}` : `Show all ${features.length}`;
|
|
517
518
|
}
|
|
518
519
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.2.167.a4220.dev9"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/ads_management/__init__.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/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.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/cross.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/delta.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/numpy_kernels.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/autofe/timeseries/trend.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/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.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/normalizer/normalize_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/resource_bundle/__init__.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/resource_bundle/exceptions.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/resource_bundle/strings.properties
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/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.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/base_search_key_detector.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/blocked_time_series.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/custom_loss_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/deduplicate_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/src/upgini/utils/fallback_progress_bar.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev11}/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.dev9 → upgini-1.2.167a4220.dev11}/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.dev9 → upgini-1.2.167a4220.dev11}/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
|