Implementation:Evidentlyai Evidently Legacy Custom Feature
| Knowledge Sources | |
|---|---|
| Domains | ML Monitoring, Feature Engineering |
| Last Updated | 2026-02-14 12:00 GMT |
Overview
Provides three generated feature classes that allow users to define custom feature computations via arbitrary callable functions operating on full DataFrames, single columns, or pairs of columns.
Description
This module defines three concrete GeneratedFeature subclasses, each accepting a user-provided callable to compute custom features:
CustomFeature accepts a function with signature (pd.DataFrame, DataDefinition) -> pd.Series. It has access to the entire DataFrame and data definition, providing maximum flexibility for features that depend on multiple columns or dataset metadata.
CustomSingleColumnFeature accepts a function with signature (pd.Series) -> pd.Series and a column_name parameter. The function is applied to a single column from the DataFrame. This class also overrides get_fingerprint_parts() to exclude the func field from fingerprinting, since callables are not reliably serializable.
CustomPairColumnFeature accepts a function with signature (pd.Series, pd.Series) -> pd.Series along with first_column and second_column parameters. The two specified columns are extracted from the DataFrame and passed to the function.
All three classes use FeatureTypeFieldMixin to allow the feature type (Numerical, Categorical, etc.) to be specified as a field rather than a class variable, defaulting to Numerical. Each class generates a unique name using new_id() (UUID) by default and wraps the function result in a single-column DataFrame.
Usage
Use these classes when you need to compute custom features that cannot be expressed through the built-in feature types. CustomFeature is best for complex multi-column logic, CustomSingleColumnFeature for simple column transformations, and CustomPairColumnFeature for pairwise column operations. They are typically instantiated by the corresponding descriptor classes in custom_descriptor.py but can also be used directly.
Code Reference
Source Location
- Repository: Evidentlyai_Evidently
- File:
src/evidently/legacy/features/custom_feature.py
Signature
class CustomFeature(FeatureTypeFieldMixin, GeneratedFeature):
display_name: str
name: str = Field(default_factory=lambda: str(new_id()))
func: Callable[[pd.DataFrame, DataDefinition], pd.Series]
feature_type: ColumnType = ColumnType.Numerical
def generate_feature(self, data: pd.DataFrame, data_definition: DataDefinition) -> pd.DataFrame: ...
def _as_column(self) -> ColumnName: ...
class CustomSingleColumnFeature(FeatureTypeFieldMixin, GeneratedFeature):
display_name: str
func: Callable[[pd.Series], pd.Series]
name: str = Field(default_factory=lambda: str(new_id()))
column_name: str
feature_type: ColumnType = ColumnType.Numerical
def generate_feature(self, data: pd.DataFrame, data_definition: DataDefinition) -> pd.DataFrame: ...
def _as_column(self) -> ColumnName: ...
def get_fingerprint_parts(self) -> Tuple[FingerprintPart, ...]: ...
class CustomPairColumnFeature(FeatureTypeFieldMixin, GeneratedFeature):
display_name: str
func: Callable[[pd.Series, pd.Series], pd.Series]
name: str = Field(default_factory=lambda: str(new_id()))
first_column: str
second_column: str
feature_type: ColumnType = ColumnType.Numerical
def generate_feature(self, data: pd.DataFrame, data_definition: DataDefinition) -> pd.DataFrame: ...
def _as_column(self) -> ColumnName: ...
Import
from evidently.legacy.features.custom_feature import CustomFeature
from evidently.legacy.features.custom_feature import CustomSingleColumnFeature
from evidently.legacy.features.custom_feature import CustomPairColumnFeature
I/O Contract
Inputs
CustomFeature:
| Name | Type | Required | Description |
|---|---|---|---|
| func | Callable[[pd.DataFrame, DataDefinition], pd.Series] | Yes | A function that receives the full DataFrame and DataDefinition and returns a Series. |
| display_name | str | Yes | Human-readable name for the feature. |
| name | str | No | Unique identifier for the feature column. Defaults to a generated UUID. |
| feature_type | ColumnType | No | The type of the resulting feature column. Defaults to ColumnType.Numerical. |
CustomSingleColumnFeature:
| Name | Type | Required | Description |
|---|---|---|---|
| func | Callable[[pd.Series], pd.Series] | Yes | A function that transforms a single column Series. |
| column_name | str | Yes | The name of the DataFrame column to pass to the function. |
| display_name | str | Yes | Human-readable name for the feature. |
| name | str | No | Unique identifier for the feature column. Defaults to a generated UUID. |
| feature_type | ColumnType | No | The type of the resulting feature column. Defaults to ColumnType.Numerical. |
CustomPairColumnFeature:
| Name | Type | Required | Description |
|---|---|---|---|
| func | Callable[[pd.Series, pd.Series], pd.Series] | Yes | A function that operates on two column Series and returns a result Series. |
| first_column | str | Yes | The name of the first DataFrame column. |
| second_column | str | Yes | The name of the second DataFrame column. |
| display_name | str | Yes | Human-readable name for the feature. |
| name | str | No | Unique identifier for the feature column. Defaults to a generated UUID. |
| feature_type | ColumnType | No | The type of the resulting feature column. Defaults to ColumnType.Numerical. |
Outputs
| Name | Type | Description |
|---|---|---|
| generate_feature() return | pd.DataFrame | A single-column DataFrame containing the computed feature values, with column name set to the feature's name attribute. |
Usage Examples
import pandas as pd
from evidently.legacy.features.custom_feature import (
CustomFeature, CustomSingleColumnFeature, CustomPairColumnFeature
)
from evidently.legacy.core import ColumnType
# Full DataFrame access
custom = CustomFeature(
func=lambda df, dd: df["col_a"] + df["col_b"],
display_name="Sum of A and B",
feature_type=ColumnType.Numerical,
)
# Single column transformation
single = CustomSingleColumnFeature(
func=lambda s: s.str.len(),
column_name="text",
display_name="Text Length",
)
# Pair column comparison
pair = CustomPairColumnFeature(
func=lambda s1, s2: (s1 - s2).abs(),
first_column="predicted_score",
second_column="actual_score",
display_name="Score Difference",
)
Related Pages
- Environment:Evidentlyai_Evidently_Python_Core_Environment
- Evidentlyai_Evidently_Legacy_Custom_Descriptor - Descriptor classes that instantiate these custom features from higher-level configuration.
- Evidentlyai_Evidently_Legacy_Generated_Features - Base classes (GeneratedFeature, FeatureTypeFieldMixin) that these classes extend.