dataeval 1.2.0rc1__tar.gz → 1.2.0rc2__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.
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/PKG-INFO +1 -1
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/pyproject.toml +1 -1
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_version.py +2 -2
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_completeness.py +10 -11
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/scope/_coverage.py +173 -39
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/_base.py +10 -1
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/_wasserstein.py +164 -60
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/.gitignore +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/LICENSE +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/README.md +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_embeddings.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_experimental.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_helpers.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_log.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_aggregate.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_collisions.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_columns.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_corrections.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_encoding.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_filters.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_input.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_keyed.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_known.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_links.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_loading.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_metadata.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_reductions.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_serialize.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_source_groups.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_store.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_accumulator.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_base.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_block.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_classification.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_data.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_dataset.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_detection.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_factors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_frames.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_gather.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_instances.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_layout.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_ordering.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_propagation.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_reporting.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_reserved.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_select.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_source_index.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_metadata/_structurers/_tracking.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/_ontology.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/bias/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/bias/_balance.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/bias/_diversity.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/bias/_parity.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/config.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_alignment.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_annotation_match.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_ap_bounds.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_association.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_ber.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_bin.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_base.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_cache.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_descriptivestats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_dimensionstats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_egostats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_hashstats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_persistencestats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_pixelstats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_redundancystats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_register.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_registry.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_video_base.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_video_register.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_calculators/_visualstats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_clusterer.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_combination_scores.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_compute_ratios.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_compute_stats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_concentration.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_consensus.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_coverage.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_divergence.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_diversity.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_effective_n.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_ego_stats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_fast_hdbscan/_cluster_trees.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_fast_hdbscan/_disjoint_set.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_fast_hdbscan/_mst.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_feature_distance.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_hash.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_hash_index.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_image_stats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_label_alignment.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_label_cooccurrence.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_label_coverage.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_label_errors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_label_parity.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_label_reconciliation.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_label_stats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_local_panels.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_metadata_insights.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_mst.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_mutual_info.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_nullmodel.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_ontology_validation.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_parity.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_persistence.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_rank.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_rao_scott.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_sequence_match.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_sequence_residuals.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_temporal.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_track_stats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_uap.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_video_runner.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/core/_video_stats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_camera_travel.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_chain.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_classbalance.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_classfilter.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_crop.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_crops.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_filter.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_frames.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_geometry.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_indices.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_invalidates.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_label_selectors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_limit.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_locate.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_merge.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_planners.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_quality_gate.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_reads.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_relabel.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_resize.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_reverse.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_segments.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_selectchannels.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_selectors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_shuffle.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_split.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_stitch.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_torchvision.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_tracks.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_unzip.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_video_proxies.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/data/_view.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/exceptions.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/extractors/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/extractors/_bovw.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/extractors/_flatten.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/extractors/_geometry.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/extractors/_onnx.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/extractors/_scores.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/extractors/_torch.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/extractors/_uncertainty.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/extractors/_videotorch.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/flags.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/models/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/models/_backends.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/models/_input.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/models/_metadata.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/models/_predictors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/_aggregator.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/_feasibility.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/_feasibility_classification.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/_feasibility_constants.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/_feasibility_decide.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/_feasibility_evidence.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/_feasibility_target.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/_feasibility_units.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/_output.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/_sufficiency.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/performance/schedules.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/protocols.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/py.typed +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/quality/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/quality/_duplicates.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/quality/_factor_stats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/quality/_outliers.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/quality/_outliers_neighbors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/quality/_outliers_rows.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/quality/_outliers_scores.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/quality/_shared.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/scope/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/scope/_prioritize.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/scope/_representation.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/_chunk.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/_domain_classifier.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/_domain_spec.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/_kneighbors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/_known_domains.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/_mmd.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/_reconstruction.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_drift/_univariate.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_ood/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_ood/_base.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_ood/_domain_classifier.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_ood/_kneighbors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_ood/_reconstruction.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_shared/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_shared/_domain_classifier.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_shared/_kneighbors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/_shared/_reconstruction.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/shift/update_strategies.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_array.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_config.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_evaluator.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_execution.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_factors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_index.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_known_factors.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_ontology.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_output.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_removal.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_schema.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_target.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_task.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/types/_track.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/_array.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/_internal.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/_mask.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/_merge.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/data.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/losses.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/models.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/onnx.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/preprocessing.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/scipy/__init__.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/scipy/stats.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/thresholds.py +0 -0
- {dataeval-1.2.0rc1 → dataeval-1.2.0rc2}/src/dataeval/utils/training.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: dataeval
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.0rc2
|
|
4
4
|
Summary: DataEval provides a simple interface to characterize image data and its impact on model performance across classification and object-detection tasks
|
|
5
5
|
Project-URL: Homepage, https://dataeval.ai/
|
|
6
6
|
Project-URL: Repository, https://github.com/aria-ml/dataeval/
|
|
@@ -130,7 +130,7 @@ docs = [
|
|
|
130
130
|
"numpy>=1.24.2", # floor capped by the JATIC program standard; uv.lock resolves current
|
|
131
131
|
"av>=12.0.0",
|
|
132
132
|
"certifi>=2024.07.04",
|
|
133
|
-
"dataeval-plots[plotly]>=0.0.
|
|
133
|
+
"dataeval-plots[plotly]>=0.0.16",
|
|
134
134
|
"ipykernel>=6.26.0",
|
|
135
135
|
"ipywidgets>=8.1.1",
|
|
136
136
|
"jinja2>=3.1.6",
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 2, 0, '
|
|
21
|
+
__version__ = version = '1.2.0rc2'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 2, 0, 'rc2')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -27,10 +27,13 @@ class CompletenessResult(TypedDict):
|
|
|
27
27
|
space actually spanned by embeddings.
|
|
28
28
|
nearest_neighbor_pairs : Sequence[tuple[int, int]]
|
|
29
29
|
Sequence of tuples (i, j) representing point indices and their nearest neighbors,
|
|
30
|
-
sorted by decreasing nearest neighbor distance. Each pair appears only once
|
|
30
|
+
sorted by decreasing nearest neighbor distance. Each pair appears only once, so two
|
|
31
|
+
points that are each other's nearest neighbor share one entry. ``j`` is never ``i``,
|
|
32
|
+
even when ``i`` has an exact duplicate.
|
|
31
33
|
nearest_neighbor_distances : Sequence[float]
|
|
32
34
|
Distance between each pair in ``nearest_neighbor_pairs``, aligned 1:1 and sharing
|
|
33
35
|
the same decreasing order. The small-distance tail flags near-duplicate samples.
|
|
36
|
+
Each point's own nearest-neighbor distance is the smallest among the pairs it is in.
|
|
34
37
|
"""
|
|
35
38
|
|
|
36
39
|
completeness: float
|
|
@@ -246,16 +249,12 @@ def completeness(embeddings: Array) -> CompletenessResult:
|
|
|
246
249
|
nearest_neighbor_distances=[],
|
|
247
250
|
)
|
|
248
251
|
|
|
249
|
-
#
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
# Extract the actual nearest neighbor (second column, index 1)
|
|
257
|
-
nearest_neighbors = indices[:, 1]
|
|
258
|
-
nearest_distances = distances[:, 1]
|
|
252
|
+
# Each point's nearest other point. Querying the fitted points themselves (no X) makes sklearn drop each
|
|
253
|
+
# point from its own neighbors by index, which stays right for exact duplicates: there a zero-distance tie
|
|
254
|
+
# can rank the point after its copy, so "the first neighbor is the point itself" does not hold.
|
|
255
|
+
distances, indices = NearestNeighbors(n_neighbors=1).fit(embeddings).kneighbors()
|
|
256
|
+
nearest_neighbors = indices[:, 0]
|
|
257
|
+
nearest_distances = distances[:, 0]
|
|
259
258
|
|
|
260
259
|
# Create pairs, deduplicating so each pair appears only once
|
|
261
260
|
seen_pairs = set()
|
|
@@ -15,8 +15,8 @@ label counts cannot reveal:
|
|
|
15
15
|
varies (via :func:`~dataeval.core.completeness`). A class can spread far yet vary along a
|
|
16
16
|
single axis — all images shot from one angle, lighting or zoom aside — which dispersion's
|
|
17
17
|
single radius cannot distinguish.
|
|
18
|
-
* **near-duplicate fraction** — the *redundancy*, the share of a class
|
|
19
|
-
|
|
18
|
+
* **near-duplicate fraction** — the *redundancy*, the share of a class's images whose nearest
|
|
19
|
+
neighbor is unusually close (repeated stock frames), derived from the same computation.
|
|
20
20
|
|
|
21
21
|
Alongside them, the global :func:`~dataeval.core.coverage_adaptive` result flags individual
|
|
22
22
|
samples in under-sampled regions of the whole space.
|
|
@@ -41,12 +41,13 @@ from pydantic import PositiveFloat, PositiveInt
|
|
|
41
41
|
from dataeval import Metadata
|
|
42
42
|
from dataeval._helpers import BareLabels, is_labels_like, reject_filtered_metadata
|
|
43
43
|
from dataeval._log import get_logger
|
|
44
|
+
from dataeval.core._completeness import CompletenessResult
|
|
44
45
|
from dataeval.core._completeness import completeness as _completeness
|
|
45
46
|
from dataeval.core._coverage import CoverageResult, coverage_adaptive, coverage_naive
|
|
46
47
|
from dataeval.exceptions import ShapeMismatchError
|
|
47
48
|
from dataeval.protocols import AnnotatedDataset, Array, ArrayLike, FeatureExtractor, LabelsLike
|
|
48
49
|
from dataeval.types import ClassAxis, DataFrameOutput, Evaluator, EvaluatorConfig, set_metadata
|
|
49
|
-
from dataeval.types._config import OpenUnitInterval
|
|
50
|
+
from dataeval.types._config import OpenUnitInterval, UnitInterval
|
|
50
51
|
|
|
51
52
|
_logger = get_logger(__name__)
|
|
52
53
|
|
|
@@ -61,6 +62,10 @@ _PER_CLASS_SCHEMA: dict[str, pl.DataType] = {
|
|
|
61
62
|
"isotropy": pl.Float64(),
|
|
62
63
|
"near_duplicate_fraction": pl.Float64(),
|
|
63
64
|
"assessable": pl.Boolean(),
|
|
65
|
+
# Appended, so the columns released before them keep their positions.
|
|
66
|
+
"is_clustered": pl.Boolean(),
|
|
67
|
+
"is_one_dimensional": pl.Boolean(),
|
|
68
|
+
"has_near_duplicates": pl.Boolean(),
|
|
64
69
|
}
|
|
65
70
|
|
|
66
71
|
|
|
@@ -69,6 +74,19 @@ def _mean_dispersion(points: NDArray[np.float64]) -> float:
|
|
|
69
74
|
return float(np.linalg.norm(points - points.mean(axis=0), axis=1).mean())
|
|
70
75
|
|
|
71
76
|
|
|
77
|
+
def _nearest_distances(result: CompletenessResult, n: int) -> NDArray[np.float64]:
|
|
78
|
+
"""Each of the ``n`` points' distance to its nearest other point, from ``completeness``'s pairs.
|
|
79
|
+
|
|
80
|
+
The pairs list two mutual nearest neighbors once, so they count pairs, not points. A point's
|
|
81
|
+
nearest-neighbor distance is the smallest among the pairs it is in.
|
|
82
|
+
"""
|
|
83
|
+
nearest = np.full(n, np.inf)
|
|
84
|
+
distances = np.asarray(result["nearest_neighbor_distances"], dtype=np.float64)
|
|
85
|
+
for points in np.asarray(result["nearest_neighbor_pairs"], dtype=np.intp).reshape(-1, 2).T:
|
|
86
|
+
np.minimum.at(nearest, points, distances)
|
|
87
|
+
return nearest
|
|
88
|
+
|
|
89
|
+
|
|
72
90
|
class CoverageOutput(DataFrameOutput):
|
|
73
91
|
"""
|
|
74
92
|
A dataset's per-class embedding-space coverage.
|
|
@@ -76,10 +94,47 @@ class CoverageOutput(DataFrameOutput):
|
|
|
76
94
|
The wrapped DataFrame is the per-class breakdown — one row per class, sorted with the
|
|
77
95
|
lowest-dispersion assessable classes first (the ones most worth collecting varied data
|
|
78
96
|
for) and unassessable classes last — with columns ``class``, ``count``, ``uncovered``,
|
|
79
|
-
``uncovered_fraction``, ``dispersion``, ``isotropy``, ``near_duplicate_fraction``,
|
|
80
|
-
``assessable
|
|
81
|
-
|
|
82
|
-
it as attributes.
|
|
97
|
+
``uncovered_fraction``, ``dispersion``, ``isotropy``, ``near_duplicate_fraction``,
|
|
98
|
+
``assessable``, ``is_clustered``, ``is_one_dimensional``, and ``has_near_duplicates``.
|
|
99
|
+
``isotropy`` and ``near_duplicate_fraction`` are null for classes below the sample floors
|
|
100
|
+
that make them meaningful. The sample-level coverage detail hangs off it as attributes.
|
|
101
|
+
|
|
102
|
+
The last three columns are a verdict on each variety signal, with cutoffs that are
|
|
103
|
+
parameters of :class:`Coverage`. They are independent, and a class can trip more than one:
|
|
104
|
+
|
|
105
|
+
- is_clustered: bool - True if dispersion < dispersion_factor (default 0.5): the class
|
|
106
|
+
spreads less than half as far from its centroid as the median class.
|
|
107
|
+
- is_one_dimensional: bool - True if isotropy < isotropy_factor (default 0.5) x the median
|
|
108
|
+
isotropy of the classes that report one, the class itself included. Isotropy is not
|
|
109
|
+
normalized by the evaluator, since it depends on the embedding dimension and on any
|
|
110
|
+
reduction applied first, so it is judged against its peers.
|
|
111
|
+
- has_near_duplicates: bool - True if near_duplicate_fraction > near_duplicate_threshold
|
|
112
|
+
(default 0.1).
|
|
113
|
+
|
|
114
|
+
A flag is null where it cannot judge, which is new: the flags of
|
|
115
|
+
:class:`~dataeval.bias.Balance` and :class:`~dataeval.bias.Diversity` are never null. A
|
|
116
|
+
flag is null where its signal is null, that is, for a class below ``min_class_samples`` or,
|
|
117
|
+
for ``is_one_dimensional``, below the isotropy sample floor. It is also null on every row
|
|
118
|
+
where the median it is judged against is not positive. A median spread of 0 leaves
|
|
119
|
+
``dispersion`` in raw embedding units, and a median isotropy of 0 would flag no class at
|
|
120
|
+
all. With a single assessable class the median is the class itself, so neither
|
|
121
|
+
``is_clustered`` nor ``is_one_dimensional`` can trip however flat the class is.
|
|
122
|
+
|
|
123
|
+
The defaults are conservative, so a flag means a class has collapsed, not that it sits a
|
|
124
|
+
little below its peers. Tighten a factor to catch a partial collapse. They are tuned for
|
|
125
|
+
deep embeddings, and two signals depend on more than the data:
|
|
126
|
+
|
|
127
|
+
- Isotropy rises with class size, so a small class reads lower beside large ones.
|
|
128
|
+
Tighten ``isotropy_factor`` only for classes of similar size.
|
|
129
|
+
- The near-duplicate share of a class with no duplicates rises as the embedding dimension
|
|
130
|
+
falls. On simulated Gaussian classes of 100 to 400 images it exceeded 0.1 for most
|
|
131
|
+
classes in 2 dimensions, for about half in 3 and for a few up to 7, and for none in 8
|
|
132
|
+
or more. Raise ``near_duplicate_threshold`` before reading ``has_near_duplicates`` on a
|
|
133
|
+
low-dimensional embedding, such as a few principal components.
|
|
134
|
+
|
|
135
|
+
.. versionadded:: 1.2
|
|
136
|
+
The ``is_clustered``, ``is_one_dimensional`` and ``has_near_duplicates`` columns,
|
|
137
|
+
after ``assessable`` so the earlier columns keep their positions.
|
|
83
138
|
|
|
84
139
|
Attributes
|
|
85
140
|
----------
|
|
@@ -130,8 +185,12 @@ class Coverage(Evaluator):
|
|
|
130
185
|
class); low means clustered even if numerous.
|
|
131
186
|
* **isotropy** — shape of that spread (in how many independent directions the class
|
|
132
187
|
varies); low means it varies along few axes even when dispersion is high.
|
|
133
|
-
* **near_duplicate_fraction** — redundancy (share of the class
|
|
134
|
-
|
|
188
|
+
* **near_duplicate_fraction** — redundancy (share of the class's images whose nearest
|
|
189
|
+
neighbor is unusually close); high means repeated / near-identical samples.
|
|
190
|
+
|
|
191
|
+
Each signal comes with a boolean verdict, ``is_clustered``, ``is_one_dimensional`` and
|
|
192
|
+
``has_near_duplicates``, so the output table is the per-class gap report. See
|
|
193
|
+
:class:`CoverageOutput` for the exact rules and when a flag is null.
|
|
135
194
|
|
|
136
195
|
Parameters
|
|
137
196
|
----------
|
|
@@ -156,8 +215,27 @@ class Coverage(Evaluator):
|
|
|
156
215
|
effective-dimension estimate is degenerate when samples do not exceed dimensions).
|
|
157
216
|
When None, defaults to one more than the embedding dimensionality.
|
|
158
217
|
near_duplicate_factor : float, default 0.5
|
|
159
|
-
|
|
160
|
-
fraction of
|
|
218
|
+
An image counts as a near-duplicate when its nearest neighbor in its class is no farther
|
|
219
|
+
than this fraction of a typical class's median nearest-neighbor distance (scale-free).
|
|
220
|
+
A scale for a distance, which sets ``near_duplicate_fraction``. Not to be confused with
|
|
221
|
+
``near_duplicate_threshold``, the share of images that sets the flag.
|
|
222
|
+
dispersion_factor : float, default 0.5
|
|
223
|
+
``is_clustered`` is True where ``dispersion < dispersion_factor``, that is, where a class
|
|
224
|
+
spreads less than this share of the median class's spread. Must be in (0, 1); a factor
|
|
225
|
+
near 1 flags about half the classes by construction.
|
|
226
|
+
|
|
227
|
+
.. versionadded:: 1.2
|
|
228
|
+
isotropy_factor : float, default 0.5
|
|
229
|
+
``is_one_dimensional`` is True where ``isotropy < isotropy_factor * median(isotropy)``,
|
|
230
|
+
the median taken over the classes that report an isotropy. Must be in (0, 1).
|
|
231
|
+
|
|
232
|
+
.. versionadded:: 1.2
|
|
233
|
+
near_duplicate_threshold : float, default 0.1
|
|
234
|
+
``has_near_duplicates`` is True where ``near_duplicate_fraction`` is above this share of
|
|
235
|
+
the class's images. Must be in [0, 1]: 0 flags any near-duplicate, and 1 turns the flag
|
|
236
|
+
off. A share, where ``near_duplicate_factor`` is a distance scale.
|
|
237
|
+
|
|
238
|
+
.. versionadded:: 1.2
|
|
161
239
|
config : Coverage.Config or None, default None
|
|
162
240
|
Optional configuration object; parameters passed directly to ``__init__`` override
|
|
163
241
|
its values.
|
|
@@ -185,10 +263,25 @@ class Coverage(Evaluator):
|
|
|
185
263
|
high-dimensional extractor most classes fall below that floor and report ``isotropy``
|
|
186
264
|
as null rather than zero. Reduce the embedding dimensionality (for example with PCA) if
|
|
187
265
|
you need the signal on classes of a few hundred samples. ``near_duplicate_fraction`` is the
|
|
188
|
-
share of
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
266
|
+
share of a class's images whose nearest other image in the class is within
|
|
267
|
+
``near_duplicate_factor`` x the *median* across assessable classes of each class's median
|
|
268
|
+
nearest-neighbor distance, surfacing repeated / near-identical samples that inflate counts
|
|
269
|
+
without adding variety. Both images of a near-identical pair count, and an exact copy counts
|
|
270
|
+
the same as one that differs by float noise. Like ``dispersion``, the scale comes from the
|
|
271
|
+
peers rather than the class itself, so a tight clump that is most of its class still shows;
|
|
272
|
+
the cost is that a class whose images sit that close together by nature reads high too.
|
|
273
|
+
With a single assessable class there are no peers, and a clump of more than half of it goes
|
|
274
|
+
unflagged. Embeddings are auto-rescaled to the unit interval for the coverage
|
|
275
|
+
computation.
|
|
276
|
+
|
|
277
|
+
The flag defaults are conservative and tuned for deep embeddings: at 0.5 a flag means a
|
|
278
|
+
class has collapsed. A flag is null where its signal is null, and on every row where the
|
|
279
|
+
median it is judged against is not positive. On an embedding of fewer than about 8
|
|
280
|
+
dimensions, healthy classes can have a near-duplicate share above the 0.1 default, so raise
|
|
281
|
+
``near_duplicate_threshold`` there. Isotropy rises with class size, so tighten
|
|
282
|
+
``isotropy_factor`` only for classes of similar size.
|
|
283
|
+
|
|
284
|
+
This evaluator assumes one embedding per label (image classification). For
|
|
192
285
|
object detection, wrap the dataset with :class:`~dataeval.data.DetectionCrops` to present
|
|
193
286
|
its boxes as an image-classification dataset (one crop per detection, aligned 1:1 with the
|
|
194
287
|
labels) and evaluate that, or supply detection-level embeddings you have computed yourself.
|
|
@@ -244,8 +337,17 @@ class Coverage(Evaluator):
|
|
|
244
337
|
isotropy_min_samples : int or None, default None
|
|
245
338
|
Minimum samples for a class's isotropy to be reported (None: dims + 1).
|
|
246
339
|
near_duplicate_factor : float, default 0.5
|
|
247
|
-
Fraction of
|
|
248
|
-
near-duplicate
|
|
340
|
+
Fraction of a typical class's median nearest-neighbor distance within which an
|
|
341
|
+
image's nearest neighbor makes it a near-duplicate (a distance scale, which sets
|
|
342
|
+
``near_duplicate_fraction``).
|
|
343
|
+
dispersion_factor : float, default 0.5
|
|
344
|
+
``is_clustered`` is True where ``dispersion`` is below this, in (0, 1).
|
|
345
|
+
isotropy_factor : float, default 0.5
|
|
346
|
+
``is_one_dimensional`` is True where ``isotropy`` is below this share of the median
|
|
347
|
+
isotropy, in (0, 1).
|
|
348
|
+
near_duplicate_threshold : float, default 0.1
|
|
349
|
+
``has_near_duplicates`` is True where ``near_duplicate_fraction`` is above this
|
|
350
|
+
share of images, in [0, 1].
|
|
249
351
|
"""
|
|
250
352
|
|
|
251
353
|
extractor: FeatureExtractor | None = None
|
|
@@ -256,6 +358,9 @@ class Coverage(Evaluator):
|
|
|
256
358
|
min_class_samples: PositiveInt = 20
|
|
257
359
|
isotropy_min_samples: PositiveInt | None = None
|
|
258
360
|
near_duplicate_factor: PositiveFloat = 0.5
|
|
361
|
+
dispersion_factor: OpenUnitInterval = 0.5
|
|
362
|
+
isotropy_factor: OpenUnitInterval = 0.5
|
|
363
|
+
near_duplicate_threshold: UnitInterval = 0.1
|
|
259
364
|
|
|
260
365
|
# Set by apply_config from Config.
|
|
261
366
|
extractor: FeatureExtractor | None
|
|
@@ -266,6 +371,9 @@ class Coverage(Evaluator):
|
|
|
266
371
|
min_class_samples: int
|
|
267
372
|
isotropy_min_samples: int | None
|
|
268
373
|
near_duplicate_factor: float
|
|
374
|
+
dispersion_factor: float
|
|
375
|
+
isotropy_factor: float
|
|
376
|
+
near_duplicate_threshold: float
|
|
269
377
|
config: Config
|
|
270
378
|
|
|
271
379
|
def __init__(
|
|
@@ -279,6 +387,9 @@ class Coverage(Evaluator):
|
|
|
279
387
|
min_class_samples: int | None = None,
|
|
280
388
|
isotropy_min_samples: int | None = None,
|
|
281
389
|
near_duplicate_factor: float | None = None,
|
|
390
|
+
dispersion_factor: float | None = None,
|
|
391
|
+
isotropy_factor: float | None = None,
|
|
392
|
+
near_duplicate_threshold: float | None = None,
|
|
282
393
|
config: Config | None = None,
|
|
283
394
|
) -> None:
|
|
284
395
|
super().__init__(locals())
|
|
@@ -340,20 +451,6 @@ class Coverage(Evaluator):
|
|
|
340
451
|
"""Minimum class size for a non-degenerate isotropy estimate (samples must exceed dims)."""
|
|
341
452
|
return self.isotropy_min_samples if self.isotropy_min_samples is not None else dim + 1
|
|
342
453
|
|
|
343
|
-
def _near_duplicate_fraction(self, distances: Any) -> float | None:
|
|
344
|
-
"""Share of nearest-neighbor pairs closer than ``near_duplicate_factor`` x the class median.
|
|
345
|
-
|
|
346
|
-
Relative-to-median so it is scale-free. A zero median means at least half the pairs are
|
|
347
|
-
exact duplicates, so the exact-duplicate share is reported instead.
|
|
348
|
-
"""
|
|
349
|
-
dists = np.asarray(distances, dtype=np.float64)
|
|
350
|
-
if dists.size == 0:
|
|
351
|
-
return None
|
|
352
|
-
median = float(np.median(dists))
|
|
353
|
-
if median == 0.0:
|
|
354
|
-
return float(np.mean(dists == 0.0))
|
|
355
|
-
return float(np.mean(dists < self.near_duplicate_factor * median))
|
|
356
|
-
|
|
357
454
|
def _per_class(
|
|
358
455
|
self,
|
|
359
456
|
embeddings: NDArray[np.float64],
|
|
@@ -376,7 +473,8 @@ class Coverage(Evaluator):
|
|
|
376
473
|
# Normalize by the median assessable class, so a typical class scores ~1 regardless of
|
|
377
474
|
# how far apart the classes sit in the embedding space (the global spread would conflate
|
|
378
475
|
# within-class variety with between-class separation). Avoid /0.
|
|
379
|
-
|
|
476
|
+
median_spread = float(np.median(list(raw_spread.values()))) if raw_spread else 0.0
|
|
477
|
+
reference = median_spread or 1.0
|
|
380
478
|
|
|
381
479
|
# One completeness pass per assessable class yields both directional variety (isotropy)
|
|
382
480
|
# and the nearest-neighbor distances that expose near-duplicates.
|
|
@@ -388,27 +486,46 @@ class Coverage(Evaluator):
|
|
|
388
486
|
# don't exceed dimensions, so it needs more samples than dispersion (default: more than dims).
|
|
389
487
|
isotropy_floor = max(self.min_class_samples, self._isotropy_floor(embeddings.shape[1]))
|
|
390
488
|
isotropy = {cls: float(r["isotropy"]) for cls, r in results.items() if counts[cls] >= isotropy_floor}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
489
|
+
# Isotropy is not normalized, so its flag compares each class with the median class instead.
|
|
490
|
+
median_isotropy = float(np.median(list(isotropy.values()))) if isotropy else 0.0
|
|
491
|
+
# Each image's distance to its nearest other image in its class; a class of one has none.
|
|
492
|
+
nearest = {cls: _nearest_distances(r, counts[cls]) for cls, r in results.items() if counts[cls] > 1}
|
|
493
|
+
# Like dispersion, measure against a typical (median) class's nearest-neighbor spacing rather than
|
|
494
|
+
# the class's own, which a tight clump covering most of the class would set. `<=` keeps exact
|
|
495
|
+
# duplicates when that spacing is itself zero.
|
|
496
|
+
spacing = float(np.median([np.median(d) for d in nearest.values()])) if nearest else 0.0
|
|
497
|
+
near_duplicate = {cls: float(np.mean(d <= self.near_duplicate_factor * spacing)) for cls, d in nearest.items()}
|
|
394
498
|
|
|
395
499
|
rows: list[dict[str, Any]] = []
|
|
396
500
|
for cls, mask in masks.items():
|
|
397
501
|
count = counts[cls]
|
|
398
502
|
uncovered = int(is_uncovered[mask].sum())
|
|
399
503
|
assessable = cls in raw_spread
|
|
504
|
+
dispersion = raw_spread[cls] / reference if assessable else None
|
|
505
|
+
class_isotropy = isotropy.get(cls)
|
|
506
|
+
duplicates = near_duplicate.get(cls)
|
|
400
507
|
rows.append({
|
|
401
508
|
"class": index2label.get(cls, str(cls)),
|
|
402
509
|
"count": count,
|
|
403
510
|
"uncovered": uncovered,
|
|
404
511
|
"uncovered_fraction": uncovered / count if count else 0.0,
|
|
405
512
|
# Spread relative to a typical class; < 1 == clustered / near-duplicate.
|
|
406
|
-
"dispersion":
|
|
513
|
+
"dispersion": dispersion,
|
|
407
514
|
# In how many independent directions the class varies; null when too few samples.
|
|
408
|
-
"isotropy":
|
|
409
|
-
# Share of the class
|
|
410
|
-
"near_duplicate_fraction":
|
|
515
|
+
"isotropy": class_isotropy,
|
|
516
|
+
# Share of the class's images whose nearest neighbor is a near-duplicate.
|
|
517
|
+
"near_duplicate_fraction": duplicates,
|
|
411
518
|
"assessable": assessable,
|
|
519
|
+
# A flag is null where its signal is, or where the median it is judged against is not positive.
|
|
520
|
+
"is_clustered": (
|
|
521
|
+
dispersion < self.dispersion_factor if dispersion is not None and median_spread > 0 else None
|
|
522
|
+
),
|
|
523
|
+
"is_one_dimensional": (
|
|
524
|
+
class_isotropy < self.isotropy_factor * median_isotropy
|
|
525
|
+
if class_isotropy is not None and median_isotropy > 0
|
|
526
|
+
else None
|
|
527
|
+
),
|
|
528
|
+
"has_near_duplicates": duplicates > self.near_duplicate_threshold if duplicates is not None else None,
|
|
412
529
|
})
|
|
413
530
|
# Lowest-dispersion assessable classes first (most worth broadening); unassessable last.
|
|
414
531
|
return sorted(rows, key=lambda row: (not row["assessable"], row["dispersion"] or 0.0, row["class"]))
|
|
@@ -474,6 +591,23 @@ class Coverage(Evaluator):
|
|
|
474
591
|
│ plane ┆ 27 ┆ 0 ┆ 1.194517 │
|
|
475
592
|
│ person ┆ 20 ┆ 1 ┆ 1.488841 │
|
|
476
593
|
└────────┴───────┴───────────┴────────────┘
|
|
594
|
+
|
|
595
|
+
The flags give the verdict. ``car`` spreads less than half as far as the median class.
|
|
596
|
+
``is_one_dimensional`` is null because no class has more crops than the embedding has
|
|
597
|
+
dimensions, so none reports an isotropy:
|
|
598
|
+
|
|
599
|
+
>>> result.data().select("class", "is_clustered", "is_one_dimensional", "has_near_duplicates")
|
|
600
|
+
shape: (4, 4)
|
|
601
|
+
┌────────┬──────────────┬────────────────────┬─────────────────────┐
|
|
602
|
+
│ class ┆ is_clustered ┆ is_one_dimensional ┆ has_near_duplicates │
|
|
603
|
+
│ --- ┆ --- ┆ --- ┆ --- │
|
|
604
|
+
│ str ┆ bool ┆ bool ┆ bool │
|
|
605
|
+
╞════════╪══════════════╪════════════════════╪═════════════════════╡
|
|
606
|
+
│ car ┆ true ┆ null ┆ false │
|
|
607
|
+
│ boat ┆ false ┆ null ┆ false │
|
|
608
|
+
│ plane ┆ false ┆ null ┆ false │
|
|
609
|
+
│ person ┆ false ┆ null ┆ false │
|
|
610
|
+
└────────┴──────────────┴────────────────────┴─────────────────────┘
|
|
477
611
|
"""
|
|
478
612
|
reject_filtered_metadata(dataset, "Coverage")
|
|
479
613
|
|
|
@@ -102,6 +102,9 @@ class DriftOutput(DictOutput, Generic[TDetails]):
|
|
|
102
102
|
Populated when the detector's ``extractor`` is a
|
|
103
103
|
:class:`~dataeval.protocols.NamedFeatureExtractor`, such as
|
|
104
104
|
:class:`~dataeval.Metadata`; empty otherwise.
|
|
105
|
+
baseline : Sequence[float]
|
|
106
|
+
Metric value of each reference chunk, from which the thresholds are
|
|
107
|
+
derived. Populated in chunked mode and empty otherwise.
|
|
105
108
|
"""
|
|
106
109
|
|
|
107
110
|
drifted: bool
|
|
@@ -110,6 +113,11 @@ class DriftOutput(DictOutput, Generic[TDetails]):
|
|
|
110
113
|
metric_name: str
|
|
111
114
|
details: TDetails
|
|
112
115
|
feature_names: Sequence[str] = ()
|
|
116
|
+
baseline: Sequence[float] = ()
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def plot_type(self) -> Literal["drift"]:
|
|
120
|
+
return "drift"
|
|
113
121
|
|
|
114
122
|
|
|
115
123
|
@dataclass(frozen=True, repr=False)
|
|
@@ -550,7 +558,7 @@ class ChunkedDrift(Generic[TDetails]):
|
|
|
550
558
|
*reference_data : Any
|
|
551
559
|
Reference dataset(s), forwarded verbatim to the underlying detector's
|
|
552
560
|
``fit()``. Most detectors take a single reference; detectors with a
|
|
553
|
-
|
|
561
|
+
validation baseline (e.g. :class:`DriftWasserstein`) take both a
|
|
554
562
|
training and a validation reference. When the underlying detector has an
|
|
555
563
|
``extractor`` configured, each reference may be any input the extractor
|
|
556
564
|
accepts (e.g. a full MAITE dataset or raw images); otherwise each must be
|
|
@@ -700,6 +708,7 @@ class ChunkedDrift(Generic[TDetails]):
|
|
|
700
708
|
distance=distance,
|
|
701
709
|
metric_name=self._detector._metric_name,
|
|
702
710
|
feature_names=self._detector._feature_names,
|
|
711
|
+
baseline=tuple(float(v) for v in self._baseline_values),
|
|
703
712
|
details=df,
|
|
704
713
|
)
|
|
705
714
|
|