Cómo crear canales de validación de datos de nivel de producción utilizando Pandera, esquemas escritos y contratos de marco de datos componibles

Esquemas y contratos de marcos de datos componibles En este tutorial, demostramos cómo crear canales de validación de datos robustos y de nivel de producción utilizando Pandera con modelos de marcos de datos tipificados. Comenzamos simulando datos transaccionales realistas e imperfectos y aplicamos progresivamente estrictas restricciones de esquema, reglas a nivel de columna y lógica empresarial entre columnas mediante comprobaciones declarativas. Mostramos cómo la validación diferida nos ayuda a detectar múltiples problemas de calidad de los datos a la vez, cómo los registros no válidos se pueden poner en cuarentena sin romper las canalizaciones y cómo la aplicación del esquema se puede aplicar directamente en los límites de las funciones para garantizar la corrección a medida que los datos fluyen a través de las transformaciones. Consulta los CÓDIGOS COMPLETOS aquí.

!pip -q install “pandera>=0.18” pandas numpy polars hipótesis de pyarrow importar json importar numpy como np importar pandas como pd importar pandera como pa de pandera.errors importar SchemaError, SchemaErrors de pandera.typing import Series, DataFrame print(“pandera version:”, pa.__version__) print(“pandas version:”, pd.__version__)

Configuramos el entorno de ejecución instalando Pandera y sus dependencias e importando todas las bibliotecas necesarias. Confirmamos las versiones de la biblioteca para garantizar la reproducibilidad y la compatibilidad. Establece una base limpia para hacer cumplir la validación de datos escritos a lo largo del tutorial. Consulta los CÓDIGOS COMPLETOS aquí.

rng = np.random.default_rng(42) def make_raw_orders(n=250): países = np.array([“CA”, “US”, “MX”]) canales = np.array([“web”, “mobile”, “partner”]) raw = pd.DataFrame( { “order_id”: rng.integers(1, 120, tamaño=n), “customer_id”: rng.integers(1, 90, tamaño=n), “correo electrónico”: rng.choice(
[“[email protected]”, “[email protected]”, “correo_electrónico incorrecto”, Ninguno]tamaño=n, p=[0.45, 0.45, 0.07, 0.03]), “país”: rng.choice(países, tamaño=n, p=[0.5, 0.45, 0.05]), “canal”: rng.choice(canales, tamaño=n, p=[0.55, 0.35, 0.10]), “artículos”: rng.integers(0, 8, tamaño=n), “precio unitario”: rng.normal(loc=35, escala=20, tamaño=n), “descuento”: rng.choice([0.0, 0.05, 0.10, 0.20, 0.50]talla=n,p=[0.55, 0.15, 0.15, 0.12, 0.03]), “ordered_at”: pd.to_datetime(“2025-01-01″) + pd.to_timedelta(rng.integers(0, 120, tamaño=n), unidad=”D”), } ) raw.loc[rng.choice(n, size=8, replace=False), “unit_price”] = -abs(crudo[“unit_price”].iloc[0]) crudo.loc[rng.choice(n, size=6, replace=False), “items”] = 0 crudo.loc[rng.choice(n, size=5, replace=False), “discount”] = 0,9 bruto.loc[rng.choice(n, size=4, replace=False), “country”] = “ZZ” crudo.loc[rng.choice(n, size=3, replace=False), “channel”] = “desconocido” raw.loc[rng.choice(n, size=6, replace=False), “unit_price”] = crudo[“unit_price”].iloc[:6].round(2).astype(str).values ​​devuelve raw_orders = make_raw_orders(250) display(raw_orders.head(10))

Generamos un conjunto de datos transaccionales realista que incluye intencionalmente problemas comunes de calidad de los datos. Simulamos valores no válidos, tipos inconsistentes y categorías inesperadas para reflejar escenarios de ingesta del mundo real. Nos permite probar y demostrar de manera significativa la efectividad de la validación basada en esquemas. Consulta los CÓDIGOS COMPLETOS aquí.

CORREO ELECTRÓNICO_RE = r”^[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}$” clase Pedidos(pa.DataFrameModel): order_id: Serie[int] = pa.Field(ge=1) customer_id: Serie[int] = pa.Field(ge=1) correo electrónico: Serie[object] = pa.Field(nullable=True) país: Serie[str] = pa.Campo(isin=[“CA”, “US”, “MX”]) canal: Serie[str] = pa.Campo(isin=[“web”, “mobile”, “partner”]) artículos: Serie[int] = pa.Field(ge=1, le=50) precio_unidad: Serie[float] = pa.Field(gt=0) descuento: Serie[float] = pa.Field(ge=0.0, le=0.8) ordenado_en: Serie[pd.Timestamp]

configuración de clase: coerce = Verdadero estricto = Verdadero ordenado = Falso @pa.check(“email”) def email_valid(cls, s: pd.Series) -> pd.Series: return s.isna() | s.astype(str).str.match(EMAIL_RE) @pa.dataframe_check def total_value_reasonable(cls, df: pd.DataFrame) -> pd.Series: total = df[“items”] * df[“unit_price”] * (1,0 – gl[“discount”]) devuelve total.between(0.01, 5000.0) @pa.dataframe_check def channel_country_rule(cls, df: pd.DataFrame) -> pd.Series: ok = ~((df[“channel”] == “socio”) & (df[“country”] == “MX”)) regresar ok

Definimos un estricto Pandera DataFrameModel que captura restricciones estructurales y de nivel empresarial. Aplicamos reglas a nivel de columna, validación basada en expresiones regulares y comprobaciones de todo el marco de datos para codificar de forma declarativa la lógica del dominio. Consulta los CÓDIGOS COMPLETOS aquí.

intente: validado = Orders.validate(raw_orders, lazy=True) print(validated.dtypes) excepto SchemaErrors como exc: display(exc.failure_cases.head(25)) err_json = exc.failure_cases.to_dict(orient=”records”) print(json.dumps(err_json)[:5]sangría=2, predeterminado=cadena))

Validamos el conjunto de datos sin procesar mediante una evaluación diferida para revelar múltiples infracciones en una sola pasada. Inspeccionamos casos de fallas estructuradas para comprender exactamente dónde y por qué los datos infringen las reglas del esquema. Nos ayuda a depurar problemas de calidad de los datos sin interrumpir todo el proceso. Consulta los CÓDIGOS COMPLETOS aquí.

def split_clean_quarantine(df: pd.DataFrame): intente: clean = Orders.validate(df, lazy=False) devuelve limpio, df.iloc[0:0].copy() excepto SchemaError: pase, intente: Orders.validate(df, lazy=True) devuelve df.copy(), df.iloc[0:0].copy() excepto SchemaErrors como exc: bad_idx = sorted(set(exc.failure_cases[“index”].dropna().astype(int).tolist())) cuarentena = df.loc[bad_idx].copy() clean = df.drop(index=bad_idx).copy() return Orders.validate(clean, lazy=False), cuarentena clean_orders, cuarentena_orders = split_clean_quarantine(raw_orders) display(quarantine_orders.head(10)) display(clean_orders.head(10)) @pa.check_types def enrich_orders(df: DataFrame[Orders]) -> Marco de datos[Orders]: salida = df.copy() salida[“unit_price”] = fuera[“unit_price”].redondear(2) hacia afuera[“discount”] = fuera[“discount”].round(2) devuelve enriquecido = enrich_orders(clean_orders) display(enriched.head(5))

Separamos los registros válidos de los no válidos poniendo en cuarentena las filas que no superan las comprobaciones de esquema. Luego aplicamos garantías de esquema en los límites de las funciones para garantizar que solo se transformen datos confiables. Este patrón permite el enriquecimiento seguro de los datos y al mismo tiempo previene la corrupción silenciosa. Consulta los CÓDIGOS COMPLETOS aquí.

clase EnrichedOrders(Pedidos): valor_total: Serie[float] = pa.Field(gt=0) configuración de clase: coerce = Verdadero estricto = Verdadero @pa.dataframe_check def totals_consistent(cls, df: pd.DataFrame) -> pd.Series: total = df[“items”] * df[“unit_price”] * (1,0 – gl[“discount”]) volver (df[“total_value”] – total).abs() <= 1e-6 @pa.check_types def add_totals(df: DataFrame[Orders]) -> Marco de datos[EnrichedOrders]: salida = df.copy() salida[“total_value”] = fuera[“items”] * afuera[“unit_price”] * (1.0 – fuera[“discount”]) devuelve EnrichedOrders.validate(out, lazy=False) enriched2 = add_totals(clean_orders) display(enriched2.head(5))

Ampliamos el esquema base con una columna derivada y validamos la coherencia entre columnas mediante esquemas que se pueden componer. Verificamos que los valores calculados obedecen a invariantes numéricos estrictos después de la transformación. Demuestra cómo Pandera respalda la ingeniería de funciones seguras con garantías exigibles.

En conclusión, establecimos un enfoque disciplinado para la validación de datos que trata los esquemas como contratos de primera clase en lugar de salvaguardas opcionales. Demostramos cómo la composición de esquemas nos permite ampliar de forma segura conjuntos de datos con características derivadas preservando al mismo tiempo las invariantes, y cómo Pandera se integra perfectamente en flujos de trabajo reales de ingeniería de datos y análisis. A través de este tutorial, nos aseguramos de que cada transformación opere con datos confiables, lo que nos permite crear canalizaciones que son transparentes, depurables y resistentes en entornos del mundo real.

Consulta los CÓDIGOS COMPLETOS aquí. Además, no dude en seguirnos en Twitter y no olvide unirse a nuestro SubReddit de más de 100.000 ML y suscribirse a nuestro boletín. ¡Esperar! estas en telegrama? Ahora también puedes unirte a nosotros en Telegram.