howso-engine 68.1.0__tar.gz → 68.2.0__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.
- {howso_engine-68.1.0/howso_engine.egg-info → howso_engine-68.2.0}/PKG-INFO +1 -1
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/base.py +96 -61
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/infer_feature_attributes.py +73 -11
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/time_series.py +26 -14
- {howso_engine-68.1.0 → howso_engine-68.2.0/howso_engine.egg-info}/PKG-INFO +1 -1
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.coveragerc +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.flake8 +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.github/CODEOWNERS +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.github/templates/version_summary.md +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.github/workflows/build-pr.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.github/workflows/build-release.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.github/workflows/build.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.github/workflows/rebuild-requirements.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.github/workflows/version-update.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.gitignore +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.gitmodules +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/.pylintrc +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/CONTRIBUTING.md +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/LICENSE-3RD-PARTY.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/LICENSE.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/MANIFEST.in +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/Makefile +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/README.md +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/bin/build.sh +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/config/latest-mt-debug-howso.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/config/latest-mt-howso.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/config/latest-mt-noavx-traces-howso.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/config/latest-mt-traces-howso.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/config/latest-st-debug-howso.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/config/latest-st-howso.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/config/latest-st-traces-howso.yml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/config/powershell/Download-Tzdata.ps1 +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/config/powershell/Helper-Functions.ps1 +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/hatch.toml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/__main__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/__init__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/api.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/base.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/cache.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/client.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/configuration.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/exceptions.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/feature_flags.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/pandas/__init__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/pandas/client.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/protocols.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/schemas/__init__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/schemas/aggregate_reaction.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/schemas/base.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/schemas/group_reaction.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/schemas/project.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/schemas/reaction.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/schemas/session.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/schemas/trainee.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/schemas/version.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/client/typing.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/direct/__init__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/direct/_utilities.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/direct/client.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/direct/schemas/__init__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/direct/schemas/trainee.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/engine/__init__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/engine/client.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/engine/project.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/engine/session.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/engine/trainee.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/howso-engine/howso.caml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/howso-engine/migrations/migrations.caml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/howso-engine/version.json +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/scikit/__init__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/scikit/scikit.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/__init__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/decorators.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/fanout_features.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/__init__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/abstract_data.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/pandas.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/protocols.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/relational.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/serializers.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/suggestions.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/warnings.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/features.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/__init__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/__main__.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/_constants.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/_helpers.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/_output.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/_probes.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/_types.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/checks_cpu.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/checks_engine.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/checks_environment.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/checks_optional.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/main.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/registry.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/internals.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/json_wrapper.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/locale.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/monitors.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/posix.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/progress.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/random.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/reaction.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/testing.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/tokenizing.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/utilities.py +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso_engine.egg-info/SOURCES.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso_engine.egg-info/dependency_links.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso_engine.egg-info/entry_points.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso_engine.egg-info/requires.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso_engine.egg-info/scm_file_list.json +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/howso_engine.egg-info/top_level.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/pyproject.toml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/pyrightconfig.json +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/requirements-3.11-dev.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/requirements-3.11.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/requirements-3.12-dev.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/requirements-3.12.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/requirements-3.13-dev.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/requirements-3.13.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/requirements-3.14-dev.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/requirements-3.14.txt +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/ruff.toml +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/setup.cfg +0 -0
- {howso_engine-68.1.0 → howso_engine-68.2.0}/version.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: howso-engine
|
|
3
|
-
Version: 68.
|
|
3
|
+
Version: 68.2.0
|
|
4
4
|
Summary: The Howso Engine™ is a natively and fully explainable ML engine, serving as an alternative to black box AI neural networks.
|
|
5
5
|
Author: Howso Incorporated
|
|
6
6
|
Author-email: support@howso.com
|
|
@@ -77,8 +77,16 @@ INTEGER_MAX = int(math.pow(2, 53))
|
|
|
77
77
|
LINUX_DT_MAX = "2262-04-11"
|
|
78
78
|
WIN_DT_MAX = "6053-01-24"
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
"""The default number of cases a
|
|
80
|
+
PRESERVE_RARE_VALUES_MIN_CASES_DEFAULT: int = 15
|
|
81
|
+
"""The default number of cases a value needs in the data to be considered for rare value preservation."""
|
|
82
|
+
|
|
83
|
+
PRESERVE_RARE_VALUES_DISTILLED_MIN_CASES_DEFAULT: int = 3
|
|
84
|
+
"""
|
|
85
|
+
The default number of cases a preserved rare value is expected to keep after distillation.
|
|
86
|
+
|
|
87
|
+
It is also the fewest cases a frequent value is expected to keep when its weight is reduced to fund
|
|
88
|
+
the rare values.
|
|
89
|
+
"""
|
|
82
90
|
|
|
83
91
|
DEFAULT_MAX_DISTILLED_CASES: int = 50_000
|
|
84
92
|
"""The distillation target assumed for rare value weighting when `max_distilled_cases` is not given."""
|
|
@@ -1208,7 +1216,8 @@ class InferFeatureAttributesBase(ABC):
|
|
|
1208
1216
|
ordinal_feature_values: dict[str, list[Any]] | None = None,
|
|
1209
1217
|
preserve_rare_values: PreserveRareValues | None = None,
|
|
1210
1218
|
preserve_rare_values_caps: PreserveRareValuesCaps | None = None,
|
|
1211
|
-
|
|
1219
|
+
preserve_rare_values_distilled_min_cases: int = PRESERVE_RARE_VALUES_DISTILLED_MIN_CASES_DEFAULT,
|
|
1220
|
+
preserve_rare_values_min_cases: int = PRESERVE_RARE_VALUES_MIN_CASES_DEFAULT,
|
|
1212
1221
|
tight_bounds: Iterable[str] | None = None,
|
|
1213
1222
|
types: dict[str, str] | dict[str, MutableSequence[str]] | None = None,
|
|
1214
1223
|
) -> dict:
|
|
@@ -1554,8 +1563,10 @@ class InferFeatureAttributesBase(ABC):
|
|
|
1554
1563
|
self.suggestions_collector.append(FanoutFeaturesSuggestion(candidate_fanout))
|
|
1555
1564
|
|
|
1556
1565
|
# Compute or suggest `preserve_rare_values` configuration
|
|
1557
|
-
self._process_rare_values(preserve_rare_values, max_distilled_cases,
|
|
1558
|
-
|
|
1566
|
+
self._process_rare_values(preserve_rare_values, max_distilled_cases, enable_suggestions,
|
|
1567
|
+
min_cases=preserve_rare_values_min_cases,
|
|
1568
|
+
distilled_min_cases=preserve_rare_values_distilled_min_cases,
|
|
1569
|
+
caps=_normalize_rare_value_caps(preserve_rare_values_caps))
|
|
1559
1570
|
|
|
1560
1571
|
# Re-order the keys like the original dataframe
|
|
1561
1572
|
ordered_attributes = {}
|
|
@@ -2205,7 +2216,8 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2205
2216
|
def _find_protected_value_candidates(
|
|
2206
2217
|
self,
|
|
2207
2218
|
max_distilled_cases: int,
|
|
2208
|
-
|
|
2219
|
+
min_cases: int,
|
|
2220
|
+
distilled_min_cases: int,
|
|
2209
2221
|
*,
|
|
2210
2222
|
features: Container[str] | None = None,
|
|
2211
2223
|
) -> tuple[PreserveRareValuesMap, list[dict]]:
|
|
@@ -2216,9 +2228,11 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2216
2228
|
----------
|
|
2217
2229
|
max_distilled_cases : int
|
|
2218
2230
|
The maximum number of cases in the resultant data following distillation.
|
|
2219
|
-
|
|
2220
|
-
The number of cases
|
|
2221
|
-
|
|
2231
|
+
min_cases : int
|
|
2232
|
+
The number of cases a value needs in the data to be a candidate.
|
|
2233
|
+
distilled_min_cases : int
|
|
2234
|
+
The number of cases a value should keep after distillation; a value expected to keep
|
|
2235
|
+
fewer is a candidate.
|
|
2222
2236
|
features : Container of str, optional
|
|
2223
2237
|
The features to search. Defaults to every nominal feature.
|
|
2224
2238
|
|
|
@@ -2238,7 +2252,6 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2238
2252
|
if self._get_unique_count(feature) == total_cases:
|
|
2239
2253
|
# Don't make a suggestion for a completely unique feature
|
|
2240
2254
|
continue
|
|
2241
|
-
threshold = significance_threshold
|
|
2242
2255
|
# Every null form (None, NaN, NA) is counted together, so it is one candidate, None
|
|
2243
2256
|
null_seen = False
|
|
2244
2257
|
for unique_value in self._get_unique_values(feature):
|
|
@@ -2254,10 +2267,10 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2254
2267
|
self.warnings_collector.triage(IFAWarningEmitterType.VALUE_COUNTS_PROCESSING, feature)
|
|
2255
2268
|
continue
|
|
2256
2269
|
# Don't include values that aren't significant to begin with
|
|
2257
|
-
if count <
|
|
2270
|
+
if count < min_cases:
|
|
2258
2271
|
continue
|
|
2259
2272
|
expected_freq_at_target_size = (max_distilled_cases / total_cases) * count
|
|
2260
|
-
if expected_freq_at_target_size <
|
|
2273
|
+
if expected_freq_at_target_size < distilled_min_cases:
|
|
2261
2274
|
value_counts.append({"feature": feature, "value": value, "count": count})
|
|
2262
2275
|
if feature not in pvm:
|
|
2263
2276
|
pvm[feature] = [value]
|
|
@@ -2270,7 +2283,8 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2270
2283
|
self,
|
|
2271
2284
|
feature: str,
|
|
2272
2285
|
targets: Sequence[ProtectedValueMultiplier],
|
|
2273
|
-
|
|
2286
|
+
min_cases: int,
|
|
2287
|
+
distilled_min_cases: int,
|
|
2274
2288
|
floor: float,
|
|
2275
2289
|
*,
|
|
2276
2290
|
fit: Literal["largest_first", "scale"],
|
|
@@ -2280,12 +2294,12 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2280
2294
|
Compute the case weight multipliers of a feature that fund the preservation of its rare values.
|
|
2281
2295
|
|
|
2282
2296
|
The `targets` are the rare values to weight up, each to its given multiplier. Values with
|
|
2283
|
-
at least `floor` cases are significant: these are all scaled by one
|
|
2284
|
-
that none is scaled below `floor` cases, so a value that is
|
|
2285
|
-
distillation stays significant after it. With a `cap`, the factor is
|
|
2286
|
-
``1 - cap``. The factor is chosen so the total case weight of the feature is unchanged.
|
|
2287
|
-
Every other value, whether it has fewer than `
|
|
2288
|
-
|
|
2297
|
+
at least `min_cases` and at least `floor` cases are significant: these are all scaled by one
|
|
2298
|
+
common factor, except that none is scaled below `floor` cases, so a value that is
|
|
2299
|
+
significant before distillation stays significant after it. With a `cap`, the factor is
|
|
2300
|
+
no smaller than ``1 - cap``. The factor is chosen so the total case weight of the feature is unchanged.
|
|
2301
|
+
Every other value, whether it has fewer than `min_cases` cases or falls below the floor,
|
|
2302
|
+
keeps a multiplier of 1.
|
|
2289
2303
|
|
|
2290
2304
|
When the significant values cannot fund every target within those limits, `fit` decides
|
|
2291
2305
|
what happens: ``"largest_first"`` keeps the targets with the most cases and leaves the
|
|
@@ -2300,11 +2314,13 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2300
2314
|
The rare values and the multipliers they should receive, each at least 1. Values must
|
|
2301
2315
|
already be in stored form, as :func:`_as_feature_value` gives them: nulls as None and
|
|
2302
2316
|
numpy scalars as Python types.
|
|
2303
|
-
|
|
2317
|
+
min_cases : int
|
|
2304
2318
|
The number of cases below which a value is small.
|
|
2319
|
+
distilled_min_cases : int
|
|
2320
|
+
The number of cases each value should keep after distillation.
|
|
2305
2321
|
floor : float
|
|
2306
|
-
The number of cases a significant value must keep, ``
|
|
2307
|
-
|
|
2322
|
+
The number of cases a significant value must keep, ``distilled_min_cases`` divided by
|
|
2323
|
+
the reduction ratio of distillation, or 0 when no distillation target is known.
|
|
2308
2324
|
fit : {"largest_first", "scale"}
|
|
2309
2325
|
How to reconcile the targets with the available case weight when they do not fit.
|
|
2310
2326
|
cap : float, optional
|
|
@@ -2318,7 +2334,7 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2318
2334
|
every significant value, whether scaled by the common factor or held at the floor. Values
|
|
2319
2335
|
that keep a multiplier of 1 are not listed. Every listed value keeps at least `floor`
|
|
2320
2336
|
cases of weight, so a configuration lists at most ``total_cases / floor`` values, which
|
|
2321
|
-
is the distillation target divided by
|
|
2337
|
+
is the distillation target divided by `distilled_min_cases`. None when the
|
|
2322
2338
|
feature has no significant values to take case weight from, or no target could be
|
|
2323
2339
|
funded.
|
|
2324
2340
|
list of ProtectedValueMultiplier
|
|
@@ -2339,8 +2355,8 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2339
2355
|
|
|
2340
2356
|
# The algorithm, in four steps:
|
|
2341
2357
|
# 1. Sort every non-target value into "unchanged" (keeps weight 1) or "significant" (can give
|
|
2342
|
-
# weight up). A significant value has at least `floor` cases, so it
|
|
2343
|
-
# keep `
|
|
2358
|
+
# weight up). A significant value has at least `min_cases` and at least `floor` cases, so it
|
|
2359
|
+
# can lose some and still keep `distilled_min_cases` after distillation.
|
|
2344
2360
|
# 2. Compare what the targets need ("deficits") with what the significant values can give
|
|
2345
2361
|
# ("budgets"), and decide which targets are funded.
|
|
2346
2362
|
# 3. Find the one factor that scales the significant values so their total loss equals the
|
|
@@ -2349,7 +2365,7 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2349
2365
|
# values, each at the factor or held at the floor.
|
|
2350
2366
|
|
|
2351
2367
|
# Step 1: classify the other values. A value is unchanged when it is small (fewer than
|
|
2352
|
-
# `
|
|
2368
|
+
# `min_cases` cases) or already below the floor, since it has no weight to spare and
|
|
2353
2369
|
# is not a target to lift. Nulls are counted together as the single value None.
|
|
2354
2370
|
null_seen = False
|
|
2355
2371
|
unchanged_counts: list[int] = []
|
|
@@ -2373,7 +2389,7 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2373
2389
|
except (TypeError, ValueError):
|
|
2374
2390
|
self.warnings_collector.triage(IFAWarningEmitterType.VALUE_COUNTS_PROCESSING, feature)
|
|
2375
2391
|
continue
|
|
2376
|
-
if count <
|
|
2392
|
+
if count < min_cases or count < floor:
|
|
2377
2393
|
unchanged_counts.append(count)
|
|
2378
2394
|
else:
|
|
2379
2395
|
significant.append((value, count))
|
|
@@ -2391,7 +2407,8 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2391
2407
|
target_counts=lifted_counts,
|
|
2392
2408
|
other_counts=all_other_counts,
|
|
2393
2409
|
total_cases=total_cases,
|
|
2394
|
-
|
|
2410
|
+
min_cases=min_cases,
|
|
2411
|
+
distilled_min_cases=distilled_min_cases,
|
|
2395
2412
|
min_multiplier=min_multiplier,
|
|
2396
2413
|
),
|
|
2397
2414
|
"multiplier_scale": None,
|
|
@@ -2447,7 +2464,8 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2447
2464
|
target_counts=lifted_counts,
|
|
2448
2465
|
other_counts=all_other_counts,
|
|
2449
2466
|
total_cases=total_cases,
|
|
2450
|
-
|
|
2467
|
+
min_cases=min_cases,
|
|
2468
|
+
distilled_min_cases=distilled_min_cases,
|
|
2451
2469
|
min_multiplier=min_multiplier,
|
|
2452
2470
|
),
|
|
2453
2471
|
"multiplier_scale": None,
|
|
@@ -2524,7 +2542,7 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2524
2542
|
|
|
2525
2543
|
@staticmethod
|
|
2526
2544
|
def _min_distilled_cases_to_fit(target_counts: np.ndarray, other_counts: np.ndarray, total_cases: int,
|
|
2527
|
-
|
|
2545
|
+
min_cases: int, distilled_min_cases: int, min_multiplier: float) -> int | None:
|
|
2528
2546
|
"""
|
|
2529
2547
|
Find the smallest `max_distilled_cases` at which every rare value of a feature can be preserved.
|
|
2530
2548
|
|
|
@@ -2537,7 +2555,9 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2537
2555
|
at each searched target, since the floor falls as the target grows.
|
|
2538
2556
|
total_cases : int
|
|
2539
2557
|
The number of cases in the data.
|
|
2540
|
-
|
|
2558
|
+
min_cases : int
|
|
2559
|
+
The number of cases below which a value is small and cannot donate.
|
|
2560
|
+
distilled_min_cases : int
|
|
2541
2561
|
The number of cases each value should keep after distillation.
|
|
2542
2562
|
min_multiplier : float
|
|
2543
2563
|
The smallest multiplier the feature's significant values may receive.
|
|
@@ -2555,10 +2575,10 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2555
2575
|
def fits(max_distilled_cases: int) -> bool:
|
|
2556
2576
|
max_distilled_cases, _ = get_optimized_partition_size(row_count=total_cases,
|
|
2557
2577
|
max_partition_size=max_distilled_cases)
|
|
2558
|
-
floor =
|
|
2559
|
-
# Targets below the floor need funding; any value at or above it can give some up
|
|
2578
|
+
floor = distilled_min_cases * total_cases / max_distilled_cases
|
|
2579
|
+
# Targets below the floor need funding; any value at or above it that is not small can give some up
|
|
2560
2580
|
needed = float((floor - target_counts[target_counts < floor]).sum())
|
|
2561
|
-
significant = counts[counts >= floor]
|
|
2581
|
+
significant = counts[(counts >= floor) & (counts >= min_cases)]
|
|
2562
2582
|
budget = float((significant - np.maximum(floor, min_multiplier * significant)).sum())
|
|
2563
2583
|
return needed <= budget
|
|
2564
2584
|
|
|
@@ -2577,14 +2597,15 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2577
2597
|
self,
|
|
2578
2598
|
max_distilled_cases: int,
|
|
2579
2599
|
values_map: PreserveRareValuesMap,
|
|
2580
|
-
|
|
2600
|
+
min_cases: int,
|
|
2601
|
+
distilled_min_cases: int,
|
|
2581
2602
|
caps: Mapping[str, float] | None = None,
|
|
2582
2603
|
) -> tuple[FullPreserveRareValuesConfig, PreserveRareValuesMap, list[RareValuePreservationLimit],
|
|
2583
2604
|
dict[str, list[tuple[Any, int]]]]:
|
|
2584
2605
|
"""
|
|
2585
2606
|
Determine the case weight multipliers for the provided rare values and the other values of their features.
|
|
2586
2607
|
|
|
2587
|
-
Each rare value is weighted so that it keeps `
|
|
2608
|
+
Each rare value is weighted so that it keeps `distilled_min_cases` cases after
|
|
2588
2609
|
distillation, funded by the feature's significant values as described in
|
|
2589
2610
|
:meth:`_reweight_rare_values`. When not every rare value fits, those with the most cases
|
|
2590
2611
|
are preserved.
|
|
@@ -2595,9 +2616,10 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2595
2616
|
The maximum number of cases in the resultant data following distillation.
|
|
2596
2617
|
values_map : PreserveRareValuesMap
|
|
2597
2618
|
A mapping of feature name to list of rare values to compute multipliers for.
|
|
2598
|
-
|
|
2599
|
-
The number of cases
|
|
2600
|
-
|
|
2619
|
+
min_cases : int
|
|
2620
|
+
The number of cases below which a value is small and does not fund the rare values.
|
|
2621
|
+
distilled_min_cases : int
|
|
2622
|
+
The number of cases each rare value should keep after distillation.
|
|
2601
2623
|
caps : Mapping of str to float, optional
|
|
2602
2624
|
The largest share of its weight a significant value of each listed feature may give up.
|
|
2603
2625
|
|
|
@@ -2612,7 +2634,7 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2612
2634
|
The features whose rare values could not all be preserved.
|
|
2613
2635
|
dict of str to list of tuple
|
|
2614
2636
|
The values of each feature that were not lifted, with their case counts, because each
|
|
2615
|
-
keeps
|
|
2637
|
+
keeps `distilled_min_cases` cases after distillation on its own at this target.
|
|
2616
2638
|
"""
|
|
2617
2639
|
prvc: FullPreserveRareValuesConfig = {}
|
|
2618
2640
|
protected_map: PreserveRareValuesMap = {}
|
|
@@ -2624,7 +2646,7 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2624
2646
|
if feature not in self.attributes:
|
|
2625
2647
|
# Multiprocessing is enabled, and this feature will be handled in another process
|
|
2626
2648
|
continue
|
|
2627
|
-
floor =
|
|
2649
|
+
floor = distilled_min_cases * total_cases / max_distilled_cases
|
|
2628
2650
|
targets: list[ProtectedValueMultiplier] = []
|
|
2629
2651
|
for value in _dedupe_values(values):
|
|
2630
2652
|
count = self._get_value_count(feature, value)
|
|
@@ -2632,7 +2654,7 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2632
2654
|
raise ValueError(f"Specified protected value `{value}` not found in column `{feature}`. "
|
|
2633
2655
|
"Please verify the value and type.")
|
|
2634
2656
|
multiplier = floor / count
|
|
2635
|
-
# A value that keeps
|
|
2657
|
+
# A value that keeps `distilled_min_cases` on its own does not need signal preservation
|
|
2636
2658
|
if multiplier <= 1:
|
|
2637
2659
|
skipped.setdefault(feature, []).append((_as_feature_value(value), count))
|
|
2638
2660
|
continue
|
|
@@ -2642,7 +2664,8 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2642
2664
|
config, kept, limit = self._reweight_rare_values(
|
|
2643
2665
|
feature=feature,
|
|
2644
2666
|
targets=targets,
|
|
2645
|
-
|
|
2667
|
+
min_cases=min_cases,
|
|
2668
|
+
distilled_min_cases=distilled_min_cases,
|
|
2646
2669
|
floor=floor,
|
|
2647
2670
|
fit="largest_first",
|
|
2648
2671
|
cap=caps.get(feature),
|
|
@@ -2658,9 +2681,10 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2658
2681
|
self,
|
|
2659
2682
|
preserve_rare_values: PreserveRareValues | None,
|
|
2660
2683
|
max_distilled_cases: int | None,
|
|
2661
|
-
significance_threshold: int,
|
|
2662
2684
|
enable_suggestions: bool = True,
|
|
2663
2685
|
*,
|
|
2686
|
+
min_cases: int,
|
|
2687
|
+
distilled_min_cases: int,
|
|
2664
2688
|
caps: Mapping[str, float] | None = None,
|
|
2665
2689
|
) -> None:
|
|
2666
2690
|
"""
|
|
@@ -2708,12 +2732,14 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2708
2732
|
if not enable_suggestions or self._get_row_count() < requested_max_distilled_cases:
|
|
2709
2733
|
return
|
|
2710
2734
|
candidates, values_ranking = self._find_protected_value_candidates(
|
|
2711
|
-
max_distilled_cases=max_distilled_cases,
|
|
2735
|
+
max_distilled_cases=max_distilled_cases, min_cases=min_cases,
|
|
2736
|
+
distilled_min_cases=distilled_min_cases)
|
|
2712
2737
|
if candidates:
|
|
2713
2738
|
candidate_prvc, protected_map, limits, _ = self._compute_preserve_rare_values_config(
|
|
2714
2739
|
max_distilled_cases=max_distilled_cases,
|
|
2715
2740
|
values_map=candidates,
|
|
2716
|
-
|
|
2741
|
+
min_cases=min_cases,
|
|
2742
|
+
distilled_min_cases=distilled_min_cases,
|
|
2717
2743
|
caps=caps,
|
|
2718
2744
|
)
|
|
2719
2745
|
if candidate_prvc or limits:
|
|
@@ -2743,7 +2769,8 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2743
2769
|
"inference with the `types` parameter.")
|
|
2744
2770
|
values_map, _ = self._find_protected_value_candidates(
|
|
2745
2771
|
max_distilled_cases=max_distilled_cases,
|
|
2746
|
-
|
|
2772
|
+
min_cases=min_cases,
|
|
2773
|
+
distilled_min_cases=distilled_min_cases,
|
|
2747
2774
|
features=search_features,
|
|
2748
2775
|
)
|
|
2749
2776
|
named_features = list(search_features or [])
|
|
@@ -2758,14 +2785,16 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2758
2785
|
prvc.update(self._fund_given_multipliers(
|
|
2759
2786
|
given=given,
|
|
2760
2787
|
max_distilled_cases=max_distilled_cases,
|
|
2761
|
-
|
|
2788
|
+
min_cases=min_cases,
|
|
2789
|
+
distilled_min_cases=distilled_min_cases,
|
|
2762
2790
|
caps=caps,
|
|
2763
2791
|
))
|
|
2764
2792
|
# Plain values get their multipliers computed
|
|
2765
2793
|
computed, _, limits, skipped = self._compute_preserve_rare_values_config(
|
|
2766
2794
|
max_distilled_cases=max_distilled_cases,
|
|
2767
2795
|
values_map=values_map,
|
|
2768
|
-
|
|
2796
|
+
min_cases=min_cases,
|
|
2797
|
+
distilled_min_cases=distilled_min_cases,
|
|
2769
2798
|
caps=caps,
|
|
2770
2799
|
)
|
|
2771
2800
|
prvc.update(computed)
|
|
@@ -2781,13 +2810,13 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2781
2810
|
self.warnings_collector.triage(
|
|
2782
2811
|
IFAWarningEmitterType.SIMPLE,
|
|
2783
2812
|
f"No rare value candidates were found in {names} at a `max_distilled_cases` of "
|
|
2784
|
-
f"{requested_max_distilled_cases:,}: every value either has fewer than {
|
|
2785
|
-
"
|
|
2813
|
+
f"{requested_max_distilled_cases:,}: every value either has fewer than {min_cases} cases or "
|
|
2814
|
+
f"keeps {distilled_min_cases} after distillation on its own.\n"
|
|
2786
2815
|
"These features need no rare value preservation at this target."
|
|
2787
2816
|
)
|
|
2788
|
-
# A value the user named that was not lifted keeps
|
|
2817
|
+
# A value the user named that was not lifted keeps `distilled_min_cases` on its own; it is reported with its
|
|
2789
2818
|
# count against the floor, whether or not the other values named for the feature were lifted
|
|
2790
|
-
floor =
|
|
2819
|
+
floor = distilled_min_cases * self._get_row_count() / max_distilled_cases
|
|
2791
2820
|
floor_text = f"{floor:,.0f}" if float(floor).is_integer() else f"{floor:,.1f}"
|
|
2792
2821
|
for feature, values in skipped.items():
|
|
2793
2822
|
if feature not in self.attributes:
|
|
@@ -2799,9 +2828,10 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2799
2828
|
else f"No value weight multipliers were written for `{feature}`.")
|
|
2800
2829
|
self.warnings_collector.triage(
|
|
2801
2830
|
IFAWarningEmitterType.SIMPLE,
|
|
2802
|
-
f"The values {listed} of feature `{feature}` were not lifted: each keeps
|
|
2803
|
-
f"
|
|
2804
|
-
f"value needs at least {floor_text} cases to keep
|
|
2831
|
+
f"The values {listed} of feature `{feature}` were not lifted: each keeps {distilled_min_cases} "
|
|
2832
|
+
f"cases after distillation on its own at a `max_distilled_cases` of "
|
|
2833
|
+
f"{requested_max_distilled_cases:,}, where a value needs at least {floor_text} cases to keep "
|
|
2834
|
+
f"{distilled_min_cases}.\n"
|
|
2805
2835
|
f"{outcome}"
|
|
2806
2836
|
)
|
|
2807
2837
|
if not user_set_mdc:
|
|
@@ -2829,7 +2859,8 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2829
2859
|
self,
|
|
2830
2860
|
given: PreserveRareValuesConfig,
|
|
2831
2861
|
max_distilled_cases: int,
|
|
2832
|
-
|
|
2862
|
+
min_cases: int,
|
|
2863
|
+
distilled_min_cases: int,
|
|
2833
2864
|
caps: Mapping[str, float],
|
|
2834
2865
|
) -> FullPreserveRareValuesConfig:
|
|
2835
2866
|
"""
|
|
@@ -2842,8 +2873,11 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2842
2873
|
:func:`_split_rare_values` validates and deduplicates them.
|
|
2843
2874
|
max_distilled_cases : int
|
|
2844
2875
|
The distillation target, as :func:`get_optimized_partition_size` rounds it.
|
|
2845
|
-
|
|
2846
|
-
The number of cases below which a value is small.
|
|
2876
|
+
min_cases : int
|
|
2877
|
+
The number of cases below which a value is small and does not fund the rare values.
|
|
2878
|
+
distilled_min_cases : int
|
|
2879
|
+
The number of cases each value should keep after distillation, which sets the floor
|
|
2880
|
+
no funding value is reduced below.
|
|
2847
2881
|
caps : Mapping of str to float
|
|
2848
2882
|
The largest share of its weight a significant value of each listed feature may give up.
|
|
2849
2883
|
|
|
@@ -2874,11 +2908,12 @@ class InferFeatureAttributesBase(ABC):
|
|
|
2874
2908
|
# Every pair asked to hold its weight, so there is nothing to fund and no value to reweight;
|
|
2875
2909
|
# an unlisted value holds its weight already
|
|
2876
2910
|
continue
|
|
2877
|
-
floor =
|
|
2911
|
+
floor = distilled_min_cases * total_cases / max_distilled_cases
|
|
2878
2912
|
config, _, limit = self._reweight_rare_values(
|
|
2879
2913
|
feature=feature,
|
|
2880
2914
|
targets=targets,
|
|
2881
|
-
|
|
2915
|
+
min_cases=min_cases,
|
|
2916
|
+
distilled_min_cases=distilled_min_cases,
|
|
2882
2917
|
floor=floor,
|
|
2883
2918
|
fit="scale",
|
|
2884
2919
|
cap=caps.get(feature),
|
|
@@ -2,11 +2,16 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from collections.abc import Iterable, Sequence
|
|
4
4
|
from typing import Any, Literal, overload, TYPE_CHECKING, TypeAlias, TypedDict, Unpack
|
|
5
|
+
import warnings
|
|
5
6
|
|
|
6
7
|
import pandas as pd
|
|
7
8
|
|
|
8
9
|
from howso.utilities.feature_attributes.abstract_data import InferFeatureAttributesAbstractData
|
|
9
|
-
from howso.utilities.feature_attributes.base import
|
|
10
|
+
from howso.utilities.feature_attributes.base import (
|
|
11
|
+
FeatureAttributesBase,
|
|
12
|
+
PRESERVE_RARE_VALUES_DISTILLED_MIN_CASES_DEFAULT,
|
|
13
|
+
PRESERVE_RARE_VALUES_MIN_CASES_DEFAULT,
|
|
14
|
+
)
|
|
10
15
|
from howso.utilities.feature_attributes.pandas import InferFeatureAttributesDataFrame
|
|
11
16
|
from howso.utilities.feature_attributes.protocols import (
|
|
12
17
|
IFACompatibleADCProtocol,
|
|
@@ -46,6 +51,8 @@ class InferOptions(TypedDict, total=False):
|
|
|
46
51
|
ordinal_feature_values: dict[str, list[Any] | tuple[str]]
|
|
47
52
|
preserve_rare_values: PreserveRareValues | None
|
|
48
53
|
preserve_rare_values_caps: PreserveRareValuesCaps | None
|
|
54
|
+
preserve_rare_values_distilled_min_cases: int
|
|
55
|
+
preserve_rare_values_min_cases: int
|
|
49
56
|
significance_threshold: int
|
|
50
57
|
tight_bounds: Iterable[str]
|
|
51
58
|
types: dict[str, FeatureType] | dict[FeatureType, list[str]]
|
|
@@ -319,14 +326,16 @@ def infer_feature_attributes(
|
|
|
319
326
|
A dict maps each feature name to one of three forms:
|
|
320
327
|
|
|
321
328
|
- A list of values to protect. Each is weighted to keep approximately
|
|
322
|
-
`
|
|
329
|
+
`preserve_rare_values_distilled_min_cases` cases after distillation, funded by the
|
|
330
|
+
feature's other values.
|
|
323
331
|
When not every value fits, those with the most cases are given priority. Without
|
|
324
332
|
`max_distilled_cases`, the multipliers are computed for a default target of 50,000 cases.
|
|
325
333
|
- A list of dicts of "value" and "multiplier", giving the multiplier each value should
|
|
326
334
|
receive, at least 1. The feature's other values are reweighted to fund them so the total
|
|
327
|
-
case weight is unchanged: values with fewer
|
|
328
|
-
weight of 1, and every other value is scaled by one common factor, except that no
|
|
329
|
-
scaled below the number of cases that keeps
|
|
335
|
+
case weight is unchanged: values with fewer than `preserve_rare_values_min_cases` cases
|
|
336
|
+
keep a weight of 1, and every other value is scaled by one common factor, except that no
|
|
337
|
+
value is scaled below the number of cases that keeps
|
|
338
|
+
`preserve_rare_values_distilled_min_cases` after distillation. See
|
|
330
339
|
`preserve_rare_values_caps` to limit how much weight those values give up. Without
|
|
331
340
|
`max_distilled_cases`, the floor is computed for a target of 50,000 cases. If the other
|
|
332
341
|
values cannot fund the multipliers, each multiplier's increase over 1 is scaled down and a
|
|
@@ -355,9 +364,20 @@ def infer_feature_attributes(
|
|
|
355
364
|
of its weight; given as a dict, the value for each feature is the largest share of its
|
|
356
365
|
weight a significant value of that feature may give up, greater than 0 and at most 1.
|
|
357
366
|
Features not listed give up as much as preserving every rare value requires, which draws
|
|
358
|
-
the weights of their significant values toward the floor that keeps
|
|
359
|
-
|
|
360
|
-
the most cases are preserved and a warning reports how
|
|
367
|
+
the weights of their significant values toward the floor that keeps
|
|
368
|
+
`preserve_rare_values_distilled_min_cases` cases after distillation. When a cap leaves too
|
|
369
|
+
little weight, the rare values with the most cases are preserved and a warning reports how
|
|
370
|
+
many.
|
|
371
|
+
|
|
372
|
+
preserve_rare_values_distilled_min_cases : int, default 3
|
|
373
|
+
(Optional) The number of cases each preserved rare value is expected to keep after
|
|
374
|
+
distillation. It is also the fewest cases a frequent value is expected to keep when its
|
|
375
|
+
case weight is reduced to fund the rare values.
|
|
376
|
+
|
|
377
|
+
preserve_rare_values_min_cases : int, default 15
|
|
378
|
+
(Optional) The number of cases a value needs in the data to be considered for rare value
|
|
379
|
+
preservation. Values with fewer cases keep their case weight and do not fund rare values.
|
|
380
|
+
Must be at least `preserve_rare_values_distilled_min_cases`.
|
|
361
381
|
|
|
362
382
|
rate_boundaries : dict, optional
|
|
363
383
|
(Optional) For time series, specify the rate boundaries in the form
|
|
@@ -377,9 +397,10 @@ def infer_feature_attributes(
|
|
|
377
397
|
}
|
|
378
398
|
}
|
|
379
399
|
|
|
380
|
-
significance_threshold : int,
|
|
381
|
-
(Optional)
|
|
382
|
-
|
|
400
|
+
significance_threshold : int, optional
|
|
401
|
+
(Optional) Deprecated; use `preserve_rare_values_min_cases`, which receives this value.
|
|
402
|
+
The number of cases each rare value keeps after distillation is set only by
|
|
403
|
+
`preserve_rare_values_distilled_min_cases`.
|
|
383
404
|
|
|
384
405
|
tables : Iterable of TableNameProtocol
|
|
385
406
|
(Optional, required for datastores) An Iterable of table names to
|
|
@@ -524,4 +545,45 @@ def infer_feature_attributes(
|
|
|
524
545
|
else:
|
|
525
546
|
raise NotImplementedError("Data not recognized as a DataFrame, AbstractData class, or compatible datastore.")
|
|
526
547
|
|
|
548
|
+
_resolve_rare_value_thresholds(kwargs)
|
|
527
549
|
return infer(**kwargs)
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
def _resolve_rare_value_thresholds(options: dict[str, Any]) -> None:
|
|
553
|
+
"""
|
|
554
|
+
Check the rare value thresholds in `options`, replacing a deprecated `significance_threshold`.
|
|
555
|
+
|
|
556
|
+
A `significance_threshold` is moved to `preserve_rare_values_min_cases` with a deprecation
|
|
557
|
+
warning. The number of cases kept after distillation is set only by
|
|
558
|
+
`preserve_rare_values_distilled_min_cases`.
|
|
559
|
+
|
|
560
|
+
Parameters
|
|
561
|
+
----------
|
|
562
|
+
options : dict
|
|
563
|
+
The keyword arguments given to :func:`infer_feature_attributes`, updated in place.
|
|
564
|
+
|
|
565
|
+
Raises
|
|
566
|
+
------
|
|
567
|
+
ValueError
|
|
568
|
+
If both `significance_threshold` and `preserve_rare_values_min_cases` are given, or
|
|
569
|
+
`preserve_rare_values_min_cases` is less than `preserve_rare_values_distilled_min_cases`.
|
|
570
|
+
"""
|
|
571
|
+
significance_threshold = options.pop("significance_threshold", None)
|
|
572
|
+
if significance_threshold is not None:
|
|
573
|
+
if options.get("preserve_rare_values_min_cases") is not None:
|
|
574
|
+
raise ValueError("`significance_threshold` is deprecated and replaced by "
|
|
575
|
+
"`preserve_rare_values_min_cases`; pass only `preserve_rare_values_min_cases`.")
|
|
576
|
+
warnings.warn(
|
|
577
|
+
"`significance_threshold` is deprecated; use `preserve_rare_values_min_cases`, which receives its value. "
|
|
578
|
+
"The number of cases each rare value keeps after distillation is set by "
|
|
579
|
+
"`preserve_rare_values_distilled_min_cases`.",
|
|
580
|
+
DeprecationWarning, stacklevel=3,
|
|
581
|
+
)
|
|
582
|
+
options["preserve_rare_values_min_cases"] = significance_threshold
|
|
583
|
+
min_cases = options.get("preserve_rare_values_min_cases", PRESERVE_RARE_VALUES_MIN_CASES_DEFAULT)
|
|
584
|
+
distilled_min_cases = options.get("preserve_rare_values_distilled_min_cases",
|
|
585
|
+
PRESERVE_RARE_VALUES_DISTILLED_MIN_CASES_DEFAULT)
|
|
586
|
+
if min_cases < distilled_min_cases:
|
|
587
|
+
raise ValueError(f"`preserve_rare_values_min_cases` ({min_cases}) must be at least "
|
|
588
|
+
f"`preserve_rare_values_distilled_min_cases` ({distilled_min_cases}): a value with fewer "
|
|
589
|
+
"cases in the data than it should keep after distillation cannot keep them.")
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/time_series.py
RENAMED
|
@@ -18,7 +18,8 @@ import psutil
|
|
|
18
18
|
from howso.utilities.feature_attributes.abstract_data import InferFeatureAttributesAbstractData
|
|
19
19
|
from howso.utilities.feature_attributes.base import (
|
|
20
20
|
InferFeatureAttributesBase,
|
|
21
|
-
|
|
21
|
+
PRESERVE_RARE_VALUES_DISTILLED_MIN_CASES_DEFAULT,
|
|
22
|
+
PRESERVE_RARE_VALUES_MIN_CASES_DEFAULT,
|
|
22
23
|
SingleTableFeatureAttributes,
|
|
23
24
|
)
|
|
24
25
|
from howso.utilities.feature_attributes.pandas import InferFeatureAttributesDataFrame
|
|
@@ -386,8 +387,9 @@ class InferFeatureAttributesTimeSeries(ABC):
|
|
|
386
387
|
ordinal_feature_values: t.Optional[dict[str, list[t.Any]]] = None,
|
|
387
388
|
preserve_rare_values: t.Optional[PreserveRareValues] = None,
|
|
388
389
|
preserve_rare_values_caps: t.Optional[PreserveRareValuesCaps] = None,
|
|
390
|
+
preserve_rare_values_distilled_min_cases: int = PRESERVE_RARE_VALUES_DISTILLED_MIN_CASES_DEFAULT,
|
|
391
|
+
preserve_rare_values_min_cases: int = PRESERVE_RARE_VALUES_MIN_CASES_DEFAULT,
|
|
389
392
|
rate_boundaries: t.Optional[dict] = None,
|
|
390
|
-
significance_threshold: int = SIGNIFICANT_THRESHOLD_DEFAULT,
|
|
391
393
|
time_invariant_features: t.Optional[Iterable[str]] = None,
|
|
392
394
|
tight_bounds: t.Optional[Iterable[str]] = None,
|
|
393
395
|
time_feature_is_universal: t.Optional[bool] = None,
|
|
@@ -613,14 +615,16 @@ class InferFeatureAttributesTimeSeries(ABC):
|
|
|
613
615
|
A dict maps each feature name to one of three forms:
|
|
614
616
|
|
|
615
617
|
- A list of values to protect. Each is weighted to keep approximately
|
|
616
|
-
`
|
|
618
|
+
`preserve_rare_values_distilled_min_cases` cases after distillation, funded by the
|
|
619
|
+
feature's other values.
|
|
617
620
|
When not every value fits, those with the most cases are given priority. Without
|
|
618
621
|
`max_distilled_cases`, the multipliers are computed for a default target of 50,000 cases.
|
|
619
622
|
- A list of dicts of "value" and "multiplier", giving the multiplier each value should
|
|
620
623
|
receive, at least 1. The feature's other values are reweighted to fund them so the total
|
|
621
|
-
case weight is unchanged: values with fewer
|
|
622
|
-
weight of 1, and every other value is scaled by one common factor, except that no
|
|
623
|
-
scaled below the number of cases that keeps
|
|
624
|
+
case weight is unchanged: values with fewer than `preserve_rare_values_min_cases` cases
|
|
625
|
+
keep a weight of 1, and every other value is scaled by one common factor, except that no
|
|
626
|
+
value is scaled below the number of cases that keeps
|
|
627
|
+
`preserve_rare_values_distilled_min_cases` after distillation. See
|
|
624
628
|
`preserve_rare_values_caps` to limit how much weight those values give up. Without
|
|
625
629
|
`max_distilled_cases`, the floor is computed for a target of 50,000 cases. If the other
|
|
626
630
|
values cannot fund the multipliers, each multiplier's increase over 1 is scaled down and a
|
|
@@ -649,9 +653,20 @@ class InferFeatureAttributesTimeSeries(ABC):
|
|
|
649
653
|
of its weight; given as a dict, the value for each feature is the largest share of its
|
|
650
654
|
weight a significant value of that feature may give up, greater than 0 and at most 1.
|
|
651
655
|
Features not listed give up as much as preserving every rare value requires, which draws
|
|
652
|
-
the weights of their significant values toward the floor that keeps
|
|
653
|
-
|
|
654
|
-
the most cases are preserved and a warning
|
|
656
|
+
the weights of their significant values toward the floor that keeps
|
|
657
|
+
`preserve_rare_values_distilled_min_cases` cases after distillation. When a cap leaves
|
|
658
|
+
too little weight, the rare values with the most cases are preserved and a warning
|
|
659
|
+
reports how many.
|
|
660
|
+
|
|
661
|
+
preserve_rare_values_distilled_min_cases : int, default 3
|
|
662
|
+
(Optional) The number of cases each preserved rare value is expected to keep after
|
|
663
|
+
distillation. It is also the fewest cases a frequent value is expected to keep when its
|
|
664
|
+
case weight is reduced to fund the rare values.
|
|
665
|
+
|
|
666
|
+
preserve_rare_values_min_cases : int, default 15
|
|
667
|
+
(Optional) The number of cases a value needs in the data to be considered for rare value
|
|
668
|
+
preservation. Values with fewer cases keep their case weight and do not fund rare values.
|
|
669
|
+
Must be at least `preserve_rare_values_distilled_min_cases`.
|
|
655
670
|
|
|
656
671
|
rate_boundaries : dict, default None
|
|
657
672
|
(Optional) For time series, specify the rate boundaries in the form
|
|
@@ -671,10 +686,6 @@ class InferFeatureAttributesTimeSeries(ABC):
|
|
|
671
686
|
}
|
|
672
687
|
}
|
|
673
688
|
|
|
674
|
-
significance_threshold : int, default 30
|
|
675
|
-
(Optional) After data distillation, the number of cases that are expected to result in a
|
|
676
|
-
signal for preserved rare values.
|
|
677
|
-
|
|
678
689
|
tight_bounds: Iterable of str, default None
|
|
679
690
|
(Optional) Set tight min and max bounds for the features
|
|
680
691
|
specified in the Iterable.
|
|
@@ -810,7 +821,8 @@ class InferFeatureAttributesTimeSeries(ABC):
|
|
|
810
821
|
ordinal_feature_values=ordinal_feature_values,
|
|
811
822
|
preserve_rare_values=preserve_rare_values,
|
|
812
823
|
preserve_rare_values_caps=preserve_rare_values_caps,
|
|
813
|
-
|
|
824
|
+
preserve_rare_values_distilled_min_cases=preserve_rare_values_distilled_min_cases,
|
|
825
|
+
preserve_rare_values_min_cases=preserve_rare_values_min_cases,
|
|
814
826
|
tight_bounds=set(tight_bounds) if tight_bounds else None,
|
|
815
827
|
types=types,
|
|
816
828
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: howso-engine
|
|
3
|
-
Version: 68.
|
|
3
|
+
Version: 68.2.0
|
|
4
4
|
Summary: The Howso Engine™ is a natively and fully explainable ML engine, serving as an alternative to black box AI neural networks.
|
|
5
5
|
Author: Howso Incorporated
|
|
6
6
|
Author-email: support@howso.com
|
|
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
|
|
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
|
|
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
|
|
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
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/abstract_data.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/relational.py
RENAMED
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/serializers.py
RENAMED
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/feature_attributes/suggestions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/__init__.py
RENAMED
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/__main__.py
RENAMED
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/_constants.py
RENAMED
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/_helpers.py
RENAMED
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/_output.py
RENAMED
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/_probes.py
RENAMED
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/_types.py
RENAMED
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/checks_cpu.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/main.py
RENAMED
|
File without changes
|
{howso_engine-68.1.0 → howso_engine-68.2.0}/howso/utilities/installation_verification/registry.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
|
|
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
|