upgini 1.2.159a4156.dev2__tar.gz → 1.2.159a4156.dev3__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.
Files changed (86) hide show
  1. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/PKG-INFO +1 -1
  2. upgini-1.2.159a4156.dev3/src/upgini/__about__.py +1 -0
  3. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/features_enricher.py +28 -11
  4. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/sample_utils.py +36 -37
  5. upgini-1.2.159a4156.dev2/src/upgini/__about__.py +0 -1
  6. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/.gitignore +0 -0
  7. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/LICENSE +0 -0
  8. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/README.md +0 -0
  9. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/pyproject.toml +0 -0
  10. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/__init__.py +0 -0
  11. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/ads.py +0 -0
  12. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/ads_management/__init__.py +0 -0
  13. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/ads_management/ads_manager.py +0 -0
  14. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/__init__.py +0 -0
  15. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/all_operators.py +0 -0
  16. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/binary.py +0 -0
  17. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/date.py +0 -0
  18. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/feature.py +0 -0
  19. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/groupby.py +0 -0
  20. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/operand.py +0 -0
  21. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/operator.py +0 -0
  22. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/timeseries/__init__.py +0 -0
  23. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/timeseries/base.py +0 -0
  24. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/timeseries/cross.py +0 -0
  25. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/timeseries/delta.py +0 -0
  26. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/timeseries/lag.py +0 -0
  27. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/timeseries/roll.py +0 -0
  28. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/timeseries/trend.py +0 -0
  29. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/timeseries/volatility.py +0 -0
  30. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/unary.py +0 -0
  31. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/utils.py +0 -0
  32. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/autofe/vector.py +0 -0
  33. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/data_source/__init__.py +0 -0
  34. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/data_source/data_source_publisher.py +0 -0
  35. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/dataset.py +0 -0
  36. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/errors.py +0 -0
  37. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/http.py +0 -0
  38. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/mdc/__init__.py +0 -0
  39. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/mdc/context.py +0 -0
  40. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/metadata.py +0 -0
  41. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/metrics.py +0 -0
  42. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/normalizer/__init__.py +0 -0
  43. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/normalizer/normalize_utils.py +0 -0
  44. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/resource_bundle/__init__.py +0 -0
  45. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/resource_bundle/exceptions.py +0 -0
  46. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/resource_bundle/strings.properties +0 -0
  47. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/resource_bundle/strings_widget.properties +0 -0
  48. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/sampler/__init__.py +0 -0
  49. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/sampler/base.py +0 -0
  50. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/sampler/random_under_sampler.py +0 -0
  51. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/sampler/utils.py +0 -0
  52. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/search_task.py +0 -0
  53. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/spinner.py +0 -0
  54. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/Roboto-Regular.ttf +0 -0
  55. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/__init__.py +0 -0
  56. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/base_search_key_detector.py +0 -0
  57. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/blocked_time_series.py +0 -0
  58. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/config.py +0 -0
  59. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/country_utils.py +0 -0
  60. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/cpu_utils.py +0 -0
  61. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/custom_loss_utils.py +0 -0
  62. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/cv_utils.py +0 -0
  63. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/datetime_utils.py +0 -0
  64. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/deduplicate_utils.py +0 -0
  65. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/display_utils.py +0 -0
  66. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/email_utils.py +0 -0
  67. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/fallback_progress_bar.py +0 -0
  68. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/feature_info.py +0 -0
  69. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/features_validator.py +0 -0
  70. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/format.py +0 -0
  71. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/hash_utils.py +0 -0
  72. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/ip_utils.py +0 -0
  73. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/mstats.py +0 -0
  74. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/one_hot_encoder.py +0 -0
  75. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/phone_utils.py +0 -0
  76. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/postal_code_utils.py +0 -0
  77. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/progress_bar.py +0 -0
  78. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/psi.py +0 -0
  79. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/pyarrow_utils.py +0 -0
  80. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/sklearn_ext.py +0 -0
  81. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/sort.py +0 -0
  82. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/target_utils.py +0 -0
  83. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/track_info.py +0 -0
  84. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/ts_utils.py +0 -0
  85. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/src/upgini/utils/warning_counter.py +0 -0
  86. {upgini-1.2.159a4156.dev2 → upgini-1.2.159a4156.dev3}/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.159a4156.dev2
3
+ Version: 1.2.159a4156.dev3
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.159.a4156.dev3"
@@ -2017,6 +2017,18 @@ class FeaturesEnricher(TransformerMixin):
2017
2017
  resolved, _ = self._resolve_client_features_in_sampled(etalon_columns, columns_renaming, available_columns)
2018
2018
  return resolved
2019
2019
 
2020
+ @staticmethod
2021
+ def _column_name_aliases(names: list[str] | set[str] | tuple[str, ...], columns_renaming: dict[str, str]) -> set[str]:
2022
+ """Return names in both hashed and original forms for exclusion matching."""
2023
+ hashed_to_original = dict(columns_renaming)
2024
+ original_to_hashed = {original: hashed for hashed, original in columns_renaming.items()}
2025
+ aliases: set[str] = set()
2026
+ for name in names:
2027
+ aliases.add(name)
2028
+ aliases.add(hashed_to_original.get(name, name))
2029
+ aliases.add(original_to_hashed.get(name, name))
2030
+ return aliases
2031
+
2020
2032
  def _get_cached_enriched_data(
2021
2033
  self,
2022
2034
  X: pd.DataFrame | pd.Series | np.ndarray | None = None,
@@ -2066,15 +2078,18 @@ class FeaturesEnricher(TransformerMixin):
2066
2078
  file_meta = self._search_task.get_file_metadata(self._get_trace_id())
2067
2079
  fit_dropped_features = list(self.fit_dropped_features or file_meta.droppedColumns or [])
2068
2080
  renamed_to_original = dict(columns_renaming)
2069
- original_to_renamed = {original: hashed for hashed, original in columns_renaming.items()}
2070
- excluding_search_keys_original = [renamed_to_original.get(sk, sk) for sk in excluding_search_keys]
2071
2081
 
2072
- excluded_client_columns = (
2073
- excluding_search_keys_original
2082
+ # Exclude search keys / system cols in both hashed and original name forms.
2083
+ excluded_client_columns = self._column_name_aliases(
2084
+ list(excluding_search_keys)
2074
2085
  + fit_dropped_features
2075
- + [DateTimeConverter.DATETIME_COL, SYSTEM_RECORD_ID, ENTITY_SYSTEM_RECORD_ID]
2086
+ + [DateTimeConverter.DATETIME_COL, SYSTEM_RECORD_ID, ENTITY_SYSTEM_RECORD_ID],
2087
+ columns_renaming,
2088
+ )
2089
+ # Baseline should not use search-key-derived generated features (e.g. datetime cyclical).
2090
+ excluded_baseline_columns = excluded_client_columns | self._column_name_aliases(
2091
+ generated_features, columns_renaming
2076
2092
  )
2077
- excluded_client_columns_renamed = {original_to_renamed.get(c, c) for c in excluded_client_columns}
2078
2093
 
2079
2094
  # Client columns for enriched metrics (respects select_features).
2080
2095
  client_features = [
@@ -2104,11 +2119,10 @@ class FeaturesEnricher(TransformerMixin):
2104
2119
  if columns_renaming.get(c, c) in enriched_X_sorted.columns
2105
2120
  ]
2106
2121
 
2107
- # Baseline always uses all etalon columns available in the sample (ignores select_features).
2122
+ etalon_columns_in_sampled = self._get_etalon_columns_renamed(columns_renaming, X_sorted.columns)
2123
+ # Baseline: all etalon columns except search keys and generated (cyclical) features.
2108
2124
  baseline_client_features_in_sampled = [
2109
- c
2110
- for c in self._get_etalon_columns_renamed(columns_renaming, X_sorted.columns)
2111
- if c not in excluded_client_columns_renamed
2125
+ c for c in etalon_columns_in_sampled if c not in excluded_baseline_columns
2112
2126
  ]
2113
2127
  self.logger.info(f"Baseline etalon columns for metrics: {baseline_client_features_in_sampled}")
2114
2128
  if self.fit_select_features:
@@ -2116,7 +2130,10 @@ class FeaturesEnricher(TransformerMixin):
2116
2130
  client_features, columns_renaming, X_sorted.columns
2117
2131
  )
2118
2132
  else:
2119
- enriched_client_features_in_sampled = baseline_client_features_in_sampled
2133
+ # Enriched may still use generated features; baseline does not.
2134
+ enriched_client_features_in_sampled = [
2135
+ c for c in etalon_columns_in_sampled if c not in excluded_client_columns
2136
+ ]
2120
2137
  missing_client_features = set()
2121
2138
  if missing_client_features:
2122
2139
  self.logger.warning(
@@ -9,7 +9,6 @@ import pandas as pd
9
9
  from upgini.metadata import (
10
10
  EVAL_SET_INDEX,
11
11
  SYSTEM_RECORD_ID,
12
- TARGET,
13
12
  CVType,
14
13
  ModelTaskType,
15
14
  )
@@ -106,49 +105,49 @@ def sample(
106
105
  **kwargs,
107
106
  )
108
107
 
109
- # Combine balanced train with eval sets
110
- if len(eval_sets_dfs) > 0:
111
- df = pd.concat([train_df] + eval_sets_dfs, ignore_index=False)
112
- else:
113
- df = train_df
108
+ # Downsample train and each eval set independently (same cap as former OOT path)
109
+ parts: List[tuple[str, pd.DataFrame]] = [("Train", train_df)]
110
+ for eval_df in eval_sets_dfs:
111
+ eval_idx = eval_df[EVAL_SET_INDEX].iloc[0]
112
+ parts.append((f"Eval set {int(eval_idx)}", eval_df))
113
+
114
+ sampled_parts = [
115
+ _threshold_sample(
116
+ part_df,
117
+ fit_sample_threshold,
118
+ fit_sample_rows,
119
+ random_state,
120
+ logger,
121
+ part_name,
122
+ )
123
+ for part_name, part_df in parts
124
+ ]
125
+ df = pd.concat(sampled_parts, ignore_index=False) if len(sampled_parts) > 1 else sampled_parts[0]
126
+
127
+ if logger is not None:
128
+ logger.info(f"Dataset size after downsampling: {len(df)}")
129
+
130
+ return df
114
131
 
115
- # separate OOT
116
- oot_dfs = []
117
- other_dfs = []
118
- if EVAL_SET_INDEX in df.columns:
119
- for eval_set_index in df[EVAL_SET_INDEX].unique():
120
- eval_df = df[df[EVAL_SET_INDEX] == eval_set_index]
121
- if TARGET in eval_df.columns and eval_df[TARGET].isna().all():
122
- oot_dfs.append(eval_df)
123
- else:
124
- other_dfs.append(eval_df)
125
- if len(oot_dfs) > 0:
126
- oot_df = pd.concat(oot_dfs, ignore_index=False)
127
- df = pd.concat(other_dfs, ignore_index=False)
128
- else:
129
- oot_df = None
130
132
 
133
+ def _threshold_sample(
134
+ df: pd.DataFrame,
135
+ fit_sample_threshold: int,
136
+ fit_sample_rows: int,
137
+ random_state: int,
138
+ logger: Optional[logging.Logger],
139
+ part_name: str,
140
+ ) -> pd.DataFrame:
131
141
  num_samples = _num_samples(df)
132
142
  if num_samples > fit_sample_threshold:
133
- logger.info(
134
- f"Etalon has size {num_samples} more than threshold {fit_sample_threshold} "
135
- f"and will be downsampled to {fit_sample_rows}"
136
- )
137
- df = df.sample(n=fit_sample_rows, random_state=random_state)
138
- logger.info(f"Shape after threshold resampling: {df.shape}")
139
-
140
- if oot_df is not None:
141
- num_samples_oot = _num_samples(oot_df)
142
- if num_samples_oot > fit_sample_threshold:
143
+ if logger is not None:
143
144
  logger.info(
144
- f"OOT has size {num_samples_oot} more than threshold {fit_sample_threshold} "
145
+ f"{part_name} has size {num_samples} more than threshold {fit_sample_threshold} "
145
146
  f"and will be downsampled to {fit_sample_rows}"
146
147
  )
147
- oot_df = oot_df.sample(n=fit_sample_rows, random_state=random_state)
148
- df = pd.concat([df, oot_df], ignore_index=False)
149
-
150
- logger.info(f"Dataset size after downsampling: {len(df)}")
151
-
148
+ df = df.sample(n=fit_sample_rows, random_state=random_state)
149
+ if logger is not None:
150
+ logger.info(f"Shape after threshold resampling ({part_name}): {df.shape}")
152
151
  return df
153
152
 
154
153
 
@@ -1 +0,0 @@
1
- __version__ = "1.2.159.a4156.dev2"