Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions sdmetrics/reports/base_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,20 +130,22 @@ def _print_results(self, verbose):
if verbose:
sys.stdout.write(f'Overall Score (Average): {round(self._overall_score * 100, 2)}%\n\n')

def _get_skipped_properties(self, metadata):
def _get_skipped_properties(self, metadata, constraints=None):
"""Return properties that should not be computed for the metadata.

Args:
metadata (dict):
The metadata dict.
constraints (list[dict] or None):
The constraints given to the report. Defaults to None.

Returns:
set[str]:
Names of properties to skip.
"""
return set()

def generate(self, real_data, synthetic_data, metadata, verbose=True):
def generate(self, real_data, synthetic_data, metadata, constraints=None, verbose=True):
"""Generate report.

This method generates the report by iterating through each property and calculating
Expand All @@ -156,13 +158,16 @@ def generate(self, real_data, synthetic_data, metadata, verbose=True):
The synthetic data.
metadata (dict):
The metadata, which contains each column's data type as well as relationships.
constraints (list[dict] or None):
A list of constraints to evaluate their adherence, each represented as a
dictionary with a ``class_name`` and a ``parameters`` key. Defaults to None.
verbose (bool):
Whether or not to print report summary and progress.
"""
real_data = deepcopy(real_data)
synthetic_data = deepcopy(synthetic_data)
self._validate(real_data, synthetic_data, metadata)
self._skipped_properties = self._get_skipped_properties(metadata)
self._skipped_properties = self._get_skipped_properties(metadata, constraints)
self._original_datetime_columns = self.convert_datetimes(
real_data, synthetic_data, metadata
)
Expand Down Expand Up @@ -192,15 +197,22 @@ def generate(self, real_data, synthetic_data, metadata, verbose=True):
property_instance.is_computed = False
property_instance.details = pd.DataFrame()
if verbose:
sys.stdout.write(
f'{property_description}: N/A\n{self._skipped_property_message}\n\n'
skipped_message = getattr(
property_instance, '_skipped_message', self._skipped_property_message
)
sys.stdout.write(f'{property_description}: N/A\n{skipped_message}\n\n')
sys.stdout.flush()

continue

property_arguments = {}
if property_name == 'Constraint Validity':
property_arguments['constraints'] = constraints

if verbose:
num_iterations = int(property_instance._get_num_iterations(metadata))
num_iterations = int(
property_instance._get_num_iterations(metadata, **property_arguments)
)
progress_bar = tqdm.tqdm(
total=num_iterations, file=sys.stdout, bar_format='{desc}|{bar}{r_bar}|'
)
Expand All @@ -220,7 +232,7 @@ def generate(self, real_data, synthetic_data, metadata, verbose=True):

self._properties[property_name].num_rows_subsample = self.num_rows_subsample
score = self._properties[property_name].get_score(
real_data, synthetic_data, metadata, progress_bar=progress_bar
real_data, synthetic_data, metadata, progress_bar=progress_bar, **property_arguments
)
scores.append(score)
if verbose:
Expand Down
11 changes: 8 additions & 3 deletions sdmetrics/reports/base_unified_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,26 @@ class BaseUnifiedReport(BaseMultiTableReport):
})
_skipped_property_message = 'This property does not apply to single-table data.'

def _get_skipped_properties(self, metadata):
def _get_skipped_properties(self, metadata, constraints=None):
"""Return properties unavailable to single-table data.

Args:
metadata (dict):
The metadata dict.
constraints (list[dict] or None):
The constraints given to the report. Defaults to None.

Returns:
set[str]:
Names of properties to skip.
"""
skipped_properties = super()._get_skipped_properties(metadata, constraints)
if len(metadata.get('tables', {})) == 1:
return self._SINGLE_TABLE_SKIPPED_PROPERTIES
skipped_properties.update(self._SINGLE_TABLE_SKIPPED_PROPERTIES)
if not constraints:
skipped_properties.add('Constraint Validity')

return super()._get_skipped_properties(metadata)
return skipped_properties

def _validate_data_format(self, real_data, synthetic_data):
"""Validate that the real and synthetic data have compatible formats.
Expand Down
8 changes: 7 additions & 1 deletion sdmetrics/reports/diagnostic_report.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
"""Unified diagnostic report."""

from sdmetrics.reports.base_unified_report import BaseUnifiedReport
from sdmetrics.reports.multi_table._properties import DataValidity, RelationshipValidity, Structure
from sdmetrics.reports.multi_table._properties import (
ConstraintValidity,
DataValidity,
RelationshipValidity,
Structure,
)


class DiagnosticReport(BaseUnifiedReport):
Expand All @@ -17,6 +22,7 @@ def __init__(self):
'Data Validity': DataValidity(),
'Data Structure': Structure(),
'Relationship Validity': RelationshipValidity(),
'Constraint Validity': ConstraintValidity(),
}

def _validate_metadata_matches_data(self, real_data, synthetic_data, metadata):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class ConstraintValidity(BaseMultiTableProperty):
"""

_num_iteration_case = 'constraint'
_skipped_message = 'No constraints were provided.'

def _get_num_iterations(self, metadata, constraints=None):
"""Get the number of iterations for the property, which is one per constraint."""
Expand Down
9 changes: 7 additions & 2 deletions sdmetrics/reports/multi_table/base_multi_table_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def _validate_metadata_matches_data(self, real_data, synthetic_data, metadata):

self._validate_relationships(real_data, synthetic_data, metadata)

def generate(self, real_data, synthetic_data, metadata, verbose=True):
def generate(self, real_data, synthetic_data, metadata, constraints=None, verbose=True):
"""Generate report.

This method generates the report by iterating through each property and calculating
Expand All @@ -97,10 +97,12 @@ def generate(self, real_data, synthetic_data, metadata, verbose=True):
The synthetic data.
metadata (dict):
The metadata, which contains each column's data type as well as relationships.
constraints (list[dict] or None):
A list of constraints to evaluate their adherence. Defaults to None.
verbose (bool):
Whether or not to print report summary and progress.
"""
results = super().generate(real_data, synthetic_data, metadata, verbose)
results = super().generate(real_data, synthetic_data, metadata, constraints, verbose)
self.table_names = list(metadata.get('tables', {}).keys())

return results
Expand Down Expand Up @@ -173,6 +175,9 @@ def get_visualization(self, property_name, table_name=None):
if property_name == 'Data Structure':
return self._properties[property_name].get_visualization(table_name)

if property_name == 'Constraint Validity':
return self._properties[property_name].get_visualization()

if table_name is None:
raise ValueError('Please provide a table name to get a visualization for the property.')

Expand Down
Loading
Loading