Implementation:Evidentlyai Evidently Legacy Generated Features
| Knowledge Sources | |
|---|---|
| Domains | ML Monitoring, Feature Engineering, Framework Architecture |
| Last Updated | 2026-02-14 12:00 GMT |
Overview
Defines the core abstract base classes and mixins for the Evidently generated features framework, including GeneratedFeatures, GeneratedFeature, ApplyColumnGeneratedFeature, DataFeature, and the descriptor hierarchy (BaseDescriptor, FeatureDescriptor, GeneralDescriptor, MultiColumnFeatureDescriptor).
Description
This module is the foundational framework for all generated (computed) features in the Evidently legacy pipeline. It establishes the class hierarchy and contracts that all feature implementations must follow.
Core Feature Classes
GeneratedFeatures is the top-level abstract base class. It defines:
- generate_features(data, data_definition, options) - Abstract method that must return a DataFrame with new feature columns.
- generate_features_renamed() - Wrapper that renames generated columns using fingerprint-based unique identifiers and reindexes to match the source data.
- list_columns() - Abstract method returning a list of ColumnName objects identifying the feature's output columns.
- as_column(subcolumn) - Resolves a specific output column, supporting multi-column features via the subcolumn parameter.
- Column name management methods (_create_column_name, _extract_subcolumn_name, _create_column) that use the object's fingerprint for globally unique column identification.
GeneratedFeature extends GeneratedFeatures for single-output features. It introduces:
- generate_feature(data, data_definition) - Simplified abstract method that returns a single-column DataFrame.
- __feature_type__ - A class variable specifying the ColumnType (Numerical, Categorical, etc.).
- Automatic implementation of generate_features() that delegates to generate_feature() with an assertion that exactly one column is produced.
FeatureTypeFieldMixin is a Pydantic mixin that moves the feature type from a class variable to an instance field, enabling runtime-configurable feature types.
ApplyColumnGeneratedFeature extends GeneratedFeature for features that apply a per-value transformation to a single column. It requires:
- column_name - The target column.
- display_name_template - A class-level format string for generating display names.
- apply(value) - Abstract method implementing the per-value transformation.
DataFeature extends GeneratedFeature with a generate_data() abstract method returning a pd.Series, plus auto-generated UUID-based naming.
FeatureResult
FeatureResult is a generic dataclass holding the computed feature data for both current and optional reference datasets.
Descriptor Classes
The descriptor classes provide a higher-level API for declaring features:
- BaseDescriptor - Root descriptor with an optional display_name.
- FeatureDescriptor - For single-column features; its feature(column_name) method returns a GeneratedFeatures instance. Provides for_column() and on() convenience methods that return a ColumnName.
- GeneralDescriptor - For features that do not require a column name parameter; its feature() method takes no arguments.
- MultiColumnFeatureDescriptor - For features operating on multiple columns; its feature(columns) method accepts a list of column names. Provides for_columns() and on() convenience methods.
Usage
This module is not used directly for feature computation. Instead, it serves as the base framework that all concrete feature implementations (BERTScoreFeature, ContainsLink, ExactMatchFeature, OOVWordsPercentage, CustomFeature, etc.) and all descriptor classes (CustomColumnEval, ExcludesWords, IncludesWords, etc.) extend. Developers creating new custom features should subclass GeneratedFeature or ApplyColumnGeneratedFeature, and developers creating new descriptors should subclass FeatureDescriptor or GeneralDescriptor.
Code Reference
Source Location
- Repository: Evidentlyai_Evidently
- File:
src/evidently/legacy/features/generated_features.py
Signature
@dataclasses.dataclass
class FeatureResult(Generic[TEngineDataType]):
current: TEngineDataType
reference: Optional[TEngineDataType]
class GeneratedFeatures(EvidentlyBaseModel):
display_name: Optional[str] = None
@abc.abstractmethod
def get_type(self, subcolumn: Optional[str] = None) -> ColumnType: ...
@abc.abstractmethod
def generate_features(self, data: pd.DataFrame, data_definition: DataDefinition, options: Options) -> pd.DataFrame: ...
def generate_features_renamed(self, data: pd.DataFrame, data_definition: DataDefinition, options: Options) -> pd.DataFrame: ...
@abc.abstractmethod
def list_columns(self) -> List[ColumnName]: ...
def as_column(self, subcolumn: Optional[str] = None) -> ColumnName: ...
class GeneratedFeature(GeneratedFeatures):
__feature_type__: ClassVar[ColumnType]
@abc.abstractmethod
def generate_feature(self, data: pd.DataFrame, data_definition: DataDefinition) -> pd.DataFrame: ...
def generate_features(self, data, data_definition, options) -> pd.DataFrame: ...
def list_columns(self) -> List[ColumnName]: ...
@abc.abstractmethod
def _as_column(self) -> ColumnName: ...
def get_type(self, subcolumn=None): ...
class FeatureTypeFieldMixin(BaseModel):
feature_type: ColumnType
def get_type(self, subcolumn=None): ...
class ApplyColumnGeneratedFeature(GeneratedFeature):
display_name_template: ClassVar[str]
column_name: str
@abc.abstractmethod
def apply(self, value: Any): ...
def generate_feature(self, data, data_definition) -> pd.DataFrame: ...
def _as_column(self) -> ColumnName: ...
class DataFeature(GeneratedFeature):
display_name: str
name: str = Field(default_factory=lambda: str(uuid6.uuid7()))
@abc.abstractmethod
def generate_data(self, data: pd.DataFrame, data_definition: DataDefinition) -> pd.Series: ...
def generate_feature(self, data, data_definition) -> pd.DataFrame: ...
def _as_column(self) -> ColumnName: ...
class BaseDescriptor(EvidentlyBaseModel):
display_name: Optional[str] = None
class GeneralDescriptor(BaseDescriptor):
@abc.abstractmethod
def feature(self) -> GeneratedFeatures: ...
def as_column(self) -> ColumnName: ...
class MultiColumnFeatureDescriptor(BaseDescriptor):
def feature(self, columns: List[str]) -> GeneratedFeature: ...
def for_columns(self, columns: List[str]) -> ColumnName: ...
def on(self, columns: List[str]) -> ColumnName: ...
class FeatureDescriptor(BaseDescriptor):
@abc.abstractmethod
def feature(self, column_name: str) -> GeneratedFeatures: ...
def for_column(self, column_name: str) -> ColumnName: ...
def on(self, column_name: str) -> ColumnName: ...
Import
from evidently.legacy.features.generated_features import GeneratedFeatures
from evidently.legacy.features.generated_features import GeneratedFeature
from evidently.legacy.features.generated_features import ApplyColumnGeneratedFeature
from evidently.legacy.features.generated_features import DataFeature
from evidently.legacy.features.generated_features import FeatureTypeFieldMixin
from evidently.legacy.features.generated_features import FeatureResult
from evidently.legacy.features.generated_features import BaseDescriptor
from evidently.legacy.features.generated_features import FeatureDescriptor
from evidently.legacy.features.generated_features import GeneralDescriptor
from evidently.legacy.features.generated_features import MultiColumnFeatureDescriptor
I/O Contract
Inputs
GeneratedFeatures.generate_features():
| Name | Type | Required | Description |
|---|---|---|---|
| data | pd.DataFrame | Yes | The source DataFrame to compute features from. |
| data_definition | DataDefinition | Yes | The data definition describing column types and roles. |
| options | Options | Yes | Configuration options for feature generation. |
GeneratedFeature.generate_feature():
| Name | Type | Required | Description |
|---|---|---|---|
| data | pd.DataFrame | Yes | The source DataFrame to compute the feature from. |
| data_definition | DataDefinition | Yes | The data definition describing column types and roles. |
ApplyColumnGeneratedFeature.apply():
| Name | Type | Required | Description |
|---|---|---|---|
| value | Any | Yes | A single cell value from the target column. |
FeatureDescriptor.feature():
| Name | Type | Required | Description |
|---|---|---|---|
| column_name | str | Yes | The column to generate features for. |
Outputs
| Name | Type | Description |
|---|---|---|
| generate_features() return | pd.DataFrame | A DataFrame with one or more new feature columns. |
| generate_feature() return | pd.DataFrame | A single-column DataFrame with the computed feature. |
| apply() return | Any | The transformed value for a single cell. |
| list_columns() return | List[ColumnName] | A list of ColumnName objects identifying the feature's output columns. |
| as_column() return | ColumnName | A ColumnName reference for use in metrics and tests. |
| feature() return | GeneratedFeatures | A GeneratedFeatures instance ready for computation. |
Usage Examples
import pandas as pd
from evidently.legacy.features.generated_features import (
GeneratedFeature, ApplyColumnGeneratedFeature, FeatureDescriptor
)
from evidently.legacy.core import ColumnType
from evidently.legacy.base_metric import ColumnName
from evidently.legacy.utils.data_preprocessing import DataDefinition
from typing import ClassVar, Any
# Example: Creating a custom feature by subclassing ApplyColumnGeneratedFeature
class TextLengthFeature(ApplyColumnGeneratedFeature):
__feature_type__: ClassVar = ColumnType.Numerical
display_name_template: ClassVar = "Text Length for {column_name}"
def __init__(self, column_name: str):
super().__init__(column_name=column_name)
def apply(self, value: Any):
if value is None:
return 0
return len(str(value))
# Example: Creating a descriptor for the custom feature
class TextLengthDescriptor(FeatureDescriptor):
def feature(self, column_name: str):
return TextLengthFeature(column_name=column_name)
# Using the descriptor
descriptor = TextLengthDescriptor()
column_ref = descriptor.on("response_text")
Related Pages
- Environment:Evidentlyai_Evidently_Python_Core_Environment
- Evidentlyai_Evidently_Legacy_Custom_Feature - Concrete custom feature implementations using this framework.
- Evidentlyai_Evidently_Legacy_Custom_Descriptor - Descriptor implementations for custom features.
- Evidentlyai_Evidently_Legacy_BERTScore_Feature - A concrete GeneratedFeature implementation.
- Evidentlyai_Evidently_Legacy_Contains_Link_Feature - A concrete ApplyColumnGeneratedFeature implementation.
- Evidentlyai_Evidently_Legacy_OOV_Words_Feature - A concrete ApplyColumnGeneratedFeature implementation.
- Evidentlyai_Evidently_Legacy_Exact_Match_Feature - A concrete GeneratedFeature implementation.
- Evidentlyai_Evidently_Legacy_Words_Descriptor - Descriptor implementations for word-based features.
- Evidentlyai_Evidently_Legacy_Feature_Generator - The orchestrator that runs GeneratedFeatures instances.