diff --git a/diffly/cli.py b/diffly/cli.py index 7177e58..9eb736a 100644 --- a/diffly/cli.py +++ b/diffly/cli.py @@ -12,14 +12,14 @@ from ._compat import typer from ._utils import ABS_TOL_DEFAULT, ABS_TOL_TEMPORAL_DEFAULT, REL_TOL_DEFAULT -from .metrics import Metric, MetricFn +from .metrics import ChangeMetricFn, Metric from .metrics.change import DEFAULT_CHANGE_METRICS from .metrics.data import DEFAULT_DATA_METRICS app = typer.Typer() #: All metric presets selectable via ``--metric``, combining the change and data sets. -AVAILABLE_METRICS: dict[str, MetricFn | Metric] = { +AVAILABLE_METRICS: dict[str, ChangeMetricFn | Metric] = { **DEFAULT_CHANGE_METRICS, **DEFAULT_DATA_METRICS, } diff --git a/diffly/comparison.py b/diffly/comparison.py index 6976b9c..622d8ee 100644 --- a/diffly/comparison.py +++ b/diffly/comparison.py @@ -4,10 +4,11 @@ from __future__ import annotations import datetime as dt +import inspect import warnings from collections.abc import Iterable, Mapping, Sequence from functools import cached_property -from typing import TYPE_CHECKING, Literal, Self, overload +from typing import TYPE_CHECKING, Literal, Self, cast, overload import polars as pl from polars.schema import Schema as PolarsSchema @@ -25,7 +26,13 @@ lazy_len, make_and_validate_mapping, ) -from .metrics import Metric, MetricFn, _make_numeric_metric +from .metrics import ( + ChangeMetric, + ChangeMetricFn, + DataMetric, + DataMetricFn, + Metric, +) if TYPE_CHECKING: # pragma: no cover # NOTE: We cannot import at runtime as we're otherwise running into circular @@ -920,7 +927,7 @@ def summary( right_name: str = Side.RIGHT, slim: bool = False, hidden_columns: list[str] | None = None, - metrics: Mapping[str, MetricFn | Metric] | None = None, + metrics: Mapping[str, ChangeMetricFn | DataMetricFn | Metric] | None = None, ) -> Summary: """Generate a summary of all aspects of the comparison. @@ -951,16 +958,16 @@ def summary( hidden_columns: Columns for which no values are printed, e.g. because they contain sensitive information. metrics: Optional mapping from display label to a metric. A value may be a - callable ``(left_expr, right_expr) -> pl.Expr`` or a - :class:`~diffly.metrics.Metric`. Each callable receives two - :class:`polars.Expr` referring to the left and right values of a single - column across all joined rows, and must return a scalar aggregation - expression. Bare callables are only computed for numerical columns; wrap - one in a :class:`~diffly.metrics.Metric` with a column selector to target - other column types (e.g. ``Metric(fn, selector=cs.all())``). - See :doc:`/api/metrics` for the full list of presets and the - :data:`~diffly.metrics.MetricFn` type. When ``None`` (default), no metrics - are computed; presets are not applied automatically. Prefer short labels — + :class:`~diffly.metrics.ChangeMetric` (callable + ``(left_expr, right_expr) -> pl.Expr`` aggregating over the change), a + :class:`~diffly.metrics.DataMetric` (callable ``(col_expr) -> pl.Expr`` + evaluated on each side to describe the data), or a bare callable resolved + by its arity (two arguments → change metric on numerical columns, one + argument → data metric on all columns). To target other column types, + construct the metric explicitly with a column selector + (e.g. ``ChangeMetric(fn, selector=cs.all())``). See :doc:`/api/metrics` + for the full list of presets. When ``None`` (default), no metrics are + computed; presets are not applied automatically. Prefer short labels — the summary has a fixed width and many or long labels degrade rendering. Returns: @@ -977,11 +984,17 @@ def summary( # NOTE: We're importing here to prevent circular imports from .summary import Summary + def _resolve(v: ChangeMetricFn | DataMetricFn | Metric) -> Metric: + if isinstance(v, (ChangeMetric, DataMetric)): + return v + # Infer the metric family from the callable's arity: a single-argument + # callable describes one side (data), two arguments describe a change. + if len(inspect.signature(v).parameters) >= 2: + return ChangeMetric(fn=cast(ChangeMetricFn, v)) + return DataMetric(fn=cast(DataMetricFn, v)) + resolved_metrics = ( - { - label: v if isinstance(v, Metric) else _make_numeric_metric(v) - for label, v in metrics.items() - } + {label: _resolve(v) for label, v in metrics.items()} if metrics is not None else None ) diff --git a/diffly/metrics/__init__.py b/diffly/metrics/__init__.py index a3a165b..d338253 100644 --- a/diffly/metrics/__init__.py +++ b/diffly/metrics/__init__.py @@ -14,7 +14,14 @@ from __future__ import annotations from . import change, data -from ._common import Metric, MetricFn +from ._common import ( + ChangeMetric, + ChangeMetricFn, + DataMetric, + DataMetricFn, + Metric, + MetricFn, +) from .change import ( _make_numeric_metric, max, @@ -34,6 +41,10 @@ __all__ = [ "DEFAULT_METRICS", + "ChangeMetric", + "ChangeMetricFn", + "DataMetric", + "DataMetricFn", "Metric", "MetricFn", "change", diff --git a/diffly/metrics/_common.py b/diffly/metrics/_common.py index 5ba7c38..b7e9038 100644 --- a/diffly/metrics/_common.py +++ b/diffly/metrics/_common.py @@ -4,24 +4,64 @@ from __future__ import annotations from collections.abc import Callable -from dataclasses import dataclass +from dataclasses import dataclass, field +from typing import Any import polars as pl import polars.selectors as cs +ChangeMetricFn = Callable[[pl.Expr, pl.Expr], pl.Expr] +"""A change metric maps ``(left_expr, right_expr)`` to a scalar aggregation expression. + +The expressions refer to the left-side and right-side values of a single column across +all joined rows. +""" + +DataMetricFn = Callable[[pl.Expr], pl.Expr] +"""A data metric maps a single column expression to a scalar aggregation expression. + +It is evaluated on the left and right side separately to describe each dataset on its +own, rather than the change between them. +""" + +# Retained for backwards compatibility; a plain metric callable is a change metric. +MetricFn = ChangeMetricFn + @dataclass(frozen=True) -class Metric: - """A metric function paired with a column-applicability selector.""" +class ChangeMetric: + """A metric quantifying the *change* between the two sides of a comparison. - fn: MetricFn - selector: cs.Selector + ``fn`` aggregates over ``right - left`` (e.g. the mean delta) to describe the change + itself. Change metrics are rendered as extra columns in the "Columns" table, + alongside the match rate. + """ + fn: ChangeMetricFn + selector: cs.Selector = field(default_factory=cs.numeric) -MetricFn = Callable[[pl.Expr, pl.Expr], pl.Expr] -"""A metric function maps ``(left_expr, right_expr)`` to a scalar aggregation -expression. -The expressions refer to the left-side and right-side values of a single column across -all joined rows. -""" +@dataclass(frozen=True) +class DataMetric: + """A metric describing each dataset *individually*. + + ``fn`` is applied to the left and right side separately (e.g. the fraction of null + entries on each side), characterizing the data rather than the change between the + sides. Data metrics are rendered in a dedicated "Data Inspection" section, showing + the left and right value side by side, followed by their signed delta for numeric + values. + + ``formatter`` formats a single left/right value for display. ``delta_formatter`` + formats the (always non-negative) magnitude of the delta, which is rendered with an + explicit sign; when ``None``, it falls back to ``formatter``. Both fall back to the + default numeric precision when unset. + """ + + fn: DataMetricFn + selector: cs.Selector = field(default_factory=cs.all) + formatter: Callable[[Any], str] | None = None + delta_formatter: Callable[[Any], str] | None = None + + +Metric = ChangeMetric | DataMetric +"""A change or data metric paired with a column-applicability selector.""" diff --git a/diffly/metrics/change.py b/diffly/metrics/change.py index f4965f1..cadf17a 100644 --- a/diffly/metrics/change.py +++ b/diffly/metrics/change.py @@ -11,11 +11,11 @@ import polars as pl import polars.selectors as cs -from ._common import Metric, MetricFn +from ._common import ChangeMetric, ChangeMetricFn -def _make_numeric_metric(fn: MetricFn) -> Metric: - return Metric(fn=fn, selector=cs.numeric()) +def _make_numeric_metric(fn: ChangeMetricFn) -> ChangeMetric: + return ChangeMetric(fn=fn, selector=cs.numeric()) def mean(left: pl.Expr, right: pl.Expr) -> pl.Expr: @@ -54,7 +54,7 @@ def mean_relative_deviation(left: pl.Expr, right: pl.Expr) -> pl.Expr: return ((right - left) / left).abs().mean() -def quantile(q: float) -> MetricFn: +def quantile(q: float) -> ChangeMetricFn: """Factory returning a metric that computes the ``q``-quantile of ``right - left``.""" if not 0 <= q <= 1: @@ -66,7 +66,7 @@ def _quantile(left: pl.Expr, right: pl.Expr) -> pl.Expr: return _quantile -DEFAULT_CHANGE_METRICS: dict[str, MetricFn] = { +DEFAULT_CHANGE_METRICS: dict[str, ChangeMetricFn] = { "Mean": mean, "Median": median, "Min": min, diff --git a/diffly/metrics/data.py b/diffly/metrics/data.py index 066a06b..12544f2 100644 --- a/diffly/metrics/data.py +++ b/diffly/metrics/data.py @@ -9,67 +9,27 @@ from __future__ import annotations -from collections.abc import Callable - import polars as pl import polars.selectors as cs -from ._common import Metric, MetricFn +from ._common import DataMetric -def null_fraction_change(left: pl.Expr, right: pl.Expr) -> pl.Expr: - """Change in the fraction of null entries, rendered as `` -> ()``. +def null_fraction(col: pl.Expr) -> pl.Expr: + """Fraction of null entries in a column. - ``old`` and ``new`` are the null percentages of the left and right side, and - ``delta`` is their signed difference (``+`` when the right side has proportionally - more nulls, ``-`` when it has fewer). This metric function can be applied to columns - of any type. + Evaluated on each side separately and rendered as a percentage. This metric can be + applied to columns of any type. """ - return _render_change( - left.is_null().mean(), - right.is_null().mean(), - lambda value, signed: _percentage_string( - value, signed=signed, percent_sign=not signed - ), - ) + return col.is_null().mean() -DEFAULT_DATA_METRICS: dict[str, MetricFn | Metric] = { - "Null%": Metric(fn=null_fraction_change, selector=cs.all()), +DEFAULT_DATA_METRICS: dict[str, DataMetric] = { + "Null%": DataMetric( + fn=null_fraction, + selector=cs.all(), + formatter=lambda value: f"{round(value * 100, 2)}%", + delta_formatter=lambda value: f"{round(value * 100, 2)}", + ), } """Preset metrics describing the left and right datasets individually.""" - - -# ------------------------------------------------------------------------------------ # -# UTILITY METHODS # -# ------------------------------------------------------------------------------------ # - - -def _percentage_string( - fraction: pl.Expr, *, signed: bool = False, percent_sign: bool = True -) -> pl.Expr: - """Format a fraction as a percentage string, optionally with an explicit sign.""" - pct = (fraction * 100).round(2) - body = pl.format("{}%", pct) if percent_sign else pl.format("{}", pct) - if signed: - return pl.when(pct >= 0).then(pl.format("+{}", body)).otherwise(body) - return body - - -def _render_change( - old: pl.Expr, - new: pl.Expr, - format_value: Callable[[pl.Expr, bool], pl.Expr], -) -> pl.Expr: - """Render a change as `` -> ()``. - - ``format_value(value, signed)`` formats a value for display; ``old`` and ``new`` are - rendered unsigned and the delta ``new - old`` is rendered signed (with an explicit - ``+`` prefix for positive values). - """ - return pl.format( - "{} -> {} ({})", - format_value(old, False), - format_value(new, False), - format_value(new - old, True), - ) diff --git a/diffly/summary.py b/diffly/summary.py index ac3dda7..e157581 100644 --- a/diffly/summary.py +++ b/diffly/summary.py @@ -6,7 +6,7 @@ import dataclasses import io import json -from collections.abc import Mapping +from collections.abc import Callable, Mapping from dataclasses import dataclass from datetime import date, datetime, timedelta from decimal import Decimal @@ -23,7 +23,7 @@ from rich.text import Text from ._utils import Side, capitalize_first -from .metrics import Metric +from .metrics import ChangeMetric, DataMetric, Metric if TYPE_CHECKING: # pragma: no cover from .comparison import DataFrameComparison @@ -131,7 +131,9 @@ def to_json(self, **kwargs: Any) -> str: "name": "value", "match_rate": 0.667, "n_total_changes": 1, - "changes": [{"old": 1.0, "new": 2.0, "count": 1, "sample_pk": [1]}] + "changes": [{"old": 1.0, "new": 2.0, "count": 1, "sample_pk": [1]}], + "change_metrics": null, + "data_metrics": null } ], "sample_rows_left_only": [], @@ -179,6 +181,7 @@ def _print_diff(self, console: Console) -> None: self._print_schemas(console) self._print_rows(console) self._print_columns(console) + self._print_data_inspection(console) self._print_sample_rows_only_one_side(console, side=Side.LEFT) self._print_sample_rows_only_one_side(console, side=Side.RIGHT) @@ -571,7 +574,7 @@ def _section_columns(self) -> RenderableType: elif not columns: display_items.append(Text("All columns match perfectly.", style="italic")) else: - metric_labels = self._data._metric_labels + metric_labels = self._data._change_metric_labels matches = Table(show_header=bool(metric_labels)) matches.add_column( "Column", @@ -593,7 +596,9 @@ def _section_columns(self) -> RenderableType: f"{_format_fraction_as_percentage(col.match_rate)}", ] for label in metric_labels: - value = col.metrics.get(label) if col.metrics else None + value = ( + col.change_metrics.get(label) if col.change_metrics else None + ) row_items.append(_format_metric_value(value)) if col.changes is not None: change_lines = [] @@ -632,6 +637,41 @@ def _section_columns(self) -> RenderableType: return Group(*display_items) + # ------------------------------- DATA INSPECTION -------------------------------- # + + def _print_data_inspection(self, console: Console) -> None: + if not self._data.columns or not self._data._data_metric_labels: + return + _print_section( + console, + "Data Inspection", + self._section_data_inspection(), + ) + + def _section_data_inspection(self) -> RenderableType: + assert self._data.columns is not None + + table = Table() + table.add_column( + "Column", + max_width=COLUMN_SECTION_COLUMN_WIDTH, + overflow=OVERFLOW, + ) + for label in self._data._data_metric_labels: + table.add_column(label, justify="right", overflow=OVERFLOW) + for col in self._data.columns: + row_items: list[RenderableType] = [Text(col.name, style="cyan")] + for label in self._data._data_metric_labels: + value = col.data_metrics.get(label) if col.data_metrics else None + metric = self._data._data_metrics[label] + row_items.append( + _format_data_metric_value( + value, metric.formatter, metric.delta_formatter + ) + ) + table.add_row(*row_items) + return table + # ------------------------------ ROWS ONLY ONE SIDE ------------------------------ # def _print_sample_rows_only_one_side(self, console: Console, side: Side) -> None: @@ -715,7 +755,8 @@ class SummaryDataColumn: match_rate: float n_total_changes: int changes: list[SummaryDataColumnChange] | None - metrics: dict[str, Any] | None + change_metrics: dict[str, Any] | None + data_metrics: dict[str, Any] | None @dataclass @@ -733,7 +774,9 @@ class SummaryData: _other_common_columns: list[str] _truncated_left_name: str _truncated_right_name: str - _metric_labels: list[str] + _change_metric_labels: list[str] + _data_metric_labels: list[str] + _data_metrics: dict[str, DataMetric] def to_dict(self) -> dict[str, Any]: def _convert(obj: Any) -> Any: @@ -836,12 +879,22 @@ def _validate_primary_key_hidden_columns() -> None: _other_common_columns=comp._other_common_columns, _truncated_left_name=truncated_left, _truncated_right_name=truncated_right, - _metric_labels=[], + _change_metric_labels=[], + _data_metric_labels=[], + _data_metrics={}, ) metrics_resolved: dict[str, Metric] = dict(metrics or {}) metrics_by_column = _compute_column_metrics(comp, metrics_resolved) - metric_labels = list(metrics_resolved.keys()) + change_metric_labels = [ + label for label, m in metrics_resolved.items() if isinstance(m, ChangeMetric) + ] + data_metric_labels = [ + label for label, m in metrics_resolved.items() if isinstance(m, DataMetric) + ] + data_metrics = { + label: m for label, m in metrics_resolved.items() if isinstance(m, DataMetric) + } schemas = _compute_schemas(comp, slim) rows = _compute_rows(comp, slim) @@ -852,6 +905,8 @@ def _validate_primary_key_hidden_columns() -> None: top_k_changes_by_column, show_sample_primary_key_per_change, metrics_by_column, + change_metric_labels, + data_metric_labels, ) sample_rows_left_only, sample_rows_right_only = _compute_sample_rows( comp, sample_k_rows_only @@ -871,7 +926,9 @@ def _validate_primary_key_hidden_columns() -> None: _other_common_columns=comp._other_common_columns, _truncated_left_name=truncated_left, _truncated_right_name=truncated_right, - _metric_labels=metric_labels, + _change_metric_labels=change_metric_labels, + _data_metric_labels=data_metric_labels, + _data_metrics=data_metrics, ) @@ -955,18 +1012,27 @@ def select_columns(selector: cs.Selector) -> set[str]: out: dict[str, dict[str, Any]] = {c: {} for c in all_columns} joined = comp.joined(lazy=True) - agg_exprs = [ - metric.fn( - pl.col(f"{column}_{Side.LEFT}"), - pl.col(f"{column}_{Side.RIGHT}"), - ).alias(f"{label}__{column}") - for label, metric in metrics.items() - for column in sorted(metric_to_columns[label]) - ] + agg_exprs: list[pl.Expr] = [] + for label, metric in metrics.items(): + for column in sorted(metric_to_columns[label]): + left = pl.col(f"{column}_{Side.LEFT}") + right = pl.col(f"{column}_{Side.RIGHT}") + if isinstance(metric, ChangeMetric): + agg_exprs.append(metric.fn(left, right).alias(f"{label}__{column}")) + else: + agg_exprs.append(metric.fn(left).alias(f"{label}__{column}__left")) + agg_exprs.append(metric.fn(right).alias(f"{label}__{column}__right")) + row = joined.select(agg_exprs).collect().row(0, named=True) - for label, columns in metric_to_columns.items(): - for column in columns: - out[column][label] = row[f"{label}__{column}"] + for label, metric in metrics.items(): + for column in metric_to_columns[label]: + if isinstance(metric, ChangeMetric): + out[column][label] = row[f"{label}__{column}"] + else: + out[column][label] = { + "left": row[f"{label}__{column}__left"], + "right": row[f"{label}__{column}__right"], + } return out @@ -977,6 +1043,8 @@ def _compute_columns( top_k_changes_by_column: dict[str, int], show_sample_primary_key_per_change: bool, metrics_by_column: dict[str, dict[str, Any]], + change_metric_labels: list[str], + data_metric_labels: list[str], ) -> list[SummaryDataColumn] | None: # NOTE: We can only compute column matches if there are primary key columns and at # least one joined row. @@ -1017,13 +1085,25 @@ def _compute_columns( sample_pk=sample_pk, ) ) + col_metrics = metrics_by_column.get(col_name) or {} + change_metrics = { + label: col_metrics[label] + for label in change_metric_labels + if label in col_metrics + } + data_metrics = { + label: col_metrics[label] + for label in data_metric_labels + if label in col_metrics + } columns.append( SummaryDataColumn( name=col_name, match_rate=rate, n_total_changes=n_total_changes, changes=changes, - metrics=metrics_by_column.get(col_name), + change_metrics=change_metrics or None, + data_metrics=data_metrics or None, ) ) return columns @@ -1141,5 +1221,40 @@ def _format_metric_value(value: Any) -> str: return _format_value(value, float_format=".4g") +def _format_data_metric_value( + value: Any, + formatter: Callable[[Any], str] | None, + delta_formatter: Callable[[Any], str] | None, +) -> str: + """Format a data metric's ``{"left", "right"}`` pair as `` -> ``. + + Numeric values additionally show the signed delta ``()``; non-numeric + values omit it. ``formatter`` formats a left/right value and ``delta_formatter`` the + delta magnitude (rendered with an explicit sign); either falling back to ``.4g`` + precision for floats when unset. + """ + if value is None: + return "" + + def _fmt(v: Any, fn: Callable[[Any], str] | None) -> str: + if fn is not None: + return fn(v) + if isinstance(v, float): + return format(v, ".4g") + return str(v) + + left, right = value["left"], value["right"] + text = f"{_fmt(left, formatter)} -> {_fmt(right, formatter)}" + if _is_numeric(left) and _is_numeric(right): + delta = right - left + sign = "+" if delta >= 0 else "-" + text += f" ({sign}{_fmt(abs(delta), delta_formatter or formatter)})" + return _yellow(text) + + +def _is_numeric(value: Any) -> bool: + return isinstance(value, (int, float)) and not isinstance(value, bool) + + def _trim_whitespaces(s: str) -> str: return "\n".join(line.rstrip() for line in s.splitlines()) diff --git a/diffly/testing.py b/diffly/testing.py index 9a36458..31ff6cb 100644 --- a/diffly/testing.py +++ b/diffly/testing.py @@ -19,7 +19,7 @@ from ._compat import dy from .comparison import DataFrameComparison, compare_frames -from .metrics import Metric, MetricFn +from .metrics import ChangeMetricFn, DataMetricFn, Metric def assert_collection_equal( @@ -40,7 +40,7 @@ def assert_collection_equal( right_name: str = Side.RIGHT, slim: bool = False, hidden_columns: list[str] | None = None, - metrics: Mapping[str, MetricFn | Metric] | None = None, + metrics: Mapping[str, ChangeMetricFn | DataMetricFn | Metric] | None = None, ) -> None: """Assert that two :mod:`dataframely` collections are equal. @@ -84,12 +84,13 @@ def assert_collection_equal( advanced users who are familiar with the summary format. hidden_columns: Columns for which no values are printed, e.g. because they contain sensitive information. - metrics: Optional mapping from display label to a metric callable - ``(left_expr, right_expr) -> pl.Expr`` or a :class:`~diffly.metrics.Metric`. - Bare callables are only computed for numerical columns; wrap one in a - :class:`~diffly.metrics.Metric` with a column selector to target other column - types. See :mod:`diffly.metrics` for presets. When ``None`` (default), no - metrics are computed; presets are not applied automatically. + metrics: Optional mapping from display label to a + :class:`~diffly.metrics.ChangeMetric`, :class:`~diffly.metrics.DataMetric`, + or a bare callable resolved by its arity (two arguments → change metric on + numerical columns, one argument → data metric on all columns). To target + other column types, construct the metric explicitly with a column selector. + See :mod:`diffly.metrics` for presets. When ``None`` (default), no metrics + are computed; presets are not applied automatically. Raises: AssertionError: If the collections are not equal. @@ -176,7 +177,7 @@ def assert_frame_equal( right_name: str = Side.RIGHT, slim: bool = False, hidden_columns: list[str] | None = None, - metrics: Mapping[str, MetricFn | Metric] | None = None, + metrics: Mapping[str, ChangeMetricFn | DataMetricFn | Metric] | None = None, ) -> None: """Assert that two :mod:`polars` data frames are equal. @@ -227,12 +228,13 @@ def assert_frame_equal( advanced users who are familiar with the summary format. hidden_columns: Columns for which no values are printed, e.g. because they contain sensitive information. - metrics: Optional mapping from display label to a metric callable - ``(left_expr, right_expr) -> pl.Expr`` or a :class:`~diffly.metrics.Metric`. - Bare callables are only computed for numerical columns; wrap one in a - :class:`~diffly.metrics.Metric` with a column selector to target other column - types. See :mod:`diffly.metrics` for presets. When ``None`` (default), no - metrics are computed; presets are not applied automatically. + metrics: Optional mapping from display label to a + :class:`~diffly.metrics.ChangeMetric`, :class:`~diffly.metrics.DataMetric`, + or a bare callable resolved by its arity (two arguments → change metric on + numerical columns, one argument → data metric on all columns). To target + other column types, construct the metric explicitly with a column selector. + See :mod:`diffly.metrics` for presets. When ``None`` (default), no metrics + are computed; presets are not applied automatically. Raises: AssertionError: If the data frames are not equal. diff --git a/docs/api/metrics.rst b/docs/api/metrics.rst index 84c8f82..0ddb6d5 100644 --- a/docs/api/metrics.rst +++ b/docs/api/metrics.rst @@ -6,14 +6,23 @@ Metrics Metrics are scalar aggregations computed per column when generating a :meth:`~diffly.comparison.DataFrameComparison.summary`. Pass them via the -``metrics`` argument as a mapping from display label to a :data:`MetricFn` -callable. :mod:`diffly.metrics` ships a set of presets; you can also supply -your own callable ``(left_expr, right_expr) -> pl.Expr``. - -A bare callable is only computed for numerical columns. To target a different -set of columns, wrap it in a :class:`Metric` with a column selector, e.g. -``Metric(fn, selector=cs.all())``, ``Metric(fn, selector=cs.boolean())``, or -``Metric(fn, selector=cs.by_name("my_column_name"))``. +``metrics`` argument as a mapping from display label to a metric. There are two +families: + +- A :class:`ChangeMetric` describes the *change* between the two sides. Its + callable takes ``(left_expr, right_expr)`` and aggregates over the difference + (e.g. the mean delta). It is rendered as a column in the "Columns" table. +- A :class:`DataMetric` describes each dataset *individually*. Its callable takes + a single column expression and is evaluated on the left and right side + separately (e.g. the fraction of null entries). It is rendered in the + "Data Inspection" section, showing the left and right value side by side. + +A bare callable is resolved by its arity: a two-argument callable becomes a +:class:`ChangeMetric` (computed for numerical columns only), a one-argument +callable becomes a :class:`DataMetric` (computed for all columns). To target a +different set of columns, construct the metric explicitly with a column selector, +e.g. ``ChangeMetric(fn, selector=cs.all())`` or +``DataMetric(fn, selector=cs.boolean())``. Presets come in two families, each with its own module and default set: @@ -24,10 +33,15 @@ Presets come in two families, each with its own module and default set: The change default set is exposed as :data:`DEFAULT_METRICS`. -.. autodata:: MetricFn +.. autodata:: ChangeMetricFn + :no-value: + +.. autodata:: DataMetricFn :no-value: -.. autoclass:: Metric +.. autoclass:: ChangeMetric + +.. autoclass:: DataMetric .. autodata:: DEFAULT_METRICS :no-value: @@ -66,7 +80,7 @@ understand how a change affects the data. .. autosummary:: :toctree: _gen/ - null_fraction_change + null_fraction .. autodata:: DEFAULT_DATA_METRICS :no-value: diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt index f3d3d5f..8df6788 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt index f3d3d5f..8df6788 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt index 2f849f9..b202aac 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt index 2f849f9..b202aac 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt index 18568f4..ff0578d 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,17 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt index f2a498b..5c5d96f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -20,20 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt index 06d07fe..a15e074 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,17 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt index 01c654b..7b844e8 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -8,20 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt index f3d3d5f..8df6788 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt index f3d3d5f..8df6788 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt index 2f849f9..b202aac 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt index 2f849f9..b202aac 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt index 18568f4..ff0578d 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,17 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt index f2a498b..5c5d96f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -20,20 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt index 06d07fe..a15e074 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,17 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt index 01c654b..7b844e8 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -8,20 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt index 3a2a43b..eb2719e 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt index 3a2a43b..eb2719e 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt index 1316f6b..573f85a 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt index 1316f6b..573f85a 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt index bdca125..0aa07e7 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,17 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt index cdd7114..a21fa2c 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -20,20 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt index 370a2d3..e74afd8 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,17 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt index 4a10c0c..c5446f4 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -8,20 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt index 3a2a43b..eb2719e 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt index 3a2a43b..eb2719e 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt index 1316f6b..573f85a 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt index 1316f6b..573f85a 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt index bdca125..0aa07e7 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,17 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt index cdd7114..a21fa2c 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -20,20 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt index 370a2d3..e74afd8 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,17 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt index 4a10c0c..c5446f4 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -8,20 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/test_metrics_null_fraction.py b/tests/summary/fixtures/metrics_null_fraction/test_metrics_null_fraction.py index 9e26bd4..376d2d7 100644 --- a/tests/summary/fixtures/metrics_null_fraction/test_metrics_null_fraction.py +++ b/tests/summary/fixtures/metrics_null_fraction/test_metrics_null_fraction.py @@ -6,7 +6,7 @@ import pytest from diffly import compare_frames, metrics -from diffly.metrics import Metric +from diffly.metrics import ChangeMetric, DataMetric from diffly.metrics.data import DEFAULT_DATA_METRICS from tests.utils import generate_summaries @@ -34,8 +34,12 @@ def test_generate() -> None: # Numeric-only preset alongside a metric applied to all columns. "Mean": metrics.mean, "Null%": DEFAULT_DATA_METRICS["Null%"], - # A user-supplied metric with a custom (string-only) selector. - "str_len_delta": Metric( + # A second, numeric data metric to render more than one data column. + "Distinct": DataMetric(fn=lambda col: col.n_unique()), + # A non-numeric data metric: rendered as ``left -> right`` without a delta. + "Max": DataMetric(fn=lambda col: col.max(), selector=cs.string()), + # A user-supplied change metric with a custom (string-only) selector. + "str_len_delta": ChangeMetric( fn=lambda left, right: ( right.str.len_chars() - left.str.len_chars() ).mean(), diff --git a/tests/summary/test_summary.py b/tests/summary/test_summary.py index 6e43832..d10f4cb 100644 --- a/tests/summary/test_summary.py +++ b/tests/summary/test_summary.py @@ -13,6 +13,7 @@ from diffly import compare_frames, metrics from diffly.comparison import DataFrameComparison +from diffly.metrics.data import DEFAULT_DATA_METRICS from diffly.summary import _format_fraction_as_percentage, to_json_safe @@ -131,6 +132,27 @@ def test_zero_top_k_column_changes_with_show_sample_primary_key() -> None: ) +def test_change_and_data_metrics_routed_to_separate_fields() -> None: + # Joined rows id=1,2,3. value deltas (right - left) = [0, 5, null] → Mean = 2.5. + # value nulls: left 0/3 = 0%, right 1/3 = 33.33% → Null% = "0.0% -> 33.33% (+33.33)". + left = pl.DataFrame({"id": [1, 2, 3], "value": [10.0, 20.0, 30.0]}) + right = pl.DataFrame({"id": [1, 2, 3], "value": [10.0, 25.0, None]}) + comp = compare_frames(left, right, primary_key="id") + + summary = comp.summary( + metrics={"Mean": metrics.mean, "Null%": DEFAULT_DATA_METRICS["Null%"]}, + ) + result = json.loads(summary.to_json()) + + (value_col,) = result["columns"] + assert value_col["name"] == "value" + # Change metric lands in `change_metrics`, data metric in `data_metrics`. + assert value_col["change_metrics"] == {"Mean": pytest.approx(2.5)} + assert value_col["data_metrics"] == { + "Null%": {"left": pytest.approx(0.0), "right": pytest.approx(1 / 3)} + } + + def _make_comparison() -> DataFrameComparison: # Designed so every parametrized flag affects the expected JSON output: # - Same columns in both frames → schemas equal → slim suppresses schemas section @@ -228,7 +250,10 @@ def test_summary_data_parametrized( else None ), # Joined rows (id=1,2,3): value deltas = [0, 5, 0]. - "metrics": {"Mean": pytest.approx(5 / 3), "Max": 5.0} if with_metrics else None, + "change_metrics": {"Mean": pytest.approx(5 / 3), "Max": 5.0} + if with_metrics + else None, + "data_metrics": None, } expected_columns = [] if show_perfect_column_matches: @@ -238,7 +263,8 @@ def test_summary_data_parametrized( "match_rate": 1.0, "n_total_changes": 0, "changes": None, - "metrics": None, + "change_metrics": None, + "data_metrics": None, } ) expected_columns.append(value_col) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 27f5825..8d88bc8 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -65,22 +65,16 @@ def test_mean_relative_deviation_div_by_zero() -> None: assert math.isinf(_apply(metrics.mean_relative_deviation, frame)) -def test_null_fraction_change() -> None: - # left nulls: 1/4 = 25%; right nulls: 3/4 = 75%; delta = +50% - frame = pl.DataFrame({"l": [1, None, 3, 4], "r": [None, None, 3, None]}) - assert _apply(data.null_fraction_change, frame) == "25.0% -> 75.0% (+50.0)" +def test_null_fraction() -> None: + # A data metric describes a single side: 1 null out of 4 rows. + frame = pl.DataFrame({"l": [1, None, 3, 4]}) + assert frame.select(data.null_fraction(pl.col("l"))).item() == pytest.approx(0.25) -def test_null_fraction_change_negative_delta() -> None: - # left nulls: 1/2 = 50%; right nulls: 0%; delta = -50% - frame = pl.DataFrame({"l": [1, None], "r": [1, 2]}) - assert _apply(data.null_fraction_change, frame) == "50.0% -> 0.0% (-50.0)" - - -def test_null_fraction_change_non_numeric() -> None: - # Applies to any column type; here strings. left nulls: 0%; right nulls: 50% - frame = pl.DataFrame({"l": ["a", "b"], "r": ["a", None]}) - assert _apply(data.null_fraction_change, frame) == "0.0% -> 50.0% (+50.0)" +def test_null_fraction_non_numeric() -> None: + # Applies to any column type; here strings. 1 null out of 2 rows. + frame = pl.DataFrame({"l": ["a", None]}) + assert frame.select(data.null_fraction(pl.col("l"))).item() == pytest.approx(0.5) def test_quantile(frame: pl.DataFrame) -> None: