upgini 1.2.167a4220.dev9__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.dev9 → upgini-1.2.167a4220.dev10}/PKG-INFO +1 -1
- upgini-1.2.167a4220.dev10/src/upgini/__about__.py +1 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/features_enricher.py +75 -34
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/report/assemble.py +91 -18
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/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.dev10}/.gitignore +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/LICENSE +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/README.md +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/pyproject.toml +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/ads.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/ads_management/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/ads_management/ads_manager.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/all_operators.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/binary.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/date.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/feature.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/groupby.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/operand.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/operator.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/base.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/cross.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/delta.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/lag.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/numpy_kernels.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/roll.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/trend.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/volatility.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/unary.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/vector.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/data_source/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/data_source/data_source_publisher.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/dataset.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/errors.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/http.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/mdc/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/mdc/context.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/metadata.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/metrics.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/normalizer/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/normalizer/normalize_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/report/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/report/data.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/report/html.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/report/stats.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/exceptions.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/strings.properties +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/strings_widget.properties +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/sampler/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/sampler/base.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/sampler/random_under_sampler.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/sampler/utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/search_task.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/spinner.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/Roboto-Regular.ttf +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/__init__.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/base_search_key_detector.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/blocked_time_series.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/config.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/country_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/cpu_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/custom_loss_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/cv_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/datetime_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/deduplicate_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/display_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/email_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/fallback_progress_bar.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/feature_info.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/features_validator.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/format.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/hash_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/ip_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/mstats.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/one_hot_encoder.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/phone_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/postal_code_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/progress_bar.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/psi.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/pyarrow_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/sample_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/search_key_derivations.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/sklearn_ext.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/sort.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/target_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/track_info.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/ts_utils.py +0 -0
- {upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/warning_counter.py +0 -0
- {upgini-1.2.167a4220.dev9 → 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"
|
|
@@ -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,48 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
2513
2514
|
return False
|
|
2514
2515
|
return bool(aliases & self._column_name_aliases(list(ensemble_names), renaming))
|
|
2515
2516
|
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2517
|
+
@staticmethod
|
|
2518
|
+
def _match_autofe_meta_by_names(
|
|
2519
|
+
names: set[str],
|
|
2519
2520
|
features_meta: list[FeaturesMetadataV2],
|
|
2520
2521
|
used_names: set[str],
|
|
2521
2522
|
) -> FeaturesMetadataV2 | None:
|
|
2522
2523
|
available = [meta for meta in features_meta or [] if meta.name not in used_names]
|
|
2523
2524
|
by_name = {meta.name: meta for meta in available}
|
|
2524
|
-
for name in
|
|
2525
|
+
for name in names:
|
|
2525
2526
|
matched = by_name.get(name)
|
|
2526
2527
|
if matched is not None:
|
|
2527
2528
|
return matched
|
|
2528
2529
|
return None
|
|
2529
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
|
+
|
|
2530
2559
|
def _ensemble_generated_metadata(self):
|
|
2531
2560
|
autofe_meta = self._search_task.get_autofe_metadata() if self._search_task else None
|
|
2532
2561
|
if not autofe_meta:
|
|
@@ -5995,9 +6024,11 @@ if response.status_code == 200:
|
|
|
5995
6024
|
orig_to_hashed = {
|
|
5996
6025
|
base_column.original_name: base_column.hashed_name for base_column in m.base_columns
|
|
5997
6026
|
}
|
|
6027
|
+
parsed = Feature.from_formula(m.formula)
|
|
6028
|
+
if not isinstance(parsed, Feature):
|
|
6029
|
+
continue
|
|
5998
6030
|
autofe_feature = (
|
|
5999
|
-
|
|
6000
|
-
.set_display_index(m.display_index or None)
|
|
6031
|
+
parsed.set_display_index(m.display_index or None)
|
|
6001
6032
|
.set_alias(m.alias)
|
|
6002
6033
|
.set_op_params(m.operator_params or {})
|
|
6003
6034
|
.rename_columns(orig_to_hashed)
|
|
@@ -6006,40 +6037,48 @@ if response.status_code == 200:
|
|
|
6006
6037
|
self.logger.exception(f"Failed to parse AutoFE formula: {m.formula}")
|
|
6007
6038
|
continue
|
|
6008
6039
|
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
if
|
|
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
|
+
)
|
|
6016
6063
|
continue
|
|
6017
6064
|
|
|
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:
|
|
6065
|
+
is_ts = isinstance(autofe_feature.op, TimeSeriesBase)
|
|
6066
|
+
if autofe_feature.op.is_vector and not is_ts:
|
|
6034
6067
|
continue
|
|
6035
6068
|
|
|
6036
|
-
|
|
6037
|
-
|
|
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(),
|
|
6038
6080
|
)
|
|
6039
6081
|
|
|
6040
|
-
used_names.add(feature_meta.name)
|
|
6041
|
-
descriptions.append(description)
|
|
6042
|
-
|
|
6043
6082
|
if len(descriptions) == 0:
|
|
6044
6083
|
return None
|
|
6045
6084
|
|
|
@@ -6216,6 +6255,8 @@ if response.status_code == 200:
|
|
|
6216
6255
|
display_html_dataframe(self.metrics, self.metrics, msg)
|
|
6217
6256
|
|
|
6218
6257
|
def __show_selected_features(self):
|
|
6258
|
+
if self._has_single_ensemble_score():
|
|
6259
|
+
return
|
|
6219
6260
|
try:
|
|
6220
6261
|
_ = get_ipython() # type: ignore
|
|
6221
6262
|
|
|
@@ -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.dev10}/src/upgini/ads_management/__init__.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → 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.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/cross.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/delta.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/numpy_kernels.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/autofe/timeseries/trend.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → 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
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/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.dev10}/src/upgini/resource_bundle/__init__.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/resource_bundle/exceptions.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → 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.dev9 → 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
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/base_search_key_detector.py
RENAMED
|
File without changes
|
{upgini-1.2.167a4220.dev9 → 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.dev9 → 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.dev9 → 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.dev9 → upgini-1.2.167a4220.dev10}/src/upgini/utils/fallback_progress_bar.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.2.167a4220.dev9 → 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.dev9 → 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.dev9 → 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
|