sdmetrics 0.27.3.dev0__tar.gz → 0.28.1.dev0__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.
- {sdmetrics-0.27.3.dev0/sdmetrics.egg-info → sdmetrics-0.28.1.dev0}/PKG-INFO +1 -1
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/pyproject.toml +1 -1
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/__init__.py +1 -1
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/_utils_metadata.py +24 -26
- sdmetrics-0.28.1.dev0/sdmetrics/demos/single_table/metadata.json +72 -0
- sdmetrics-0.28.1.dev0/sdmetrics/demos/timeseries/metadata.json +33 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/demos.py +5 -10
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/detection/parent_child.py +2 -2
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/multi_single_table.py +2 -2
- sdmetrics-0.28.1.dev0/sdmetrics/reports/__init__.py +38 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/base_report.py +36 -6
- sdmetrics-0.28.1.dev0/sdmetrics/reports/base_unified_report.py +118 -0
- sdmetrics-0.28.1.dev0/sdmetrics/reports/diagnostic_report.py +23 -0
- sdmetrics-0.28.1.dev0/sdmetrics/reports/multi_table/__init__.py +21 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/base_multi_table_report.py +1 -1
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/diagnostic_report.py +3 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/quality_report.py +9 -2
- sdmetrics-0.28.1.dev0/sdmetrics/reports/quality_report.py +28 -0
- sdmetrics-0.28.1.dev0/sdmetrics/reports/single_table/__init__.py +21 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/_properties/base.py +7 -2
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/_properties/boundary.py +6 -2
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/_properties/column_pair_trends.py +15 -9
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/_properties/column_shapes.py +3 -2
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/_properties/coverage.py +3 -2
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/_properties/data_validity.py +13 -4
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/diagnostic_report.py +3 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/quality_report.py +9 -2
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/utils.py +19 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/base.py +26 -10
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/data_augmentation/base.py +7 -3
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/data_augmentation/utils.py +2 -2
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/detection/base.py +13 -8
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/equalized_odds.py +2 -1
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/dcr_baseline_protection.py +3 -1
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/dcr_overfitting_protection.py +3 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/dcr_utils.py +2 -1
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/utils.py +4 -2
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/timeseries/base.py +6 -6
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/timeseries/detection.py +3 -1
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/timeseries/efficacy/base.py +3 -1
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/utils.py +79 -5
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0/sdmetrics.egg-info}/PKG-INFO +1 -1
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics.egg-info/SOURCES.txt +7 -4
- sdmetrics-0.27.3.dev0/sdmetrics/demos/single_table/metadata.json +0 -68
- sdmetrics-0.27.3.dev0/sdmetrics/demos/timeseries/metadata.json +0 -29
- sdmetrics-0.27.3.dev0/sdmetrics/reports/__init__.py +0 -13
- sdmetrics-0.27.3.dev0/sdmetrics/reports/multi_table/__init__.py +0 -9
- sdmetrics-0.27.3.dev0/sdmetrics/reports/single_table/__init__.py +0 -9
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/LICENSE +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/README.md +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/base.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/column_pairs/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/column_pairs/base.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/column_pairs/statistical/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/column_pairs/statistical/cardinality_boundary_adherence.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/column_pairs/statistical/contingency_similarity.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/column_pairs/statistical/correlation_similarity.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/column_pairs/statistical/inter_row_msas.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/column_pairs/statistical/kl_divergence.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/column_pairs/statistical/referential_integrity.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/column_pairs/statistical/statistic_msas.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/demos/multi_table/metadata.json +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/demos/multi_table/sessions_real.csv +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/demos/multi_table/sessions_synthetic.csv +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/demos/multi_table/transactions_real.csv +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/demos/multi_table/transactions_synthetic.csv +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/demos/multi_table/users_real.csv +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/demos/multi_table/users_synthetic.csv +0 -0
- /sdmetrics-0.27.3.dev0/sdmetrics/demos/single_table/real.csv → /sdmetrics-0.28.1.dev0/sdmetrics/demos/single_table/student_placements_real.csv +0 -0
- /sdmetrics-0.27.3.dev0/sdmetrics/demos/single_table/synthetic.csv → /sdmetrics-0.28.1.dev0/sdmetrics/demos/single_table/student_placements_synthetic.csv +0 -0
- /sdmetrics-0.27.3.dev0/sdmetrics/demos/timeseries/real.csv → /sdmetrics-0.28.1.dev0/sdmetrics/demos/timeseries/timeseries_real.csv +0 -0
- /sdmetrics-0.27.3.dev0/sdmetrics/demos/timeseries/synthetic.csv → /sdmetrics-0.28.1.dev0/sdmetrics/demos/timeseries/timeseries_synthetic.csv +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/errors.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/goal.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/README.md +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/base.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/detection/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/detection/base.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/statistical/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/statistical/cardinality_shape_similarity.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/statistical/cardinality_statistic_similarity.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/base.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/boundary.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/cardinality.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/column_pair_trends.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/column_shapes.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/coverage.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/data_validity.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/inter_table_trends.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/relationship_validity.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/structure.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/_properties/synthesis.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/_properties/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/_properties/structure.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/_properties/synthesis.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/single_table/plot_utils.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/README.md +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/base.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/boundary_adherence.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/category_adherence.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/category_coverage.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/cstest.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/key_uniqueness.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/kscomplement.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/missing_value_similarity.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/range_coverage.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/sequence_length_similarity.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/statistic_similarity.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_column/statistical/tv_complement.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/README.md +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/bayesian_network.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/data_augmentation/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/data_augmentation/binary_classifier_precision_efficacy.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/data_augmentation/binary_classifier_recall_efficacy.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/detection/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/detection/sklearn.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/efficacy/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/efficacy/base.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/efficacy/binary.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/efficacy/mlefficacy.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/efficacy/multiclass.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/efficacy/regression.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/gaussian_mixture.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/multi_column_pairs.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/multi_single_column.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/new_row_synthesis.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/base.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/cap.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/categorical_sklearn.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/disclosure_protection.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/ensemble.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/loss.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/numerical_sklearn.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/radius_nearest_neighbor.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/privacy/util.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/single_table/table_structure.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/timeseries/README.md +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/timeseries/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/timeseries/efficacy/__init__.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/timeseries/efficacy/classification.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/timeseries/ml_scorers.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/visualization.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/warnings.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics.egg-info/dependency_links.txt +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics.egg-info/entry_points.txt +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics.egg-info/requires.txt +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics.egg-info/top_level.txt +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/setup.cfg +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/tests/test_scripts.py +0 -0
- {sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/tests/test_tasks.py +0 -0
|
@@ -148,7 +148,7 @@ convention = 'google'
|
|
|
148
148
|
add-ignore = ['D107', 'D407', 'D417']
|
|
149
149
|
|
|
150
150
|
[tool.bumpversion]
|
|
151
|
-
current_version = "0.
|
|
151
|
+
current_version = "0.28.1.dev0"
|
|
152
152
|
parse = '(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\.(?P<release>[a-z]+)(?P<candidate>\d+))?'
|
|
153
153
|
serialize = [
|
|
154
154
|
'{major}.{minor}.{patch}.{release}{candidate}',
|
|
@@ -2,7 +2,7 @@ import warnings
|
|
|
2
2
|
|
|
3
3
|
import pandas as pd
|
|
4
4
|
|
|
5
|
-
from sdmetrics.utils import is_datetime
|
|
5
|
+
from sdmetrics.utils import get_columns_from_metadata, is_datetime
|
|
6
6
|
|
|
7
7
|
MODELABLE_SDTYPES = ('numerical', 'datetime', 'categorical', 'boolean')
|
|
8
8
|
|
|
@@ -17,42 +17,40 @@ def _validate_metadata_dict(metadata):
|
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def
|
|
20
|
+
def _validate_columns_exist_in_single_table_metadata(metadata):
|
|
21
21
|
"""Validate the metadata for a single table."""
|
|
22
22
|
_validate_metadata_dict(metadata)
|
|
23
23
|
if 'columns' not in metadata:
|
|
24
24
|
raise ValueError(
|
|
25
|
-
"
|
|
25
|
+
"Each table in the metadata must include a 'columns' key that maps column names"
|
|
26
26
|
' to their corresponding information.'
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def
|
|
31
|
-
"""Validate the metadata
|
|
30
|
+
def _validate_metadata(metadata):
|
|
31
|
+
"""Validate the metadata."""
|
|
32
32
|
_validate_metadata_dict(metadata)
|
|
33
33
|
if 'tables' not in metadata:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
)
|
|
34
|
+
_validate_columns_exist_in_single_table_metadata(metadata)
|
|
35
|
+
return
|
|
36
|
+
|
|
38
37
|
for table_name, table_metadata in metadata['tables'].items():
|
|
39
38
|
try:
|
|
40
|
-
|
|
39
|
+
_validate_columns_exist_in_single_table_metadata(table_metadata)
|
|
41
40
|
except ValueError as e:
|
|
42
41
|
raise ValueError(f"Error in table '{table_name}': {str(e)}")
|
|
43
42
|
|
|
44
43
|
|
|
45
|
-
def
|
|
46
|
-
"""Validate the metadata."""
|
|
44
|
+
def _validate_unified_metadata(metadata):
|
|
45
|
+
"""Validate the unified metadata object."""
|
|
47
46
|
_validate_metadata_dict(metadata)
|
|
48
|
-
if
|
|
47
|
+
if 'tables' not in metadata:
|
|
49
48
|
raise ValueError(
|
|
50
|
-
"Metadata must include
|
|
51
|
-
|
|
49
|
+
"Metadata must include a 'tables' key that maps table names"
|
|
50
|
+
' to their respective metadata.'
|
|
52
51
|
)
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
_validate_multi_table_metadata(metadata)
|
|
53
|
+
_validate_metadata(metadata)
|
|
56
54
|
|
|
57
55
|
|
|
58
56
|
def handle_single_and_multi_table(single_table_func):
|
|
@@ -94,11 +92,9 @@ def _convert_datetime_column(column_name, column_data, column_metadata):
|
|
|
94
92
|
@handle_single_and_multi_table
|
|
95
93
|
def _convert_datetime_columns(data, metadata):
|
|
96
94
|
"""Convert datetime columns to datetime type."""
|
|
97
|
-
for column in metadata
|
|
98
|
-
if
|
|
99
|
-
data[column] = _convert_datetime_column(
|
|
100
|
-
column, data[column], metadata['columns'][column]
|
|
101
|
-
)
|
|
95
|
+
for column, column_metadata in get_columns_from_metadata(metadata).items():
|
|
96
|
+
if column_metadata['sdtype'] == 'datetime':
|
|
97
|
+
data[column] = _convert_datetime_column(column, data[column], column_metadata)
|
|
102
98
|
|
|
103
99
|
return data
|
|
104
100
|
|
|
@@ -106,7 +102,7 @@ def _convert_datetime_columns(data, metadata):
|
|
|
106
102
|
@handle_single_and_multi_table
|
|
107
103
|
def _remove_missing_columns_metadata(data, metadata):
|
|
108
104
|
"""Remove columns that are not present in the metadata."""
|
|
109
|
-
columns_in_metadata = set(metadata
|
|
105
|
+
columns_in_metadata = set(get_columns_from_metadata(metadata).keys())
|
|
110
106
|
columns_in_data = set(data.columns)
|
|
111
107
|
columns_to_remove = columns_in_data - columns_in_metadata
|
|
112
108
|
extra_metadata_columns = columns_in_metadata - columns_in_data
|
|
@@ -126,7 +122,9 @@ def _remove_missing_columns_metadata(data, metadata):
|
|
|
126
122
|
)
|
|
127
123
|
|
|
128
124
|
data = data.drop(columns=columns_to_remove)
|
|
129
|
-
column_intersection = [
|
|
125
|
+
column_intersection = [
|
|
126
|
+
column for column in data.columns if column in get_columns_from_metadata(metadata)
|
|
127
|
+
]
|
|
130
128
|
|
|
131
129
|
return data[column_intersection]
|
|
132
130
|
|
|
@@ -138,8 +136,8 @@ def _remove_non_modelable_columns(data, metadata):
|
|
|
138
136
|
All modelable columns are numerical, datetime, categorical, or boolean sdtypes.
|
|
139
137
|
"""
|
|
140
138
|
columns_modelable = []
|
|
141
|
-
for column in metadata
|
|
142
|
-
column_sdtype =
|
|
139
|
+
for column, column_metadata in get_columns_from_metadata(metadata).items():
|
|
140
|
+
column_sdtype = column_metadata['sdtype']
|
|
143
141
|
if column_sdtype in MODELABLE_SDTYPES and column in data.columns:
|
|
144
142
|
columns_modelable.append(column)
|
|
145
143
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tables": {
|
|
3
|
+
"student_placements": {
|
|
4
|
+
"primary_key": "student_id",
|
|
5
|
+
"columns": {
|
|
6
|
+
"start_date": {
|
|
7
|
+
"sdtype": "datetime",
|
|
8
|
+
"datetime_format": "%Y-%m-%d"
|
|
9
|
+
},
|
|
10
|
+
"end_date": {
|
|
11
|
+
"sdtype": "datetime",
|
|
12
|
+
"datetime_format": "%Y-%m-%d"
|
|
13
|
+
},
|
|
14
|
+
"salary": {
|
|
15
|
+
"sdtype": "numerical",
|
|
16
|
+
"computer_representation": "Int64"
|
|
17
|
+
},
|
|
18
|
+
"duration": {
|
|
19
|
+
"sdtype": "numerical",
|
|
20
|
+
"computer_representation": "Int64"
|
|
21
|
+
},
|
|
22
|
+
"student_id": {
|
|
23
|
+
"sdtype": "id",
|
|
24
|
+
"regex_format": "\\d{30}"
|
|
25
|
+
},
|
|
26
|
+
"high_perc": {
|
|
27
|
+
"sdtype": "numerical",
|
|
28
|
+
"computer_representation": "Float"
|
|
29
|
+
},
|
|
30
|
+
"high_spec": {
|
|
31
|
+
"sdtype": "categorical"
|
|
32
|
+
},
|
|
33
|
+
"mba_spec": {
|
|
34
|
+
"sdtype": "categorical"
|
|
35
|
+
},
|
|
36
|
+
"second_perc": {
|
|
37
|
+
"sdtype": "numerical",
|
|
38
|
+
"computer_representation": "Float"
|
|
39
|
+
},
|
|
40
|
+
"gender": {
|
|
41
|
+
"sdtype": "categorical"
|
|
42
|
+
},
|
|
43
|
+
"degree_perc": {
|
|
44
|
+
"sdtype": "numerical",
|
|
45
|
+
"computer_representation": "Float"
|
|
46
|
+
},
|
|
47
|
+
"placed": {
|
|
48
|
+
"sdtype": "boolean"
|
|
49
|
+
},
|
|
50
|
+
"experience_years": {
|
|
51
|
+
"sdtype": "numerical",
|
|
52
|
+
"computer_representation": "Float"
|
|
53
|
+
},
|
|
54
|
+
"employability_perc": {
|
|
55
|
+
"sdtype": "numerical",
|
|
56
|
+
"computer_representation": "Float"
|
|
57
|
+
},
|
|
58
|
+
"mba_perc": {
|
|
59
|
+
"sdtype": "numerical",
|
|
60
|
+
"computer_representation": "Float"
|
|
61
|
+
},
|
|
62
|
+
"work_experience": {
|
|
63
|
+
"sdtype": "boolean"
|
|
64
|
+
},
|
|
65
|
+
"degree_type": {
|
|
66
|
+
"sdtype": "categorical"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"METADATA_SPEC_VERSION": "SINGLE_TABLE_V1"
|
|
72
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tables": {
|
|
3
|
+
"timeseries": {
|
|
4
|
+
"columns": {
|
|
5
|
+
"region": {
|
|
6
|
+
"sdtype": "categorical"
|
|
7
|
+
},
|
|
8
|
+
"store_id": {
|
|
9
|
+
"sdtype": "numerical",
|
|
10
|
+
"computer_representation": "Int64"
|
|
11
|
+
},
|
|
12
|
+
"nb_customers": {
|
|
13
|
+
"sdtype": "numerical",
|
|
14
|
+
"computer_representation": "Int64"
|
|
15
|
+
},
|
|
16
|
+
"total_sales": {
|
|
17
|
+
"sdtype": "numerical",
|
|
18
|
+
"computer_representation": "Float"
|
|
19
|
+
},
|
|
20
|
+
"date": {
|
|
21
|
+
"sdtype": "datetime"
|
|
22
|
+
},
|
|
23
|
+
"day_of_week": {
|
|
24
|
+
"sdtype": "numerical",
|
|
25
|
+
"computer_representation": "Int64"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"sequence_key": "store_id",
|
|
29
|
+
"sequence_index": "date"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"METADATA_SPEC_VERSION": "SINGLE_TABLE_V1"
|
|
33
|
+
}
|
|
@@ -35,16 +35,11 @@ def load_demo(modality='multi_table'):
|
|
|
35
35
|
with open(demo_path / 'metadata.json', 'r') as metadata_file:
|
|
36
36
|
metadata = json.loads(metadata_file.read())
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
synthetic_data[table] = _load_table(table_meta, demo_path / f'{table}_synthetic.csv')
|
|
44
|
-
|
|
45
|
-
else:
|
|
46
|
-
real_data = _load_table(metadata, demo_path / 'real.csv')
|
|
47
|
-
synthetic_data = _load_table(metadata, demo_path / 'synthetic.csv')
|
|
38
|
+
real_data = {}
|
|
39
|
+
synthetic_data = {}
|
|
40
|
+
for table, table_meta in metadata['tables'].items():
|
|
41
|
+
real_data[table] = _load_table(table_meta, demo_path / f'{table}_real.csv')
|
|
42
|
+
synthetic_data[table] = _load_table(table_meta, demo_path / f'{table}_synthetic.csv')
|
|
48
43
|
|
|
49
44
|
return real_data, synthetic_data, metadata
|
|
50
45
|
|
{sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/multi_table/detection/parent_child.py
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
|
|
5
|
-
from sdmetrics._utils_metadata import
|
|
5
|
+
from sdmetrics._utils_metadata import _validate_metadata
|
|
6
6
|
from sdmetrics.multi_table.detection.base import DetectionMetric
|
|
7
7
|
from sdmetrics.single_table.detection import LogisticDetection, SVCDetection
|
|
8
8
|
from sdmetrics.utils import get_columns_from_metadata, nested_attrs_meta
|
|
@@ -38,7 +38,7 @@ class ParentChildDetectionMetric(
|
|
|
38
38
|
|
|
39
39
|
@staticmethod
|
|
40
40
|
def _extract_foreign_keys(metadata):
|
|
41
|
-
|
|
41
|
+
_validate_metadata(metadata)
|
|
42
42
|
foreign_keys = []
|
|
43
43
|
for child_table, child_meta in metadata['tables'].items():
|
|
44
44
|
for child_key, field_meta in get_columns_from_metadata(child_meta).items():
|
|
@@ -6,7 +6,7 @@ from collections import defaultdict
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
|
|
8
8
|
from sdmetrics import single_table
|
|
9
|
-
from sdmetrics._utils_metadata import
|
|
9
|
+
from sdmetrics._utils_metadata import _validate_metadata
|
|
10
10
|
from sdmetrics.errors import IncomputableMetricError
|
|
11
11
|
from sdmetrics.multi_table.base import MultiTableMetric
|
|
12
12
|
from sdmetrics.utils import nested_attrs_meta
|
|
@@ -79,7 +79,7 @@ class MultiSingleTableMetric(MultiTableMetric, metaclass=nested_attrs_meta('sing
|
|
|
79
79
|
if metadata is None:
|
|
80
80
|
metadata = {'tables': defaultdict(type(None))}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
_validate_metadata(metadata)
|
|
83
83
|
scores = {}
|
|
84
84
|
errors = {}
|
|
85
85
|
for table_name, real_table in real_data.items():
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Reports for sdmetrics."""
|
|
2
|
+
|
|
3
|
+
from sdmetrics.reports.diagnostic_report import DiagnosticReport
|
|
4
|
+
from sdmetrics.reports.quality_report import QualityReport
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
'DiagnosticReport',
|
|
8
|
+
'QualityReport',
|
|
9
|
+
'SingleTableQualityReport', # noqa: F822
|
|
10
|
+
'SingleTableDiagnosticReport', # noqa: F822
|
|
11
|
+
'MultiTableQualityReport', # noqa: F822
|
|
12
|
+
'MultiTableDiagnosticReport', # noqa: F822
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def __getattr__(name):
|
|
17
|
+
"""Lazy load deprecated report class aliases."""
|
|
18
|
+
if name == 'SingleTableQualityReport':
|
|
19
|
+
from sdmetrics.reports.single_table.quality_report import QualityReport
|
|
20
|
+
|
|
21
|
+
return QualityReport
|
|
22
|
+
|
|
23
|
+
if name == 'SingleTableDiagnosticReport':
|
|
24
|
+
from sdmetrics.reports.single_table.diagnostic_report import DiagnosticReport
|
|
25
|
+
|
|
26
|
+
return DiagnosticReport
|
|
27
|
+
|
|
28
|
+
if name == 'MultiTableQualityReport':
|
|
29
|
+
from sdmetrics.reports.multi_table.quality_report import QualityReport
|
|
30
|
+
|
|
31
|
+
return QualityReport
|
|
32
|
+
|
|
33
|
+
if name == 'MultiTableDiagnosticReport':
|
|
34
|
+
from sdmetrics.reports.multi_table.diagnostic_report import DiagnosticReport
|
|
35
|
+
|
|
36
|
+
return DiagnosticReport
|
|
37
|
+
|
|
38
|
+
raise AttributeError(f"module 'sdmetrics.reports' has no attribute '{name}'")
|
|
@@ -15,6 +15,7 @@ import tqdm
|
|
|
15
15
|
|
|
16
16
|
from sdmetrics._utils_metadata import _convert_datetime_column, _validate_metadata
|
|
17
17
|
from sdmetrics.reports.utils import DEFAULT_NUM_ROWS_SUBSAMPLE
|
|
18
|
+
from sdmetrics.utils import get_columns_from_metadata
|
|
18
19
|
from sdmetrics.visualization import set_plotly_config
|
|
19
20
|
|
|
20
21
|
|
|
@@ -24,10 +25,13 @@ class BaseReport:
|
|
|
24
25
|
This class creates a base report for single-table data.
|
|
25
26
|
"""
|
|
26
27
|
|
|
28
|
+
_skipped_property_message = 'This property was skipped.'
|
|
29
|
+
|
|
27
30
|
def __init__(self):
|
|
28
31
|
self._overall_score = None
|
|
29
32
|
self.is_generated = False
|
|
30
33
|
self._properties = {}
|
|
34
|
+
self._skipped_properties = set()
|
|
31
35
|
self.num_rows_subsample = DEFAULT_NUM_ROWS_SUBSAMPLE
|
|
32
36
|
self.report_info = {
|
|
33
37
|
'report_type': self.__class__.__name__,
|
|
@@ -42,7 +46,7 @@ class BaseReport:
|
|
|
42
46
|
"""
|
|
43
47
|
real_columns = set(real_data.columns)
|
|
44
48
|
synthetic_columns = set(synthetic_data.columns)
|
|
45
|
-
metadata_columns = set(metadata
|
|
49
|
+
metadata_columns = set(get_columns_from_metadata(metadata).keys())
|
|
46
50
|
|
|
47
51
|
missing_data = metadata_columns.difference(real_columns.union(synthetic_columns))
|
|
48
52
|
missing_metadata = real_columns.union(synthetic_columns).difference(metadata_columns)
|
|
@@ -97,7 +101,7 @@ class BaseReport:
|
|
|
97
101
|
metadata (dict):
|
|
98
102
|
The metadata, which contains each column's data type as well as relationships.
|
|
99
103
|
"""
|
|
100
|
-
for column, col_meta in metadata
|
|
104
|
+
for column, col_meta in get_columns_from_metadata(metadata).items():
|
|
101
105
|
if col_meta['sdtype'] == 'datetime':
|
|
102
106
|
real_col = real_data[column]
|
|
103
107
|
synth_col = synthetic_data[column]
|
|
@@ -117,6 +121,19 @@ class BaseReport:
|
|
|
117
121
|
if verbose:
|
|
118
122
|
sys.stdout.write(f'Overall Score (Average): {round(self._overall_score * 100, 2)}%\n\n')
|
|
119
123
|
|
|
124
|
+
def _get_skipped_properties(self, metadata):
|
|
125
|
+
"""Return properties that should not be computed for the metadata.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
metadata (dict):
|
|
129
|
+
The metadata dict.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
set[str]:
|
|
133
|
+
Names of properties to skip.
|
|
134
|
+
"""
|
|
135
|
+
return set()
|
|
136
|
+
|
|
120
137
|
def generate(self, real_data, synthetic_data, metadata, verbose=True):
|
|
121
138
|
"""Generate report.
|
|
122
139
|
|
|
@@ -134,6 +151,7 @@ class BaseReport:
|
|
|
134
151
|
Whether or not to print report summary and progress.
|
|
135
152
|
"""
|
|
136
153
|
self._validate(real_data, synthetic_data, metadata)
|
|
154
|
+
self._skipped_properties = self._get_skipped_properties(metadata)
|
|
137
155
|
self.convert_datetimes(real_data, synthetic_data, metadata)
|
|
138
156
|
|
|
139
157
|
self.report_info['generated_date'] = datetime.today().strftime('%Y-%m-%d')
|
|
@@ -156,14 +174,24 @@ class BaseReport:
|
|
|
156
174
|
|
|
157
175
|
start_time = time.time()
|
|
158
176
|
for ind, (property_name, property_instance) in enumerate(self._properties.items()):
|
|
177
|
+
property_description = f'({ind + 1}/{len(self._properties)}) Evaluating {property_name}'
|
|
178
|
+
if property_name in self._skipped_properties:
|
|
179
|
+
property_instance.is_computed = False
|
|
180
|
+
property_instance.details = pd.DataFrame()
|
|
181
|
+
if verbose:
|
|
182
|
+
sys.stdout.write(
|
|
183
|
+
f'{property_description}: N/A\n{self._skipped_property_message}\n\n'
|
|
184
|
+
)
|
|
185
|
+
sys.stdout.flush()
|
|
186
|
+
|
|
187
|
+
continue
|
|
188
|
+
|
|
159
189
|
if verbose:
|
|
160
190
|
num_iterations = int(property_instance._get_num_iterations(metadata))
|
|
161
191
|
progress_bar = tqdm.tqdm(
|
|
162
192
|
total=num_iterations, file=sys.stdout, bar_format='{desc}|{bar}{r_bar}|'
|
|
163
193
|
)
|
|
164
|
-
progress_bar.set_description(
|
|
165
|
-
f'({ind + 1}/{len(self._properties)}) Evaluating {property_name}'
|
|
166
|
-
)
|
|
194
|
+
progress_bar.set_description(property_description)
|
|
167
195
|
|
|
168
196
|
if hasattr(self, 'real_correlation_threshold') and hasattr(
|
|
169
197
|
property_instance, 'real_correlation_threshold'
|
|
@@ -180,7 +208,9 @@ class BaseReport:
|
|
|
180
208
|
)
|
|
181
209
|
scores.append(score)
|
|
182
210
|
if verbose:
|
|
183
|
-
progress_bar
|
|
211
|
+
if progress_bar is not None:
|
|
212
|
+
progress_bar.close()
|
|
213
|
+
progress_bar = None
|
|
184
214
|
sys.stdout.write(f'{property_name} Score: {round(score * 100, 2)}%\n\n')
|
|
185
215
|
sys.stdout.flush()
|
|
186
216
|
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Unified table base report."""
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
from sdmetrics._utils_metadata import _validate_unified_metadata
|
|
6
|
+
from sdmetrics.reports.multi_table.base_multi_table_report import BaseMultiTableReport
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BaseUnifiedReport(BaseMultiTableReport):
|
|
10
|
+
"""Base Unified Report for single-table and multi-table data."""
|
|
11
|
+
|
|
12
|
+
_SINGLE_TABLE_SKIPPED_PROPERTIES = frozenset({
|
|
13
|
+
'Relationship Validity',
|
|
14
|
+
'Cardinality',
|
|
15
|
+
'Intertable Trends',
|
|
16
|
+
})
|
|
17
|
+
_skipped_property_message = 'This property does not apply to single-table data.'
|
|
18
|
+
|
|
19
|
+
def _get_skipped_properties(self, metadata):
|
|
20
|
+
"""Return properties unavailable to single-table data.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
metadata (dict):
|
|
24
|
+
The metadata dict.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
set[str]:
|
|
28
|
+
Names of properties to skip.
|
|
29
|
+
"""
|
|
30
|
+
if len(metadata.get('tables', {})) == 1:
|
|
31
|
+
return self._SINGLE_TABLE_SKIPPED_PROPERTIES
|
|
32
|
+
|
|
33
|
+
return super()._get_skipped_properties(metadata)
|
|
34
|
+
|
|
35
|
+
def _validate_data_format(self, real_data, synthetic_data):
|
|
36
|
+
"""Validate that the real and synthetic data have compatible formats.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
real_data (dict[str, pd.DataFrame]):
|
|
40
|
+
The real data.
|
|
41
|
+
synthetic_data (dict[str, pd.DataFrame]):
|
|
42
|
+
The synthetic data.
|
|
43
|
+
"""
|
|
44
|
+
if not isinstance(real_data, dict):
|
|
45
|
+
raise ValueError(
|
|
46
|
+
'Please pass in a dictionary mapping tables to dataframes for real_data.'
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if not isinstance(synthetic_data, dict):
|
|
50
|
+
raise ValueError(
|
|
51
|
+
'Please pass in a dictionary mapping tables to dataframes for synthetic_data.'
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
all_real_dataframes = all(isinstance(table, pd.DataFrame) for table in real_data.values())
|
|
55
|
+
all_synthetic_dataframes = all(
|
|
56
|
+
isinstance(table, pd.DataFrame) for table in synthetic_data.values()
|
|
57
|
+
)
|
|
58
|
+
if all_real_dataframes and all_synthetic_dataframes:
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
raise ValueError(
|
|
62
|
+
f'{self.__class__.__name__} expects real_data and synthetic_data to both be '
|
|
63
|
+
'pandas.DataFrame, or both be dictionaries mapping table names to '
|
|
64
|
+
f'pandas.DataFrame. Received real_data={type(real_data).__name__} and '
|
|
65
|
+
f'synthetic_data={type(synthetic_data).__name__}.'
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def _check_property_single_table(self, property_name):
|
|
69
|
+
is_single_table = self.report_info.get('num_tables', 0) == 1
|
|
70
|
+
skipped_properties = getattr(self, '_SINGLE_TABLE_SKIPPED_PROPERTIES', [])
|
|
71
|
+
if is_single_table and property_name in skipped_properties:
|
|
72
|
+
raise ValueError('This property is not available for single-table datasets.')
|
|
73
|
+
|
|
74
|
+
def _validate_property_generated(self, property_name):
|
|
75
|
+
super()._validate_property_generated(property_name)
|
|
76
|
+
self._check_property_single_table(property_name)
|
|
77
|
+
|
|
78
|
+
def _validate(self, real_data, synthetic_data, metadata):
|
|
79
|
+
"""Validate the inputs.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
real_data (dict[str, pd.DataFrame]):
|
|
83
|
+
The real data.
|
|
84
|
+
synthetic_data (dict[str, pd.DataFrame]):
|
|
85
|
+
The synthetic data.
|
|
86
|
+
metadata (dict):
|
|
87
|
+
The metadata.
|
|
88
|
+
"""
|
|
89
|
+
_validate_unified_metadata(metadata)
|
|
90
|
+
self.table_names = list(metadata.get('tables', []))
|
|
91
|
+
self._validate_data_format(real_data, synthetic_data)
|
|
92
|
+
self._validate_metadata_matches_data(
|
|
93
|
+
real_data,
|
|
94
|
+
synthetic_data,
|
|
95
|
+
metadata,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def get_properties(self):
|
|
99
|
+
"""Return the property score.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
pandas.DataFrame
|
|
103
|
+
The property score.
|
|
104
|
+
"""
|
|
105
|
+
self._check_report_generated()
|
|
106
|
+
name, score = [], []
|
|
107
|
+
is_single_table = self.report_info.get('num_tables', 0) == 1
|
|
108
|
+
|
|
109
|
+
for property_name, property_instance in self._properties.items():
|
|
110
|
+
if not (is_single_table and property_name in self._SINGLE_TABLE_SKIPPED_PROPERTIES):
|
|
111
|
+
property_score = property_instance._compute_average()
|
|
112
|
+
name.append(property_name)
|
|
113
|
+
score.append(property_score)
|
|
114
|
+
|
|
115
|
+
return pd.DataFrame({
|
|
116
|
+
'Property': name,
|
|
117
|
+
'Score': score,
|
|
118
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Unified diagnostic report."""
|
|
2
|
+
|
|
3
|
+
from sdmetrics.reports.base_unified_report import BaseUnifiedReport
|
|
4
|
+
from sdmetrics.reports.multi_table._properties import DataValidity, RelationshipValidity, Structure
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DiagnosticReport(BaseUnifiedReport):
|
|
8
|
+
"""Diagnostic report for single-table and multi-table data.
|
|
9
|
+
|
|
10
|
+
This class creates a diagnostic report for single-table data.
|
|
11
|
+
It calculates the quality score using the multi-table report properties.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self):
|
|
15
|
+
super().__init__()
|
|
16
|
+
self._properties = {
|
|
17
|
+
'Data Validity': DataValidity(),
|
|
18
|
+
'Data Structure': Structure(),
|
|
19
|
+
'Relationship Validity': RelationshipValidity(),
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
def _validate_metadata_matches_data(self, real_data, synthetic_data, metadata):
|
|
23
|
+
self._validate_relationships(real_data, synthetic_data, metadata)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Multi table reports for sdmetrics."""
|
|
2
|
+
|
|
3
|
+
__all__ = [
|
|
4
|
+
'QualityReport', # noqa: F822
|
|
5
|
+
'DiagnosticReport', # noqa: F822
|
|
6
|
+
]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def __getattr__(name):
|
|
10
|
+
"""Lazy load deprecated report classes."""
|
|
11
|
+
if name == 'QualityReport':
|
|
12
|
+
from sdmetrics.reports.multi_table.quality_report import QualityReport
|
|
13
|
+
|
|
14
|
+
return QualityReport
|
|
15
|
+
|
|
16
|
+
if name == 'DiagnosticReport':
|
|
17
|
+
from sdmetrics.reports.multi_table.diagnostic_report import DiagnosticReport
|
|
18
|
+
|
|
19
|
+
return DiagnosticReport
|
|
20
|
+
|
|
21
|
+
raise AttributeError(f"module 'sdmetrics.reports.multi_table' has no attribute '{name}'")
|
|
@@ -20,7 +20,7 @@ class BaseMultiTableReport(BaseReport):
|
|
|
20
20
|
self.table_names = []
|
|
21
21
|
|
|
22
22
|
def _validate_data_format(self, real_data, synthetic_data):
|
|
23
|
-
"""Validate that the real and synthetic are
|
|
23
|
+
"""Validate that the real and synthetic are dictionaries of tables."""
|
|
24
24
|
is_real_dict = isinstance(real_data, dict)
|
|
25
25
|
is_synthetic_dict = isinstance(synthetic_data, dict)
|
|
26
26
|
if is_real_dict and is_synthetic_dict:
|
{sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/diagnostic_report.py
RENAMED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from sdmetrics.reports.multi_table._properties import DataValidity, RelationshipValidity, Structure
|
|
4
4
|
from sdmetrics.reports.multi_table.base_multi_table_report import BaseMultiTableReport
|
|
5
|
+
from sdmetrics.reports.utils import _warn_deprecated_report
|
|
6
|
+
|
|
7
|
+
_warn_deprecated_report('multi table diagnostic', 'DiagnosticReport')
|
|
5
8
|
|
|
6
9
|
|
|
7
10
|
class DiagnosticReport(BaseMultiTableReport):
|
{sdmetrics-0.27.3.dev0 → sdmetrics-0.28.1.dev0}/sdmetrics/reports/multi_table/quality_report.py
RENAMED
|
@@ -7,6 +7,13 @@ from sdmetrics.reports.multi_table._properties import (
|
|
|
7
7
|
InterTableTrends,
|
|
8
8
|
)
|
|
9
9
|
from sdmetrics.reports.multi_table.base_multi_table_report import BaseMultiTableReport
|
|
10
|
+
from sdmetrics.reports.utils import (
|
|
11
|
+
DEFAULT_REAL_ASSOCIATION_THRESHOLD,
|
|
12
|
+
DEFAULT_REAL_CORRELATION_THRESHOLD,
|
|
13
|
+
_warn_deprecated_report,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
_warn_deprecated_report('multi table quality', 'QualityReport')
|
|
10
17
|
|
|
11
18
|
|
|
12
19
|
class QualityReport(BaseMultiTableReport):
|
|
@@ -18,8 +25,8 @@ class QualityReport(BaseMultiTableReport):
|
|
|
18
25
|
|
|
19
26
|
def __init__(self):
|
|
20
27
|
super().__init__()
|
|
21
|
-
self.real_correlation_threshold =
|
|
22
|
-
self.real_association_threshold =
|
|
28
|
+
self.real_correlation_threshold = DEFAULT_REAL_CORRELATION_THRESHOLD
|
|
29
|
+
self.real_association_threshold = DEFAULT_REAL_ASSOCIATION_THRESHOLD
|
|
23
30
|
self._properties = {
|
|
24
31
|
'Column Shapes': ColumnShapes(),
|
|
25
32
|
'Column Pair Trends': ColumnPairTrends(),
|