upgini 1.2.156.dev2__tar.gz → 1.2.156.dev4__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 (83) hide show
  1. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/PKG-INFO +1 -1
  2. upgini-1.2.156.dev4/src/upgini/__about__.py +1 -0
  3. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/date.py +197 -42
  4. upgini-1.2.156.dev2/src/upgini/__about__.py +0 -1
  5. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/.gitignore +0 -0
  6. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/LICENSE +0 -0
  7. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/README.md +0 -0
  8. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/pyproject.toml +0 -0
  9. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/__init__.py +0 -0
  10. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/ads.py +0 -0
  11. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/ads_management/__init__.py +0 -0
  12. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/ads_management/ads_manager.py +0 -0
  13. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/__init__.py +0 -0
  14. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/all_operators.py +0 -0
  15. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/binary.py +0 -0
  16. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/feature.py +0 -0
  17. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/groupby.py +0 -0
  18. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/operator.py +0 -0
  19. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/timeseries/__init__.py +0 -0
  20. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/timeseries/base.py +0 -0
  21. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/timeseries/cross.py +0 -0
  22. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/timeseries/delta.py +0 -0
  23. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/timeseries/lag.py +0 -0
  24. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/timeseries/roll.py +0 -0
  25. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/timeseries/trend.py +0 -0
  26. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/timeseries/volatility.py +0 -0
  27. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/unary.py +0 -0
  28. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/utils.py +0 -0
  29. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/autofe/vector.py +0 -0
  30. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/data_source/__init__.py +0 -0
  31. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/data_source/data_source_publisher.py +0 -0
  32. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/dataset.py +0 -0
  33. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/errors.py +0 -0
  34. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/features_enricher.py +0 -0
  35. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/http.py +0 -0
  36. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/mdc/__init__.py +0 -0
  37. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/mdc/context.py +0 -0
  38. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/metadata.py +0 -0
  39. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/metrics.py +0 -0
  40. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/normalizer/__init__.py +0 -0
  41. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/normalizer/normalize_utils.py +0 -0
  42. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/resource_bundle/__init__.py +0 -0
  43. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/resource_bundle/exceptions.py +0 -0
  44. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/resource_bundle/strings.properties +0 -0
  45. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/resource_bundle/strings_widget.properties +0 -0
  46. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/sampler/__init__.py +0 -0
  47. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/sampler/base.py +0 -0
  48. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/sampler/random_under_sampler.py +0 -0
  49. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/sampler/utils.py +0 -0
  50. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/search_task.py +0 -0
  51. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/spinner.py +0 -0
  52. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/Roboto-Regular.ttf +0 -0
  53. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/__init__.py +0 -0
  54. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/base_search_key_detector.py +0 -0
  55. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/blocked_time_series.py +0 -0
  56. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/config.py +0 -0
  57. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/country_utils.py +0 -0
  58. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/custom_loss_utils.py +0 -0
  59. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/cv_utils.py +0 -0
  60. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/datetime_utils.py +0 -0
  61. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/deduplicate_utils.py +0 -0
  62. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/display_utils.py +0 -0
  63. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/email_utils.py +0 -0
  64. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/fallback_progress_bar.py +0 -0
  65. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/feature_info.py +0 -0
  66. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/features_validator.py +0 -0
  67. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/format.py +0 -0
  68. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/hash_utils.py +0 -0
  69. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/ip_utils.py +0 -0
  70. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/mstats.py +0 -0
  71. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/one_hot_encoder.py +0 -0
  72. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/phone_utils.py +0 -0
  73. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/postal_code_utils.py +0 -0
  74. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/progress_bar.py +0 -0
  75. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/psi.py +0 -0
  76. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/sample_utils.py +0 -0
  77. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/sklearn_ext.py +0 -0
  78. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/sort.py +0 -0
  79. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/target_utils.py +0 -0
  80. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/track_info.py +0 -0
  81. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/ts_utils.py +0 -0
  82. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/utils/warning_counter.py +0 -0
  83. {upgini-1.2.156.dev2 → upgini-1.2.156.dev4}/src/upgini/version_validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: upgini
3
- Version: 1.2.156.dev2
3
+ Version: 1.2.156.dev4
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.156.dev4"
@@ -113,6 +113,172 @@ _ext_aggregations = {"nunique": (lambda x: len(np.unique(x)), 0), "count": (len,
113
113
  _count_aggregations = ["nunique", "count"]
114
114
 
115
115
 
116
+ def _aggregate_diffs(values: np.ndarray, aggregation: str) -> float:
117
+ values = np.atleast_1d(np.asarray(values, dtype=np.float64))
118
+ method = getattr(np, aggregation, None)
119
+ default = np.nan
120
+ if method is None and aggregation in _ext_aggregations:
121
+ method, default = _ext_aggregations[aggregation]
122
+ elif not callable(method):
123
+ raise ValueError(f"Unsupported aggregation: {aggregation}")
124
+
125
+ return method(values) if len(values) > 0 else default
126
+
127
+
128
+ class DateListDiffLists(PandasOperator, DateDiffMixin, ParametrizedOperator):
129
+ name: str = "date_diff_lists"
130
+ is_binary: bool = True
131
+ has_symmetry_importance: bool = True
132
+ output_type: Optional[str] = "vector"
133
+
134
+ replace_negative: bool = False
135
+
136
+ def get_params(self) -> Dict[str, Optional[str]]:
137
+ res = super().get_params()
138
+ res.update(
139
+ {
140
+ "diff_unit": self.diff_unit,
141
+ "left_unit": self.left_unit,
142
+ "right_unit": self.right_unit,
143
+ "replace_negative": self.replace_negative,
144
+ }
145
+ )
146
+ return res
147
+
148
+ def to_formula(self) -> str:
149
+ return f"date_diff_lists_{self.diff_unit}"
150
+
151
+ @classmethod
152
+ def from_formula(cls, formula: str) -> Optional["DateListDiffLists"]:
153
+ if formula == "date_diff_lists":
154
+ return cls()
155
+ if formula.startswith("date_diff_lists_"):
156
+ diff_unit = formula.replace("date_diff_lists_", "")
157
+ if diff_unit in {"D", "Y"}:
158
+ return cls(diff_unit=diff_unit)
159
+ return None
160
+
161
+ @staticmethod
162
+ def _non_empty_list_mask(right: pd.Series) -> pd.Series:
163
+ values = right.to_numpy()
164
+ mask = np.empty(len(values), dtype=bool)
165
+ for i, value in enumerate(values):
166
+ if value is None or (isinstance(value, float) and np.isnan(value)):
167
+ mask[i] = False
168
+ elif isinstance(value, (list, tuple, np.ndarray)):
169
+ mask[i] = len(value) > 0
170
+ else:
171
+ mask[i] = False
172
+ return pd.Series(mask, index=right.index)
173
+
174
+ def _convert_date_lists(self, lists: pd.Series) -> pd.Series:
175
+ exploded = lists.explode()
176
+ converted = pd.to_datetime(exploded, unit=self.right_unit, errors="coerce")
177
+ return pd.Series(
178
+ {
179
+ idx: pd.arrays.DatetimeArray(values.to_numpy())
180
+ for idx, values in converted.groupby(converted.index, sort=False)
181
+ }
182
+ )
183
+
184
+ def _row_diffs(self, left_date, right_dates: pd.arrays.DatetimeArray) -> List[float]:
185
+ diffs = self._convert_diff_to_unit(left_date - right_dates)
186
+ if self.replace_negative:
187
+ diffs = diffs[diffs > 0]
188
+ return np.atleast_1d(np.asarray(diffs, dtype=np.float64)).tolist()
189
+
190
+ def calculate_binary(self, left: pd.Series, right: pd.Series) -> pd.Series:
191
+ if left.isna().all() or right.isna().all():
192
+ return pd.Series([None] * len(left), index=left.index, dtype=object)
193
+
194
+ left = self._convert_to_date(left, self.left_unit)
195
+ right_mask = self._non_empty_list_mask(right)
196
+ mask = left.notna() & right.notna() & right_mask
197
+
198
+ results = pd.Series([None] * len(left), index=left.index, dtype=object)
199
+ if not mask.any():
200
+ return results
201
+
202
+ masked_left = left[mask]
203
+ converted_lists = self._convert_date_lists(right[mask])
204
+ for idx, left_date in masked_left.items():
205
+ results.loc[idx] = self._row_diffs(left_date, converted_lists[idx])
206
+ return results
207
+
208
+
209
+ class DateListDiffAggWithinBounds(PandasOperator, ParametrizedOperator):
210
+ name: str = "date_diff_list_agg"
211
+ is_unary: bool = True
212
+ output_type: Optional[str] = "float"
213
+
214
+ lower_bound: Optional[int] = None
215
+ upper_bound: Optional[int] = None
216
+ aggregation: str
217
+ normalize: Optional[bool] = None
218
+
219
+ def get_params(self) -> Dict[str, Optional[str]]:
220
+ res = super().get_params()
221
+ res.update(
222
+ {
223
+ "aggregation": self.aggregation,
224
+ "lower_bound": str(self.lower_bound) if self.lower_bound is not None else None,
225
+ "upper_bound": str(self.upper_bound) if self.upper_bound is not None else None,
226
+ "normalize": str(self.normalize) if self.normalize is not None else None,
227
+ }
228
+ )
229
+ return res
230
+
231
+ def to_formula(self) -> str:
232
+ lower_bound = "minusinf" if self.lower_bound is None else self.lower_bound
233
+ upper_bound = "plusinf" if self.upper_bound is None else self.upper_bound
234
+ norm = "_norm" if self.normalize else ""
235
+ return f"date_diff_list_agg_{lower_bound}_{upper_bound}_{self.aggregation}{norm}"
236
+
237
+ @classmethod
238
+ def from_formula(cls, formula: str) -> Optional["DateListDiffAggWithinBounds"]:
239
+ import re
240
+
241
+ normalize = formula.endswith("_norm")
242
+ formula = formula.replace("_norm", "")
243
+
244
+ pattern = r"^date_diff_list_agg_((minusinf|\d+))_((plusinf|\d+))_(\w+)$"
245
+ match = re.match(pattern, formula)
246
+ if not match:
247
+ return None
248
+
249
+ lower_bound = None if match.group(1) == "minusinf" else int(match.group(1))
250
+ upper_bound = None if match.group(3) == "plusinf" else int(match.group(3))
251
+ aggregation = match.group(5)
252
+ return cls(
253
+ lower_bound=lower_bound,
254
+ upper_bound=upper_bound,
255
+ aggregation=aggregation,
256
+ normalize=normalize,
257
+ )
258
+
259
+ def _aggregate_row(self, diffs) -> float:
260
+ if diffs is None or (isinstance(diffs, float) and np.isnan(diffs)):
261
+ return np.nan
262
+
263
+ diffs = np.atleast_1d(np.asarray(diffs, dtype=np.float64))
264
+ orig_len = len(diffs)
265
+ if self.lower_bound is not None or self.upper_bound is not None:
266
+ lower = self.lower_bound if self.lower_bound is not None else -np.inf
267
+ upper = self.upper_bound if self.upper_bound is not None else np.inf
268
+ diffs = diffs[(diffs >= lower) & (diffs < upper)]
269
+ agg_res = _aggregate_diffs(diffs, self.aggregation)
270
+ if self.normalize and orig_len > 0:
271
+ return agg_res / orig_len
272
+ return agg_res
273
+
274
+ def calculate_unary(self, data: pd.Series) -> pd.Series:
275
+ results = np.empty(len(data), dtype=np.float64)
276
+ results[:] = np.nan
277
+ for i, diffs in enumerate(data.to_numpy()):
278
+ results[i] = self._aggregate_row(diffs)
279
+ return pd.Series(results, index=data.index, dtype=np.float64)
280
+
281
+
116
282
  class DateListDiff(PandasOperator, DateDiffMixin, ParametrizedOperator):
117
283
  is_binary: bool = True
118
284
  has_symmetry_importance: bool = True
@@ -145,43 +311,35 @@ class DateListDiff(PandasOperator, DateDiffMixin, ParametrizedOperator):
145
311
  return None
146
312
  return cls(aggregation=aggregation)
147
313
 
148
- def calculate_binary(self, left: pd.Series, right: pd.Series) -> pd.Series:
149
- if left.isna().all() or right.isna().all():
150
- return pd.Series([None] * len(left), index=left.index, dtype=np.float64)
314
+ def _lists_op(self) -> DateListDiffLists:
315
+ return DateListDiffLists(
316
+ diff_unit=self.diff_unit,
317
+ left_unit=self.left_unit,
318
+ right_unit=self.right_unit,
319
+ replace_negative=self.replace_negative,
320
+ )
151
321
 
152
- left = self._convert_to_date(left, self.left_unit)
153
- right_mask = right.apply(lambda x: len(x) > 0)
154
- mask = left.notna() & right.notna() & right_mask
155
- right_masked = right[mask].apply(lambda x: pd.arrays.DatetimeArray(self._convert_to_date(x, self.right_unit)))
322
+ def _agg_op(self) -> DateListDiffAggWithinBounds:
323
+ return DateListDiffAggWithinBounds(
324
+ lower_bound=None,
325
+ upper_bound=None,
326
+ aggregation=self.aggregation,
327
+ normalize=False,
328
+ )
156
329
 
157
- if len(right_masked) == 0:
158
- diff = []
159
- elif len(right_masked) < 2:
160
- diff = [left[mask].iloc[0] - right_masked.iloc[0]]
161
- else:
162
- diff = left[mask] - right_masked.values
330
+ def _compose_list_diff(self, left: pd.Series, right: pd.Series) -> pd.Series:
331
+ if left.isna().all() or right.isna().all():
332
+ return pd.Series([None] * len(left), index=left.index, dtype=np.float64)
163
333
 
164
- res_masked = pd.Series(diff, index=left[mask].index).apply(lambda x: self._agg(self._diff(x)))
165
- res = res_masked.reindex(left.index.union(right.index))
334
+ right_mask = DateListDiffLists._non_empty_list_mask(right)
335
+ diff_lists = self._lists_op().calculate_binary(left, right)
336
+ result = self._agg_op().calculate_unary(diff_lists)
166
337
  if self.aggregation in _count_aggregations:
167
- res[~right_mask] = 0.0
168
- res = res.astype(np.float64)
169
-
170
- return res
171
-
172
- def _diff(self, x: TimedeltaArray):
173
- x = self._convert_diff_to_unit(x)
174
- return x[x > 0] if self.replace_negative else x
338
+ result[~right_mask] = 0.0
339
+ return result.astype(np.float64)
175
340
 
176
- def _agg(self, x):
177
- method = getattr(np, self.aggregation, None)
178
- default = np.nan
179
- if method is None and self.aggregation in _ext_aggregations:
180
- method, default = _ext_aggregations[self.aggregation]
181
- elif not callable(method):
182
- raise ValueError(f"Unsupported aggregation: {self.aggregation}")
183
-
184
- return method(x) if len(x) > 0 else default
341
+ def calculate_binary(self, left: pd.Series, right: pd.Series) -> pd.Series:
342
+ return self._compose_list_diff(left, right)
185
343
 
186
344
 
187
345
  class DateListDiffBounded(DateListDiff, ParametrizedOperator):
@@ -230,16 +388,13 @@ class DateListDiffBounded(DateListDiff, ParametrizedOperator):
230
388
  res["normalize"] = str(self.normalize)
231
389
  return res
232
390
 
233
- def _agg(self, x):
234
- orig_len = len(x)
235
- x = x[
236
- (x >= (self.lower_bound if self.lower_bound is not None else -np.inf))
237
- & (x < (self.upper_bound if self.upper_bound is not None else np.inf))
238
- ]
239
- agg_res = super()._agg(x)
240
- if self.normalize and orig_len > 0:
241
- return agg_res / orig_len
242
- return agg_res
391
+ def _agg_op(self) -> DateListDiffAggWithinBounds:
392
+ return DateListDiffAggWithinBounds(
393
+ lower_bound=self.lower_bound,
394
+ upper_bound=self.upper_bound,
395
+ aggregation=self.aggregation,
396
+ normalize=self.normalize or False,
397
+ )
243
398
 
244
399
 
245
400
  class DatePercentileBase(PandasOperator, abc.ABC):
@@ -1 +0,0 @@
1
- __version__ = "1.2.156.dev2"
File without changes
File without changes
File without changes