upgini 1.1.266a3254.post2__tar.gz → 1.1.267a3254.post3__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.
Potentially problematic release.
This version of upgini might be problematic. Click here for more details.
- {upgini-1.1.266a3254.post2/src/upgini.egg-info → upgini-1.1.267a3254.post3}/PKG-INFO +1 -1
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/setup.py +1 -1
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/autofe/date.py +22 -14
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/features_enricher.py +38 -6
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/resource_bundle/strings.properties +4 -2
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/target_utils.py +18 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3/src/upgini.egg-info}/PKG-INFO +1 -1
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_autofe_operands.py +3 -2
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_features_enricher.py +32 -7
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_metrics.py +36 -36
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_target_utils.py +61 -1
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/LICENSE +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/README.md +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/pyproject.toml +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/setup.cfg +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/__init__.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/ads.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/ads_management/__init__.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/ads_management/ads_manager.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/autofe/__init__.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/autofe/all_operands.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/autofe/binary.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/autofe/feature.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/autofe/groupby.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/autofe/operand.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/autofe/unary.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/autofe/vector.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/data_source/__init__.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/data_source/data_source_publisher.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/dataset.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/errors.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/http.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/mdc/__init__.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/mdc/context.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/metadata.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/metrics.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/normalizer/__init__.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/normalizer/phone_normalizer.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/resource_bundle/__init__.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/resource_bundle/exceptions.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/resource_bundle/strings_widget.properties +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/sampler/__init__.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/sampler/base.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/sampler/random_under_sampler.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/sampler/utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/search_task.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/spinner.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/__init__.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/base_search_key_detector.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/blocked_time_series.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/country_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/custom_loss_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/cv_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/datetime_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/deduplicate_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/display_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/email_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/fallback_progress_bar.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/features_validator.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/format.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/ip_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/phone_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/postal_code_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/progress_bar.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/sklearn_ext.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/track_info.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/warning_counter.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/version_validator.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini.egg-info/SOURCES.txt +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini.egg-info/dependency_links.txt +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini.egg-info/requires.txt +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini.egg-info/top_level.txt +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_binary_dataset.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_blocked_time_series.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_categorical_dataset.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_continuous_dataset.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_country_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_custom_loss_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_datetime_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_email_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_etalon_validation.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_phone_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_postal_code_utils.py +0 -0
- {upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/tests/test_widget.py +0 -0
|
@@ -54,6 +54,9 @@ class DateDiffType2(PandasOperand, DateDiffMixin):
|
|
|
54
54
|
return diff
|
|
55
55
|
|
|
56
56
|
|
|
57
|
+
_ext_aggregations = {"nunique": (lambda x: len(np.unique(x)), 0), "count": (len, 0)}
|
|
58
|
+
|
|
59
|
+
|
|
57
60
|
class DateListDiff(PandasOperand, DateDiffMixin):
|
|
58
61
|
is_binary = True
|
|
59
62
|
has_symmetry_importance = True
|
|
@@ -72,18 +75,31 @@ class DateListDiff(PandasOperand, DateDiffMixin):
|
|
|
72
75
|
|
|
73
76
|
def calculate_binary(self, left: pd.Series, right: pd.Series) -> pd.Series:
|
|
74
77
|
left = self._convert_to_date(left, self.left_unit)
|
|
78
|
+
right = right.apply(lambda x: pd.arrays.DatetimeArray(self._convert_to_date(x, self.right_unit)))
|
|
79
|
+
|
|
80
|
+
return pd.Series(left - right.values).apply(lambda x: self._agg(self._diff(x)))
|
|
75
81
|
|
|
76
|
-
|
|
82
|
+
def _diff(self, x):
|
|
83
|
+
x = x / np.timedelta64(1, self.diff_unit)
|
|
84
|
+
return x[x > 0]
|
|
85
|
+
|
|
86
|
+
def _agg(self, x):
|
|
87
|
+
method = getattr(np, self.aggregation, None)
|
|
88
|
+
default = np.nan
|
|
89
|
+
if method is None and self.aggregation in _ext_aggregations:
|
|
90
|
+
method, default = _ext_aggregations[self.aggregation]
|
|
91
|
+
elif not callable(method):
|
|
92
|
+
raise ValueError(f"Unsupported aggregation: {self.aggregation}")
|
|
93
|
+
|
|
94
|
+
return method(x) if len(x) > 0 else default
|
|
77
95
|
|
|
78
96
|
|
|
79
97
|
class DateListDiffBounded(DateListDiff):
|
|
80
98
|
lower_bound: Optional[int]
|
|
81
99
|
upper_bound: Optional[int]
|
|
82
|
-
inclusive: Optional[str]
|
|
83
100
|
|
|
84
101
|
def __init__(self, **data: Any) -> None:
|
|
85
102
|
if "name" not in data:
|
|
86
|
-
inclusive = data.get("inclusive")
|
|
87
103
|
lower_bound = data.get("lower_bound")
|
|
88
104
|
upper_bound = data.get("upper_bound")
|
|
89
105
|
components = [
|
|
@@ -92,18 +108,10 @@ class DateListDiffBounded(DateListDiff):
|
|
|
92
108
|
str(lower_bound if lower_bound is not None else "minusinf"),
|
|
93
109
|
str(upper_bound if upper_bound is not None else "plusinf"),
|
|
94
110
|
]
|
|
95
|
-
if inclusive:
|
|
96
|
-
components.append(inclusive)
|
|
97
111
|
components.append(data.get("aggregation"))
|
|
98
112
|
data["name"] = "_".join(components)
|
|
99
113
|
super().__init__(**data)
|
|
100
114
|
|
|
101
|
-
def
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
& (
|
|
105
|
-
diff_list.between(
|
|
106
|
-
self.lower_bound or -np.inf, self.upper_bound or np.inf, inclusive=self.inclusive or "left"
|
|
107
|
-
)
|
|
108
|
-
)
|
|
109
|
-
].aggregate(self.aggregation)
|
|
115
|
+
def _agg(self, x):
|
|
116
|
+
x = x[(x >= (self.lower_bound or -np.inf)) & (x < (self.upper_bound or np.inf))]
|
|
117
|
+
return super()._agg(x)
|
|
@@ -94,7 +94,7 @@ try:
|
|
|
94
94
|
except Exception:
|
|
95
95
|
from upgini.utils.fallback_progress_bar import CustomFallbackProgressBar as ProgressBar
|
|
96
96
|
|
|
97
|
-
from upgini.utils.target_utils import define_task
|
|
97
|
+
from upgini.utils.target_utils import calculate_psi, define_task
|
|
98
98
|
from upgini.utils.warning_counter import WarningCounter
|
|
99
99
|
from upgini.version_validator import validate_version
|
|
100
100
|
|
|
@@ -2226,14 +2226,11 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
2226
2226
|
validated_X, self.fit_search_keys, self.logger, self.bundle, self.warning_counter
|
|
2227
2227
|
)
|
|
2228
2228
|
|
|
2229
|
-
|
|
2229
|
+
maybe_date_column = self._get_date_column(self.fit_search_keys)
|
|
2230
|
+
has_date = maybe_date_column is not None
|
|
2230
2231
|
model_task_type = self.model_task_type or define_task(validated_y, has_date, self.logger)
|
|
2231
2232
|
self._validate_binary_observations(validated_y, model_task_type)
|
|
2232
2233
|
|
|
2233
|
-
df = self.__handle_index_search_keys(df, self.fit_search_keys)
|
|
2234
|
-
|
|
2235
|
-
df = self.__correct_target(df)
|
|
2236
|
-
|
|
2237
2234
|
self.runtime_parameters = get_runtime_params_custom_loss(
|
|
2238
2235
|
self.loss, model_task_type, self.runtime_parameters, self.logger
|
|
2239
2236
|
)
|
|
@@ -2245,6 +2242,13 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
2245
2242
|
eval_df[EVAL_SET_INDEX] = idx + 1
|
|
2246
2243
|
df = pd.concat([df, eval_df])
|
|
2247
2244
|
|
|
2245
|
+
df = self.__correct_target(df)
|
|
2246
|
+
|
|
2247
|
+
df = self.__handle_index_search_keys(df, self.fit_search_keys)
|
|
2248
|
+
|
|
2249
|
+
if is_numeric_dtype(df[self.TARGET_NAME]) and has_date:
|
|
2250
|
+
self._validate_PSI(df.sort_values(by=maybe_date_column))
|
|
2251
|
+
|
|
2248
2252
|
if DEFAULT_INDEX in df.columns:
|
|
2249
2253
|
msg = self.bundle.get("unsupported_index_column")
|
|
2250
2254
|
self.logger.info(msg)
|
|
@@ -3567,6 +3571,34 @@ class FeaturesEnricher(TransformerMixin):
|
|
|
3567
3571
|
self.logger.warning(msg)
|
|
3568
3572
|
print(msg)
|
|
3569
3573
|
|
|
3574
|
+
def _validate_PSI(self, df: pd.DataFrame):
|
|
3575
|
+
if EVAL_SET_INDEX in df.columns:
|
|
3576
|
+
train = df.query(f"{EVAL_SET_INDEX} == 0")
|
|
3577
|
+
eval1 = df.query(f"{EVAL_SET_INDEX} == 1")
|
|
3578
|
+
else:
|
|
3579
|
+
train = df
|
|
3580
|
+
eval1 = None
|
|
3581
|
+
|
|
3582
|
+
# 1. Check train PSI
|
|
3583
|
+
half_train = round(len(train) / 2)
|
|
3584
|
+
part1 = train[:half_train]
|
|
3585
|
+
part2 = train[half_train:]
|
|
3586
|
+
train_psi = calculate_psi(part1[self.TARGET_NAME], part2[self.TARGET_NAME])
|
|
3587
|
+
if train_psi > 0.2:
|
|
3588
|
+
self.warning_counter.increment()
|
|
3589
|
+
msg = self.bundle.get("train_unstable_target").format(train_psi)
|
|
3590
|
+
print(msg)
|
|
3591
|
+
self.logger.warning(msg)
|
|
3592
|
+
|
|
3593
|
+
# 2. Check train-test PSI
|
|
3594
|
+
if eval1 is not None:
|
|
3595
|
+
train_test_psi = calculate_psi(train[self.TARGET_NAME], eval1[self.TARGET_NAME])
|
|
3596
|
+
if train_test_psi > 0.2:
|
|
3597
|
+
self.warning_counter.increment()
|
|
3598
|
+
msg = self.bundle.get("eval_unstable_target").format(train_test_psi)
|
|
3599
|
+
print(msg)
|
|
3600
|
+
self.logger.warning(msg)
|
|
3601
|
+
|
|
3570
3602
|
def _dump_python_libs(self):
|
|
3571
3603
|
try:
|
|
3572
3604
|
from pip._internal.operations.freeze import freeze
|
|
@@ -111,7 +111,9 @@ x_is_empty=X is empty
|
|
|
111
111
|
y_is_empty=y is empty
|
|
112
112
|
x_contains_reserved_column_name=Column name {} is reserved. Please rename column and try again
|
|
113
113
|
missing_generate_feature=\nWARNING: Feature {} specified in `generate_features` is not present in input columns: {}
|
|
114
|
-
x_unstable_by_date=\nWARNING: Your training sample is unstable in number of rows per date. It is recommended to redesign the training sample
|
|
114
|
+
x_unstable_by_date=\nWARNING: Your training sample is unstable in number of rows per date. It is recommended to redesign the training sample
|
|
115
|
+
train_unstable_target=\nWARNING: Your training sample contains an unstable target event, PSI = {}. This will lead to unstable scoring on deferred samples. It is recommended to redesign the training sample
|
|
116
|
+
eval_unstable_target=\nWARNING: Your training and evaluation samples have a difference in target distribution. PSI = {}. The results will be unstable. It is recommended to redesign the training and evaluation samples
|
|
115
117
|
# eval set validation
|
|
116
118
|
unsupported_type_eval_set=Unsupported type of eval_set: {}. It should be list of tuples with two elements: X and y
|
|
117
119
|
eval_set_invalid_tuple_size=eval_set contains a tuple of size {}. It should contain only pairs of X and y
|
|
@@ -198,7 +200,7 @@ email_detected=Emails detected in column `{}`. It will be used as a search key\n
|
|
|
198
200
|
email_detected_not_registered=Emails detected in column `{}`. It can be used only with api_key from profile.upgini.com\nSee docs to turn off the automatic detection: https://github.com/upgini/upgini/blob/main/README.md#turn-off-autodetection-for-search-key-columns
|
|
199
201
|
phone_detected=Phone numbers detected in column `{}`. It can be used only with api_key from profile.upgini.com\nSee docs to turn off the automatic detection: https://github.com/upgini/upgini/blob/main/README.md#turn-off-autodetection-for-search-key-columns
|
|
200
202
|
phone_detected_not_registered=\nWARNING: Phone numbers detected in column `{}`. It can be used only with api_key from profile.upgini.com\nSee docs to turn off the automatic detection: https://github.com/upgini/upgini/blob/main/README.md#turn-off-autodetection-for-search-key-columns
|
|
201
|
-
target_type_detected
|
|
203
|
+
target_type_detected=\nDetected task type: {}\n
|
|
202
204
|
# all_ok_community_invite=Chat with us in Slack community:
|
|
203
205
|
all_ok_community_invite=❓ Support request
|
|
204
206
|
too_small_for_metrics=Your train dataset contains less than 500 rows. For such dataset Upgini will not calculate accuracy metrics. Please increase the number of rows in the training dataset to calculate accuracy metrics
|
|
@@ -177,3 +177,21 @@ def balance_undersample(
|
|
|
177
177
|
|
|
178
178
|
logger.info(f"Shape after rebalance resampling: {resampled_data}")
|
|
179
179
|
return resampled_data
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def calculate_psi(expected: pd.Series, actual: pd.Series) -> float:
|
|
183
|
+
df = pd.concat([expected, actual])
|
|
184
|
+
|
|
185
|
+
# Define the bins for the target variable
|
|
186
|
+
df_min = df.min()
|
|
187
|
+
df_max = df.max()
|
|
188
|
+
bins = [df_min, (df_min + df_max) / 2, df_max]
|
|
189
|
+
|
|
190
|
+
# Calculate the base distribution
|
|
191
|
+
train_distribution = expected.value_counts(bins=bins, normalize=True).sort_index().values
|
|
192
|
+
|
|
193
|
+
# Calculate the target distribution
|
|
194
|
+
test_distribution = actual.value_counts(bins=bins, normalize=True).sort_index().values
|
|
195
|
+
|
|
196
|
+
# Calculate the PSI
|
|
197
|
+
return np.sum((train_distribution - test_distribution) * np.log(train_distribution / test_distribution))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
|
+
from pydantic import NoneBytes
|
|
2
3
|
from upgini.autofe.date import DateDiff, DateDiffType2, DateListDiff, DateListDiffBounded
|
|
3
4
|
|
|
4
5
|
from datetime import datetime
|
|
@@ -47,7 +48,7 @@ def test_date_diff_list():
|
|
|
47
48
|
def check(aggregation, expected_name, expected_values):
|
|
48
49
|
operand = DateListDiff(aggregation=aggregation)
|
|
49
50
|
assert operand.name == expected_name
|
|
50
|
-
assert_series_equal(operand.calculate_binary(df.date1, df.date2), expected_values)
|
|
51
|
+
assert_series_equal(operand.calculate_binary(df.date1, df.date2).rename(None), expected_values)
|
|
51
52
|
|
|
52
53
|
check(aggregation="min", expected_name="date_diff_min", expected_values=pd.Series([10530, 10531, None, None]))
|
|
53
54
|
check(aggregation="max", expected_name="date_diff_max", expected_values=pd.Series([10531, 10531, None, None]))
|
|
@@ -83,7 +84,7 @@ def test_date_diff_list_bounded():
|
|
|
83
84
|
diff_unit="Y", aggregation="count", lower_bound=lower_bound, upper_bound=upper_bound
|
|
84
85
|
)
|
|
85
86
|
assert operand.name == expected_name
|
|
86
|
-
assert_series_equal(operand.calculate_binary(df.date1, df.date2), expected_values)
|
|
87
|
+
assert_series_equal(operand.calculate_binary(df.date1, df.date2).rename(None), expected_values)
|
|
87
88
|
|
|
88
89
|
check_num_by_years(0, 18, "date_diff_Y_0_18_count", pd.Series([2, 1, 0, 0, 0]))
|
|
89
90
|
check_num_by_years(18, 23, "date_diff_Y_18_23_count", pd.Series([1, 2, 2, 0, 0]))
|
|
@@ -428,13 +428,13 @@ def test_saved_features_enricher(requests_mock: Mocker):
|
|
|
428
428
|
df.drop(columns="SystemRecordId_473310000", inplace=True)
|
|
429
429
|
train_df = df.head(10000)
|
|
430
430
|
train_features = train_df.drop(columns="target")
|
|
431
|
-
train_target = train_df["target"]
|
|
431
|
+
train_target = train_df["target"].copy()
|
|
432
432
|
eval1_df = df[10000:11000].reset_index(drop=True)
|
|
433
433
|
eval1_features = eval1_df.drop(columns="target")
|
|
434
|
-
eval1_target = eval1_df["target"].reset_index(drop=True)
|
|
434
|
+
eval1_target = eval1_df["target"].reset_index(drop=True).copy()
|
|
435
435
|
eval2_df = df[11000:12000]
|
|
436
436
|
eval2_features = eval2_df.drop(columns="target")
|
|
437
|
-
eval2_target = eval2_df["target"]
|
|
437
|
+
eval2_target = eval2_df["target"].copy()
|
|
438
438
|
|
|
439
439
|
enricher = FeaturesEnricher(
|
|
440
440
|
search_keys={"phone_num": SearchKey.PHONE, "rep_date": SearchKey.DATE},
|
|
@@ -482,6 +482,31 @@ def test_saved_features_enricher(requests_mock: Mocker):
|
|
|
482
482
|
assert first_feature_info[feature_name_header] == "feature"
|
|
483
483
|
assert first_feature_info[shap_value_header] == 10.1
|
|
484
484
|
|
|
485
|
+
# Check imbalanced target metrics
|
|
486
|
+
random = np.random.RandomState(42)
|
|
487
|
+
train_random_indices = random.choice(train_target.index, size=9000, replace=False)
|
|
488
|
+
train_target.loc[train_random_indices] = 0
|
|
489
|
+
|
|
490
|
+
metrics = enricher.calculate_metrics(
|
|
491
|
+
train_features,
|
|
492
|
+
train_target
|
|
493
|
+
)
|
|
494
|
+
expected_metrics = pd.DataFrame(
|
|
495
|
+
{
|
|
496
|
+
segment_header: [train_segment],
|
|
497
|
+
rows_header: [10000],
|
|
498
|
+
target_mean_header: [0.049],
|
|
499
|
+
enriched_gini: [0.000985],
|
|
500
|
+
}
|
|
501
|
+
)
|
|
502
|
+
print("Expected metrics: ")
|
|
503
|
+
print(expected_metrics)
|
|
504
|
+
print("Actual metrics: ")
|
|
505
|
+
print(metrics)
|
|
506
|
+
|
|
507
|
+
assert metrics is not None
|
|
508
|
+
assert_frame_equal(expected_metrics, metrics, atol=1e-6)
|
|
509
|
+
|
|
485
510
|
|
|
486
511
|
def test_features_enricher_with_demo_key(requests_mock: Mocker):
|
|
487
512
|
url = "http://fake_url2"
|
|
@@ -2498,11 +2523,11 @@ def test_diff_target_dups(requests_mock: Mocker):
|
|
|
2498
2523
|
assert len(self.data) == 2
|
|
2499
2524
|
print(self.data)
|
|
2500
2525
|
assert self.data.loc[0, "date_0e8763"] == 1672531200000
|
|
2501
|
-
assert self.data.loc[0, "feature_2ad562"] ==
|
|
2502
|
-
assert self.data.loc[0, "target"] ==
|
|
2526
|
+
assert self.data.loc[0, "feature_2ad562"] == 13
|
|
2527
|
+
assert self.data.loc[0, "target"] == 1
|
|
2503
2528
|
assert self.data.loc[1, "date_0e8763"] == 1672531200000
|
|
2504
|
-
assert self.data.loc[1, "feature_2ad562"] ==
|
|
2505
|
-
assert self.data.loc[1, "target"] ==
|
|
2529
|
+
assert self.data.loc[1, "feature_2ad562"] == 12
|
|
2530
|
+
assert self.data.loc[1, "target"] == 0
|
|
2506
2531
|
return SearchTask("123", self, rest_client=enricher.rest_client)
|
|
2507
2532
|
|
|
2508
2533
|
Dataset.search = mock_search
|
|
@@ -857,23 +857,23 @@ def test_catboost_metric_binary(requests_mock: Mocker):
|
|
|
857
857
|
assert metrics_df.loc[0, segment_header] == train_segment
|
|
858
858
|
assert metrics_df.loc[0, rows_header] == 500
|
|
859
859
|
assert metrics_df.loc[0, target_mean_header] == 0.51
|
|
860
|
-
assert metrics_df.loc[0, baseline_gini] == approx(0.
|
|
861
|
-
assert metrics_df.loc[0, enriched_gini] == approx(0.
|
|
862
|
-
assert metrics_df.loc[0, uplift] == approx(0.
|
|
860
|
+
assert metrics_df.loc[0, baseline_gini] == approx(0.061408)
|
|
861
|
+
assert metrics_df.loc[0, enriched_gini] == approx(0.071498)
|
|
862
|
+
assert metrics_df.loc[0, uplift] == approx(0.010090)
|
|
863
863
|
|
|
864
864
|
assert metrics_df.loc[1, segment_header] == eval_1_segment
|
|
865
865
|
assert metrics_df.loc[1, rows_header] == 250
|
|
866
866
|
assert metrics_df.loc[1, target_mean_header] == 0.452
|
|
867
|
-
assert metrics_df.loc[1, baseline_gini] == approx(-0.
|
|
868
|
-
assert metrics_df.loc[1, enriched_gini] == approx(0.
|
|
869
|
-
assert metrics_df.loc[1, uplift] == approx(0.
|
|
867
|
+
assert metrics_df.loc[1, baseline_gini] == approx(-0.051702)
|
|
868
|
+
assert metrics_df.loc[1, enriched_gini] == approx(0.023668)
|
|
869
|
+
assert metrics_df.loc[1, uplift] == approx(0.075370)
|
|
870
870
|
|
|
871
871
|
assert metrics_df.loc[2, segment_header] == eval_2_segment
|
|
872
872
|
assert metrics_df.loc[2, rows_header] == 250
|
|
873
873
|
assert metrics_df.loc[2, target_mean_header] == 0.536
|
|
874
|
-
assert metrics_df.loc[2, baseline_gini] == approx(
|
|
875
|
-
assert metrics_df.loc[2, enriched_gini] == approx(0.
|
|
876
|
-
assert metrics_df.loc[2, uplift] == approx(0.
|
|
874
|
+
assert metrics_df.loc[2, baseline_gini] == approx(0.012674)
|
|
875
|
+
assert metrics_df.loc[2, enriched_gini] == approx(0.022980)
|
|
876
|
+
assert metrics_df.loc[2, uplift] == approx(0.010306)
|
|
877
877
|
|
|
878
878
|
|
|
879
879
|
def test_catboost_metric_binary_with_cat_features(requests_mock: Mocker):
|
|
@@ -984,23 +984,23 @@ def test_catboost_metric_binary_with_cat_features(requests_mock: Mocker):
|
|
|
984
984
|
assert metrics_df.loc[0, segment_header] == train_segment
|
|
985
985
|
assert metrics_df.loc[0, rows_header] == 500
|
|
986
986
|
assert metrics_df.loc[0, target_mean_header] == 0.51
|
|
987
|
-
assert metrics_df.loc[0, baseline_gini] == approx(0.
|
|
988
|
-
assert metrics_df.loc[0, enriched_gini] == approx(0.
|
|
989
|
-
assert metrics_df.loc[0, uplift] == approx(0.
|
|
987
|
+
assert metrics_df.loc[0, baseline_gini] == approx(0.027066)
|
|
988
|
+
assert metrics_df.loc[0, enriched_gini] == approx(0.101601)
|
|
989
|
+
assert metrics_df.loc[0, uplift] == approx(0.074535)
|
|
990
990
|
|
|
991
991
|
assert metrics_df.loc[1, segment_header] == eval_1_segment
|
|
992
992
|
assert metrics_df.loc[1, rows_header] == 250
|
|
993
993
|
assert metrics_df.loc[1, target_mean_header] == 0.452
|
|
994
|
-
assert metrics_df.loc[1, baseline_gini] == approx(-0.
|
|
995
|
-
assert metrics_df.loc[1, enriched_gini] == approx(-0.
|
|
996
|
-
assert metrics_df.loc[1, uplift] == approx(0.
|
|
994
|
+
assert metrics_df.loc[1, baseline_gini] == approx(-0.078548)
|
|
995
|
+
assert metrics_df.loc[1, enriched_gini] == approx(-0.019663)
|
|
996
|
+
assert metrics_df.loc[1, uplift] == approx(0.058885)
|
|
997
997
|
|
|
998
998
|
assert metrics_df.loc[2, segment_header] == eval_2_segment
|
|
999
999
|
assert metrics_df.loc[2, rows_header] == 250
|
|
1000
1000
|
assert metrics_df.loc[2, target_mean_header] == 0.536
|
|
1001
|
-
assert metrics_df.loc[2, baseline_gini] == approx(0.
|
|
1002
|
-
assert metrics_df.loc[2, enriched_gini] == approx(-0.
|
|
1003
|
-
assert metrics_df.loc[2, uplift] == approx(-0.
|
|
1001
|
+
assert metrics_df.loc[2, baseline_gini] == approx(-0.066572)
|
|
1002
|
+
assert metrics_df.loc[2, enriched_gini] == approx(-0.116598)
|
|
1003
|
+
assert metrics_df.loc[2, uplift] == approx(-0.050026)
|
|
1004
1004
|
|
|
1005
1005
|
|
|
1006
1006
|
@pytest.mark.skip()
|
|
@@ -1225,23 +1225,23 @@ def test_rf_metric_rmse(requests_mock: Mocker):
|
|
|
1225
1225
|
assert metrics_df.loc[0, segment_header] == train_segment
|
|
1226
1226
|
assert metrics_df.loc[0, rows_header] == 500
|
|
1227
1227
|
assert metrics_df.loc[0, target_mean_header] == 0.51
|
|
1228
|
-
assert metrics_df.loc[0, baseline_rmse] == approx(0.
|
|
1229
|
-
assert metrics_df.loc[0, enriched_rmse] == approx(0.
|
|
1230
|
-
assert metrics_df.loc[0, uplift] == approx(0.
|
|
1228
|
+
assert metrics_df.loc[0, baseline_rmse] == approx(0.695490)
|
|
1229
|
+
assert metrics_df.loc[0, enriched_rmse] == approx(0.656957)
|
|
1230
|
+
assert metrics_df.loc[0, uplift] == approx(0.038533)
|
|
1231
1231
|
|
|
1232
1232
|
assert metrics_df.loc[1, segment_header] == eval_1_segment
|
|
1233
1233
|
assert metrics_df.loc[1, rows_header] == 250
|
|
1234
1234
|
assert metrics_df.loc[1, target_mean_header] == 0.452
|
|
1235
|
-
assert metrics_df.loc[1, baseline_rmse] == approx(0.
|
|
1236
|
-
assert metrics_df.loc[1, enriched_rmse] == approx(0.
|
|
1237
|
-
assert metrics_df.loc[1, uplift] == approx(
|
|
1235
|
+
assert metrics_df.loc[1, baseline_rmse] == approx(0.717178)
|
|
1236
|
+
assert metrics_df.loc[1, enriched_rmse] == approx(0.685107)
|
|
1237
|
+
assert metrics_df.loc[1, uplift] == approx(0.032071)
|
|
1238
1238
|
|
|
1239
1239
|
assert metrics_df.loc[2, segment_header] == eval_2_segment
|
|
1240
1240
|
assert metrics_df.loc[2, rows_header] == 250
|
|
1241
1241
|
assert metrics_df.loc[2, target_mean_header] == 0.536
|
|
1242
|
-
assert metrics_df.loc[2, baseline_rmse] == approx(0.
|
|
1243
|
-
assert metrics_df.loc[2, enriched_rmse] == approx(0.
|
|
1244
|
-
assert metrics_df.loc[2, uplift] == approx(-0.
|
|
1242
|
+
assert metrics_df.loc[2, baseline_rmse] == approx(0.678079)
|
|
1243
|
+
assert metrics_df.loc[2, enriched_rmse] == approx(0.718205)
|
|
1244
|
+
assert metrics_df.loc[2, uplift] == approx(-0.040126)
|
|
1245
1245
|
|
|
1246
1246
|
|
|
1247
1247
|
def test_default_metric_binary_with_string_feature(requests_mock: Mocker):
|
|
@@ -1341,23 +1341,23 @@ def test_default_metric_binary_with_string_feature(requests_mock: Mocker):
|
|
|
1341
1341
|
assert metrics_df.loc[0, segment_header] == train_segment
|
|
1342
1342
|
assert metrics_df.loc[0, rows_header] == 500
|
|
1343
1343
|
assert metrics_df.loc[0, target_mean_header] == 0.51
|
|
1344
|
-
assert metrics_df.loc[0, baseline_gini] == approx(0.
|
|
1345
|
-
assert metrics_df.loc[0, enriched_gini] == approx(0.
|
|
1346
|
-
assert metrics_df.loc[0, uplift] == approx(-0.
|
|
1344
|
+
assert metrics_df.loc[0, baseline_gini] == approx(-0.034968)
|
|
1345
|
+
assert metrics_df.loc[0, enriched_gini] == approx(-0.090683)
|
|
1346
|
+
assert metrics_df.loc[0, uplift] == approx(-0.055715)
|
|
1347
1347
|
|
|
1348
1348
|
assert metrics_df.loc[1, segment_header] == eval_1_segment
|
|
1349
1349
|
assert metrics_df.loc[1, rows_header] == 250
|
|
1350
1350
|
assert metrics_df.loc[1, target_mean_header] == 0.452
|
|
1351
|
-
assert metrics_df.loc[1, baseline_gini] == approx(-0.
|
|
1352
|
-
assert metrics_df.loc[1, enriched_gini] == approx(-0.
|
|
1353
|
-
assert metrics_df.loc[1, uplift] == approx(0.
|
|
1351
|
+
assert metrics_df.loc[1, baseline_gini] == approx(-0.081674)
|
|
1352
|
+
assert metrics_df.loc[1, enriched_gini] == approx(-0.006627)
|
|
1353
|
+
assert metrics_df.loc[1, uplift] == approx(0.075047)
|
|
1354
1354
|
|
|
1355
1355
|
assert metrics_df.loc[2, segment_header] == eval_2_segment
|
|
1356
1356
|
assert metrics_df.loc[2, rows_header] == 250
|
|
1357
1357
|
assert metrics_df.loc[2, target_mean_header] == 0.536
|
|
1358
|
-
assert metrics_df.loc[2, baseline_gini] == approx(-0.
|
|
1359
|
-
assert metrics_df.loc[2, enriched_gini] == approx(-0.
|
|
1360
|
-
assert metrics_df.loc[2, uplift] == approx(
|
|
1358
|
+
assert metrics_df.loc[2, baseline_gini] == approx(-0.039166)
|
|
1359
|
+
assert metrics_df.loc[2, enriched_gini] == approx(-0.016457)
|
|
1360
|
+
assert metrics_df.loc[2, uplift] == approx(0.022710)
|
|
1361
1361
|
|
|
1362
1362
|
|
|
1363
1363
|
def approx(value: float):
|
|
@@ -4,7 +4,8 @@ import pytest
|
|
|
4
4
|
from pandas.testing import assert_frame_equal
|
|
5
5
|
|
|
6
6
|
from upgini.errors import ValidationError
|
|
7
|
-
from upgini.
|
|
7
|
+
from upgini.features_enricher import FeaturesEnricher
|
|
8
|
+
from upgini.metadata import SYSTEM_RECORD_ID, TARGET, ModelTaskType, SearchKey
|
|
8
9
|
from upgini.resource_bundle import bundle
|
|
9
10
|
from upgini.utils.target_utils import balance_undersample, define_task
|
|
10
11
|
|
|
@@ -132,3 +133,62 @@ def test_balance_undersaampling_multiclass():
|
|
|
132
133
|
})
|
|
133
134
|
# Get all of 25% quantile class (b) and minor classes (a) and x2 (or all if less) of major classes
|
|
134
135
|
assert_frame_equal(balanced_df.sort_values(by=SYSTEM_RECORD_ID).reset_index(drop=True), expected_df)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_binary_psi_calculation():
|
|
139
|
+
df = pd.DataFrame({
|
|
140
|
+
"target": [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]
|
|
141
|
+
})
|
|
142
|
+
df["date"] = pd.date_range("2020-01-01", "2020-01-20")
|
|
143
|
+
enricher = FeaturesEnricher(search_keys={"date": SearchKey.DATE})
|
|
144
|
+
enricher._validate_PSI(df)
|
|
145
|
+
assert not enricher.warning_counter.has_warnings()
|
|
146
|
+
|
|
147
|
+
df = pd.DataFrame({
|
|
148
|
+
"target": [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]
|
|
149
|
+
})
|
|
150
|
+
df["date"] = pd.date_range("2020-01-01", "2020-01-20")
|
|
151
|
+
enricher = FeaturesEnricher(search_keys={"date": SearchKey.DATE})
|
|
152
|
+
enricher._validate_PSI(df)
|
|
153
|
+
assert enricher.warning_counter._count == 1
|
|
154
|
+
|
|
155
|
+
df = pd.DataFrame({
|
|
156
|
+
"target": [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1],
|
|
157
|
+
"eval_set_index": [0] * 10 + [1] * 10,
|
|
158
|
+
})
|
|
159
|
+
df["date"] = pd.date_range("2020-01-01", "2020-01-20")
|
|
160
|
+
enricher = FeaturesEnricher(search_keys={"date": SearchKey.DATE})
|
|
161
|
+
enricher._validate_PSI(df)
|
|
162
|
+
assert enricher.warning_counter._count == 1
|
|
163
|
+
|
|
164
|
+
df = pd.DataFrame({
|
|
165
|
+
"target": [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
|
|
166
|
+
"eval_set_index": [0] * 10 + [1] * 10,
|
|
167
|
+
})
|
|
168
|
+
df["date"] = pd.date_range("2020-01-01", "2020-01-20")
|
|
169
|
+
enricher = FeaturesEnricher(search_keys={"date": SearchKey.DATE})
|
|
170
|
+
enricher._validate_PSI(df)
|
|
171
|
+
assert enricher.warning_counter._count == 2
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def test_regression_psi_calculation():
|
|
175
|
+
random = np.random.RandomState(42)
|
|
176
|
+
df = pd.DataFrame({
|
|
177
|
+
"target": random.rand(20)
|
|
178
|
+
})
|
|
179
|
+
df["date"] = pd.date_range("2020-01-01", "2020-01-20")
|
|
180
|
+
enricher = FeaturesEnricher(search_keys={"date": SearchKey.DATE})
|
|
181
|
+
enricher._validate_PSI(df)
|
|
182
|
+
assert enricher.warning_counter._count == 1
|
|
183
|
+
|
|
184
|
+
values1 = random.rand(10)
|
|
185
|
+
values2 = values1.copy()
|
|
186
|
+
values2[0] = 0.0
|
|
187
|
+
values2[9] = 1.0
|
|
188
|
+
df = pd.DataFrame({
|
|
189
|
+
"target": list(values1) + list(values2)
|
|
190
|
+
})
|
|
191
|
+
df["date"] = pd.date_range("2020-01-01", "2020-01-20")
|
|
192
|
+
enricher = FeaturesEnricher(search_keys={"date": SearchKey.DATE})
|
|
193
|
+
enricher._validate_PSI(df)
|
|
194
|
+
assert not enricher.warning_counter.has_warnings()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/ads_management/__init__.py
RENAMED
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/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
|
|
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.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/normalizer/phone_normalizer.py
RENAMED
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/resource_bundle/__init__.py
RENAMED
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/resource_bundle/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/sampler/random_under_sampler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/base_search_key_detector.py
RENAMED
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/blocked_time_series.py
RENAMED
|
File without changes
|
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/custom_loss_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/deduplicate_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/fallback_progress_bar.py
RENAMED
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/features_validator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upgini-1.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini/utils/postal_code_utils.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.1.266a3254.post2 → upgini-1.1.267a3254.post3}/src/upgini.egg-info/dependency_links.txt
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
|
|
File without changes
|