Saltar al contenido principal

Feature stores

Definición

Un feature store es un sistema de datos diseñado específicamente para gestionar el ciclo de vida de las características de ML — desde la transformación de datos brutos, pasando por el almacenamiento, hasta el servicio de baja latencia — de forma coherente entre el entrenamiento del modelo y la inferencia en producción. Sin un feature store, los equipos suelen encontrar sesgo entrenamiento-servicio: la lógica de cálculo de características ejecutada offline durante el entrenamiento difiere sutilmente de la lógica utilizada en el momento del servicio, haciendo que los modelos en producción rindan por debajo de lo esperado en comparación con la evaluación offline.

Los feature stores abordan esto almacenando las definiciones de características como código y ejecutando la misma lógica de transformación en ambos contextos. Mantienen dos capas de almacenamiento complementarias: un almacén offline (un almacén de datos o lago de datos, p. ej. BigQuery, Redshift, archivos Parquet en S3) que alberga grandes conjuntos de datos históricos utilizados para entrenamiento y puntuación por lotes, y un almacén en línea (una base de datos de valores clave de baja latencia, p. ej. Redis, DynamoDB, Cassandra) que sirve valores de características precalculados a los modelos en el momento de la inferencia con latencia de sub-milisegundos.

El problema del sesgo entrenamiento-servicio y la necesidad de reutilización de características se vuelven agudos a escala. Una organización grande puede tener docenas de equipos calculando características similares (gasto del cliente en los últimos 7 días, duración de la sesión, tipo de dispositivo) de forma independiente, con sutiles diferencias en la lógica de negocio. Un feature store proporciona un catálogo gobernado donde las características se definen una vez, se validan y se reutilizan entre equipos y modelos, reduciendo drásticamente el esfuerzo de ingeniería duplicado y el riesgo de lógica de características inconsistente.

Cómo funciona

Definición de características y pipelines de transformación

Las características se definen como código — clases Python o manifiestos YAML — que especifican la fuente de datos, la lógica de transformación y la clave de entidad (el identificador usado para buscar características, p. ej., user_id, product_id). Los pipelines de transformación por lotes se ejecutan según un programa para materializar características en el almacén offline. Los pipelines de transformación por stream (p. ej., usando Flink o Spark Structured Streaming) mantienen el almacén en línea actualizado para características sensibles al tiempo como señales de fraude en tiempo real.

Almacén offline: recuperación de datos de entrenamiento

Al entrenar un modelo, se genera un conjunto de datos proporcionando una lista de claves de entidad y un conjunto de marcas de tiempo (una "unión punto en el tiempo"). El feature store recupera los valores de características que eran correctos a partir de cada marca de tiempo, evitando la fuga de datos futuros. Esta corrección punto en el tiempo es una de las cosas más difíciles de implementar correctamente sin un feature store y una de las garantías más valiosas que proporciona.

Almacén en línea: servicio de baja latencia

Antes de que un modelo sirva una predicción, necesita valores de características para la entidad que se está puntuando (p. ej., el usuario que realiza una solicitud). El cliente del feature store consulta el almacén en línea por clave de entidad y devuelve un vector de características en milisegundos. Dado que las mismas definiciones de características sustentan tanto los almacenes offline como online, se garantiza que los valores se calculan de forma idéntica.

Registro de características y gobernanza

Un catálogo de características documenta cada característica: su definición, propietario, tipo de dato, garantía de frescura y qué modelos la consumen. Esta capa de gobernanza habilita la descubribilidad — un nuevo equipo puede explorar características existentes antes de escribir las propias — y el análisis de impacto — comprender qué modelos se ven afectados si cambia la fuente de datos upstream de una característica.

Trabajos de materialización

La materialización es el proceso de ejecutar pipelines de transformación y escribir resultados en los almacenes. La materialización offline se ejecuta como un trabajo por lotes programado. La materialización en línea copia un subconjunto de datos offline en el almacén en línea para una recuperación rápida, o está impulsada por pipelines de streaming cuando se requiere frescura en tiempo real. Feast, Tecton y Hopsworks proporcionan comandos CLI o integraciones de orquestación para activar y monitorear la materialización.

Cuándo usar / Cuándo NO usar

Usar cuandoEvitar cuando
Múltiples equipos o modelos comparten la misma lógica de características y la coherencia es críticaSe tiene un único modelo con un conjunto pequeño y estable de características que nunca cambia
El sesgo entrenamiento-servicio ha causado incidentes en producción o brechas de precisiónLos requisitos de latencia de inferencia son relajados y la puntuación por lotes es suficiente
Se necesitan conjuntos de datos de entrenamiento correctos punto en el tiempo para evitar fuga de datosLa sobrecarga de ingeniería de operar un feature store supera la escala del proyecto
Las características deben servirse con latencia de sub-milisegundos para predicciones en tiempo realSe está en exploración temprana y las características aún no son suficientemente estables para formalizarse
Los requisitos regulatorios exigen un catálogo de características gobernado y auditableEl equipo de ciencia de datos es pequeño y carece de soporte de ingeniería de ML para gestionar la infraestructura

Comparaciones

CriterioFeastTectonHopsworks
Código abiertoSí (Apache 2.0)No (SaaS / gestionado)Sí núcleo; empresa de pago
Oferta gestionadaNo (solo auto-hospedado)Sí (totalmente gestionado)Sí (nube o on-prem)
Características de streamingLimitado (vía fuente Kafka)Nativo, grado producciónNativo con integración Flink
Monitoreo de característicasBásicoAvanzado (deriva integrada)Avanzado
Mejor paraEquipos que quieren control OSSEmpresas que necesitan características en tiempo real gestionadasEquipos que quieren código abierto de pila completa

Ventajas y desventajas

VentajasDesventajas
Elimina el sesgo entrenamiento-servicio al compartir la lógica de transformaciónInversión significativa de ingeniería para configurar y operar
Habilita la reutilización de características entre equipos, reduciendo el esfuerzo duplicadoAñade una dependencia operativa en la ruta de servicio (disponibilidad del almacén en línea)
Las uniones punto en el tiempo previenen la fuga de datos en los datos de entrenamientoLas definiciones de características pueden convertirse en un cuello de botella si la gobernanza es demasiado rígida
Centraliza la gobernanza y documentación de característicasCurva de aprendizaje para científicos de datos no familiarizados con la abstracción
Admite servicio de características por lotes y en tiempo realExcesivo para equipos con un pequeño número de modelos y características estables

Ejemplos de código

# feast_feature_store_example.py
# Demonstrates defining, materializing, and retrieving features with Feast.
# Prerequisites:
# pip install feast pandas scikit-learn
# feast init my_feature_repo && cd my_feature_repo
# (Adjust the data source path below to match your environment.)

# ── feature_repo/features.py ──────────────────────────────────────────────────
# This file defines the feature views and entities in your Feast registry.

from datetime import timedelta
import pandas as pd
from feast import (
Entity,
FeatureStore,
FeatureView,
Field,
FileSource,
)
from feast.types import Float32, Int64

# 1. Define the entity — the primary key used to look up features
driver = Entity(
name="driver",
description="A taxi driver identified by driver_id",
)

# 2. Define the data source (parquet file for local demo; swap for BigQuery etc.)
driver_stats_source = FileSource(
path="data/driver_stats.parquet", # generated below
timestamp_field="event_timestamp",
created_timestamp_column="created",
)

# 3. Define a FeatureView — the transformation and storage spec
driver_stats_fv = FeatureView(
name="driver_hourly_stats",
entities=[driver],
ttl=timedelta(days=7), # how long features stay valid
schema=[
Field(name="conv_rate", dtype=Float32),
Field(name="acc_rate", dtype=Float32),
Field(name="avg_daily_trips", dtype=Int64),
],
online=True, # materialize to online store
source=driver_stats_source,
)


# ── generate_sample_data.py ───────────────────────────────────────────────────
# Run this once to create sample data before materializing.
def generate_driver_stats(path: str = "data/driver_stats.parquet") -> None:
import os
os.makedirs("data", exist_ok=True)

rng = pd.date_range(end=pd.Timestamp.now(tz="UTC"), periods=48, freq="h")
df = pd.DataFrame({
"driver_id": [1001, 1002, 1003] * 16,
"event_timestamp": list(rng[:48]),
"created": pd.Timestamp.now(tz="UTC"),
"conv_rate": [0.8, 0.6, 0.9] * 16,
"acc_rate": [0.95, 0.88, 0.92] * 16,
"avg_daily_trips": [150, 200, 175] * 16,
})
df.to_parquet(path, index=False)
print(f"Sample data written to {path}")


# ── training_data_retrieval.py ────────────────────────────────────────────────
# Retrieve a point-in-time correct training dataset.
def get_training_data(repo_path: str = ".") -> pd.DataFrame:
store = FeatureStore(repo_path=repo_path)

# Entity DataFrame: the entities and timestamps we want features for
entity_df = pd.DataFrame({
"driver_id": [1001, 1002, 1003],
"event_timestamp": [
pd.Timestamp("2024-01-15 10:00:00", tz="UTC"),
pd.Timestamp("2024-01-15 11:00:00", tz="UTC"),
pd.Timestamp("2024-01-15 12:00:00", tz="UTC"),
],
"label": [1, 0, 1], # target variable for supervised training
})

# Point-in-time join: retrieves feature values as-of each row's timestamp
training_df = store.get_historical_features(
entity_df=entity_df,
features=[
"driver_hourly_stats:conv_rate",
"driver_hourly_stats:acc_rate",
"driver_hourly_stats:avg_daily_trips",
],
).to_df()

print("Training dataset:")
print(training_df.to_string())
return training_df


# ── online_serving.py ─────────────────────────────────────────────────────────
# Retrieve features for real-time inference after materialization.
def get_online_features(driver_ids: list, repo_path: str = ".") -> dict:
store = FeatureStore(repo_path=repo_path)

# Materialize features to the online store first:
# store.materialize_incremental(end_date=pd.Timestamp.now(tz="UTC"))

feature_vector = store.get_online_features(
features=[
"driver_hourly_stats:conv_rate",
"driver_hourly_stats:acc_rate",
"driver_hourly_stats:avg_daily_trips",
],
entity_rows=[{"driver_id": did} for did in driver_ids],
).to_dict()

print("Online feature vector:")
for key, values in feature_vector.items():
print(f" {key}: {values}")
return feature_vector


# ── main ──────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
generate_driver_stats()
# After running `feast apply` to register the feature views:
# training_df = get_training_data()
# online_fv = get_online_features([1001, 1002])
print("Feature definitions ready. Run `feast apply` to register them.")

Recursos prácticos

Ver también