Skip to content

Commit

Permalink
Fix proper convert for data_definition to input_data. (#1461)
Browse files Browse the repository at this point in the history
  • Loading branch information
Liraim authored Jan 28, 2025
1 parent 6c302f5 commit 471d175
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 87 deletions.
10 changes: 7 additions & 3 deletions src/evidently/future/metrics/classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import Type
from typing import TypeVar

from evidently.base_metric import InputData
from evidently.base_metric import Metric
from evidently.future.metric_types import BoundTest
from evidently.future.metric_types import ByLabelCalculation
Expand All @@ -19,6 +20,7 @@
from evidently.future.metric_types import TMetricResult
from evidently.future.metrics._legacy import LegacyMetricCalculation
from evidently.future.report import Context
from evidently.future.report import _default_input_data_generator
from evidently.future.tests import Reference
from evidently.future.tests import eq
from evidently.future.tests import gt
Expand All @@ -44,9 +46,6 @@ class ClassificationQualityByLabel(ByLabelMetric):
probas_threshold: Optional[float] = None
k: Optional[int] = None

# def _default_tests_with_reference(self, context: Context) -> List[BoundTest]:
# return [eq(Reference(relative=0.2)).bind_single(self.get_fingerprint())]


class ClassificationQualityBase(SingleValueMetric):
probas_threshold: Optional[float] = None
Expand All @@ -69,6 +68,11 @@ def _get_dummy_value(
TSingleValueMetric = TypeVar("TSingleValueMetric", bound=ClassificationQuality)


def _gen_classification_input_data(context: "Context") -> InputData:
default_input_data = _default_input_data_generator(context)
return default_input_data


class LegacyClassificationQualityByClass(
ByLabelCalculation[TByLabelMetric],
LegacyMetricCalculation[
Expand Down
90 changes: 28 additions & 62 deletions src/evidently/future/metrics/regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from evidently.future.metric_types import TSingleValueMetric
from evidently.future.metrics._legacy import LegacyMetricCalculation
from evidently.future.report import Context
from evidently.future.report import _default_input_data_generator
from evidently.future.tests import Reference
from evidently.future.tests import eq
from evidently.future.tests import gt
Expand All @@ -41,6 +42,23 @@
}


def _gen_regression_input_data(context: "Context") -> InputData:
default_data = _default_input_data_generator(context)
regression = context.data_definition.get_regression("default")
if regression is None:
raise ValueError("No default regression in data definition")
default_data.column_mapping.target = regression.target
default_data.column_mapping.prediction = regression.prediction

definition = create_data_definition(
default_data.reference_data,
default_data.current_data,
default_data.column_mapping,
)
default_data.data_definition = definition
return default_data


class LegacyRegressionMeanStdMetric(
MeanStdCalculation[TMeanStdMetric],
LegacyMetricCalculation[MeanStdValue, TMeanStdMetric, RegressionQualityMetricResults, RegressionQualityMetric],
Expand All @@ -50,30 +68,17 @@ class LegacyRegressionMeanStdMetric(
def legacy_metric(self) -> RegressionQualityMetric:
return RegressionQualityMetric()

def _gen_input_data(self, context: "Context") -> InputData:
default_data = super()._gen_input_data(context)
regression = context.data_definition.get_regression("default")
if regression is None:
raise ValueError("No default regression in data definition")
default_data.column_mapping.target = regression.target
default_data.column_mapping.prediction = regression.prediction

definition = create_data_definition(
default_data.reference_data,
default_data.current_data,
default_data.column_mapping,
)
default_data.data_definition = definition
return default_data

def get_additional_widgets(self, context: "Context") -> List[BaseWidgetInfo]:
result = []
for field, metric in ADDITIONAL_WIDGET_MAPPING.items():
if hasattr(self.metric, field) and getattr(self.metric, field):
_, widgets = context.get_legacy_metric(metric, self._gen_input_data)
_, widgets = context.get_legacy_metric(metric, _gen_regression_input_data)
result += widgets
return result

def _gen_input_data(self, context: "Context") -> InputData:
return _gen_regression_input_data(context)


class LegacyRegressionSingleValueMetric(
SingleValueCalculation[TSingleValueMetric],
Expand All @@ -84,30 +89,17 @@ class LegacyRegressionSingleValueMetric(
def legacy_metric(self) -> RegressionQualityMetric:
return RegressionQualityMetric()

def _gen_input_data(self, context: "Context") -> InputData:
default_data = super()._gen_input_data(context)
regression = context.data_definition.get_regression("default")
if regression is None:
raise ValueError("No default regression in data definition")
default_data.column_mapping.target = regression.target
default_data.column_mapping.prediction = regression.prediction

definition = create_data_definition(
default_data.reference_data,
default_data.current_data,
default_data.column_mapping,
)
default_data.data_definition = definition
return default_data

def get_additional_widgets(self, context: "Context") -> List[BaseWidgetInfo]:
result = []
for field, metric in ADDITIONAL_WIDGET_MAPPING.items():
if hasattr(self.metric, field) and getattr(self.metric, field):
_, widgets = context.get_legacy_metric(metric, self._gen_input_data)
_, widgets = context.get_legacy_metric(metric, _gen_regression_input_data)
result += widgets
return result

def _gen_input_data(self, context: "Context") -> InputData:
return _gen_regression_input_data(context)


class MeanError(MeanStdMetric):
error_plot: bool = True
Expand Down Expand Up @@ -269,20 +261,7 @@ def legacy_metric(self) -> RegressionDummyMetric:
return RegressionDummyMetric()

def _gen_input_data(self, context: "Context") -> InputData:
default_data = super()._gen_input_data(context)
regression = context.data_definition.get_regression("default")
if regression is None:
raise ValueError("No default regression in data definition")
default_data.column_mapping.target = regression.target
default_data.column_mapping.prediction = regression.prediction

definition = create_data_definition(
default_data.reference_data,
default_data.current_data,
default_data.column_mapping,
)
default_data.data_definition = definition
return default_data
return _gen_regression_input_data(context)


class LegacyRegressionDummyValueMetric(
Expand All @@ -295,20 +274,7 @@ def legacy_metric(self) -> RegressionDummyMetric:
return RegressionDummyMetric()

def _gen_input_data(self, context: "Context") -> InputData:
default_data = super()._gen_input_data(context)
regression = context.data_definition.get_regression("default")
if regression is None:
raise ValueError("No default regression in data definition")
default_data.column_mapping.target = regression.target
default_data.column_mapping.prediction = regression.prediction

definition = create_data_definition(
default_data.reference_data,
default_data.current_data,
default_data.column_mapping,
)
default_data.data_definition = definition
return default_data
return _gen_regression_input_data(context)


class DummyMAE(SingleValueMetric):
Expand Down
33 changes: 25 additions & 8 deletions src/evidently/future/presets/classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from evidently.future.metrics.classification import DummyF1Score
from evidently.future.metrics.classification import DummyPrecision
from evidently.future.metrics.classification import DummyRecall
from evidently.future.metrics.classification import _gen_classification_input_data
from evidently.future.report import Context
from evidently.metrics import ClassificationConfusionMatrix
from evidently.metrics import ClassificationDummyMetric
Expand Down Expand Up @@ -93,15 +94,25 @@ def generate_metrics(self, context: "Context") -> List[Metric]:
return metrics

def render(self, context: "Context", results: Dict[MetricId, MetricResult]) -> List[BaseWidgetInfo]:
_, render = context.get_legacy_metric(ClassificationQualityMetric(probas_threshold=self._probas_threshold))
_, render = context.get_legacy_metric(
ClassificationQualityMetric(probas_threshold=self._probas_threshold),
_gen_classification_input_data,
)
if self._conf_matrix:
render += context.get_legacy_metric(ClassificationConfusionMatrix(probas_threshold=self._probas_threshold))[
1
]
render += context.get_legacy_metric(
ClassificationConfusionMatrix(probas_threshold=self._probas_threshold),
_gen_classification_input_data,
)[1]
if self._pr_curve:
render += context.get_legacy_metric(ClassificationPRCurve(probas_threshold=self._probas_threshold))[1]
render += context.get_legacy_metric(
ClassificationPRCurve(probas_threshold=self._probas_threshold),
_gen_classification_input_data,
)[1]
if self._pr_table:
render += context.get_legacy_metric(ClassificationPRTable(probas_threshold=self._probas_threshold))[1]
render += context.get_legacy_metric(
ClassificationPRTable(probas_threshold=self._probas_threshold),
_gen_classification_input_data,
)[1]
return render


Expand All @@ -119,7 +130,10 @@ def generate_metrics(self, context: "Context") -> List[Metric]:
]

def render(self, context: "Context", results: Dict[MetricId, MetricResult]):
render = context.get_legacy_metric(ClassificationQualityByClass(self._probas_threshold, self._k))[1]
render = context.get_legacy_metric(
ClassificationQualityByClass(self._probas_threshold, self._k),
_gen_classification_input_data,
)[1]
widget = render
widget[0].params["counters"][0]["label"] = "Classification Quality by Label"
return widget
Expand All @@ -138,7 +152,10 @@ def generate_metrics(self, context: "Context") -> List[Metric]:
]

def render(self, context: "Context", results: Dict[MetricId, MetricResult]) -> List[BaseWidgetInfo]:
_, widgets = context.get_legacy_metric(ClassificationDummyMetric(self._probas_threshold, self._k))
_, widgets = context.get_legacy_metric(
ClassificationDummyMetric(self._probas_threshold, self._k),
_gen_classification_input_data,
)
return widgets


Expand Down
3 changes: 2 additions & 1 deletion src/evidently/future/presets/dataset_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from evidently.future.metrics.dataset_statistics import EmptyColumnsCount
from evidently.future.metrics.dataset_statistics import EmptyRowsCount
from evidently.future.report import Context
from evidently.future.report import _default_input_data_generator
from evidently.metric_results import Label
from evidently.metrics import DatasetSummaryMetric
from evidently.model.widget import BaseWidgetInfo
Expand Down Expand Up @@ -224,7 +225,7 @@ def generate_metrics(self, context: Context) -> List[Metric]:

def render(self, context: Context, results: Dict[MetricId, MetricResult]) -> List[BaseWidgetInfo]:
metric = DatasetSummaryMetric()
_, render = context.get_legacy_metric(metric)
_, render = context.get_legacy_metric(metric, _default_input_data_generator)
return render


Expand Down
7 changes: 5 additions & 2 deletions src/evidently/future/presets/drift.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from evidently.future.metrics import ValueDrift
from evidently.future.metrics.column_statistics import DriftedColumnsCount
from evidently.future.report import Context
from evidently.future.report import _default_input_data_generator
from evidently.metrics import DataDriftTable
from evidently.metrics import DatasetDriftMetric
from evidently.metrics.data_drift.embedding_drift_methods import DriftMethod
Expand Down Expand Up @@ -110,7 +111,8 @@ def render(self, context: Context, results: Dict[MetricId, MetricResult]) -> Lis
num_stattest_threshold=self.num_stattest_threshold,
text_stattest_threshold=self.text_stattest_threshold,
per_column_stattest_threshold=self.per_column_stattest_threshold,
)
),
_default_input_data_generator,
)[1]
table = context.get_legacy_metric(
DataDriftTable(
Expand All @@ -125,7 +127,8 @@ def render(self, context: Context, results: Dict[MetricId, MetricResult]) -> Lis
num_stattest_threshold=self.num_stattest_threshold,
text_stattest_threshold=self.text_stattest_threshold,
per_column_stattest_threshold=self.per_column_stattest_threshold,
)
),
_default_input_data_generator,
)[1]
return dataset_drift + table

Expand Down
26 changes: 21 additions & 5 deletions src/evidently/future/presets/regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from evidently.future.metrics import DummyRMSE
from evidently.future.metrics import MeanError
from evidently.future.metrics import R2Score
from evidently.future.metrics.regression import _gen_regression_input_data
from evidently.future.report import Context
from evidently.metrics import RegressionDummyMetric
from evidently.metrics import RegressionErrorDistribution
Expand Down Expand Up @@ -45,13 +46,25 @@ def generate_metrics(self, context: Context) -> List[Metric]:
]

def render(self, context: Context, results: Dict[MetricId, MetricResult]) -> List[BaseWidgetInfo]:
widgets = context.get_legacy_metric(RegressionQualityMetric())[1]
widgets = context.get_legacy_metric(
RegressionQualityMetric(),
_gen_regression_input_data,
)[1]
if self._pred_actual_plot:
widgets += context.get_legacy_metric(RegressionPredictedVsActualPlot())[1]
widgets += context.get_legacy_metric(
RegressionPredictedVsActualPlot(),
_gen_regression_input_data,
)[1]
if self._error_plot:
widgets += context.get_legacy_metric(RegressionErrorPlot())[1]
widgets += context.get_legacy_metric(
RegressionErrorPlot(),
_gen_regression_input_data,
)[1]
if self._error_distr:
widgets += context.get_legacy_metric(RegressionErrorDistribution())[1]
widgets += context.get_legacy_metric(
RegressionErrorDistribution(),
_gen_regression_input_data,
)[1]
return widgets


Expand All @@ -64,7 +77,10 @@ def generate_metrics(self, context: Context) -> List[Metric]:
]

def render(self, context: Context, results: Dict[MetricId, MetricResult]) -> List[BaseWidgetInfo]:
return context.get_legacy_metric(RegressionDummyMetric())[1]
return context.get_legacy_metric(
RegressionDummyMetric(),
_gen_regression_input_data,
)[1]


class RegressionPreset(MetricContainer):
Expand Down
4 changes: 2 additions & 2 deletions src/evidently/future/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,15 @@ def get_reference_metric_result(self, metric: Metric) -> MetricResult:
def get_legacy_metric(
self,
metric: LegacyMetric[T],
input_data_generator: Optional[Callable[["Context"], InputData]] = None,
input_data_generator: Optional[Callable[["Context"], InputData]],
) -> Tuple[T, List[BaseWidgetInfo]]:
if input_data_generator is None:
input_data_generator = _default_input_data_generator
input_data = input_data_generator(self)
dependencies = _discover_dependencies(metric)
for _, obj in dependencies:
if isinstance(obj, LegacyMetric):
(result, render) = self.get_legacy_metric(obj)
(result, render) = self.get_legacy_metric(obj, input_data_generator)
object.__setattr__(obj, "get_result", lambda: result)
else:
raise ValueError(f"unexpected type {type(obj)}")
Expand Down
Loading

0 comments on commit 471d175

Please sign in to comment.