Validacion de datos en python

Por Jose R. Zapata

Ultima actualización: 23/May/2025

Invítame a un Café

Validación de Datos

La validación de datos es un proceso crucial en cualquier flujo de trabajo que involucre datos, especialmente en ciencia de datos y machine learning. Asegura que los datos con los que trabajamos sean precisos, consistentes, completos y cumplan con los requisitos esperados antes de ser utilizados para análisis, modelado o toma de decisiones.

En los proyectos de ciencia de datos, la validación de datos se convierte en un paso esencial para garantizar la calidad y fiabilidad de los resultados obtenidos. Ademas que permite detectar Data Drifts, que son cambios inesperados en la distribución de los datos que pueden afectar el rendimiento de los modelos.

La validación de datos no solo se limita a la verificación de errores obvios, sino que también implica la evaluación de la calidad de los datos, la identificación de patrones inusuales y la detección de anomalías. Esto es especialmente importante en el contexto de machine learning, donde los modelos dependen en gran medida de la calidad de los datos para hacer predicciones precisas.

La validación de datos es un proceso continuo que debe llevarse a cabo en todas las etapas del ciclo de vida de los datos, desde la recopilación hasta el análisis y la implementación de modelos. A medida que los datos evolucionan y cambian con el tiempo, es fundamental realizar revisiones periódicas para garantizar que sigan cumpliendo con los estándares de calidad establecidos.

¿Por qué es importante la validación de datos?

  • Calidad de los Datos (Data Quality): Garantiza que los datos sean fiables y útiles. Datos de mala calidad pueden llevar a conclusiones erróneas y modelos ineficaces.
  • Detección Temprana de Errores: Permite identificar y corregir problemas en los datos en etapas tempranas, evitando que se propaguen a procesos posteriores.
  • Consistencia: Asegura que los datos sigan un formato y estructura definidos, lo que facilita su procesamiento e integración.
  • Confianza en los Resultados: Al validar los datos, aumentamos la confianza en los análisis y modelos generados a partir de ellos.

Tipos comunes de validaciones:

  • Tipo de dato: Verificar que una columna contenga el tipo de dato esperado (e.g., entero, flotante, cadena, fecha).
  • Rango: Asegurar que los valores numéricos se encuentren dentro de un rango aceptable (e.g., edad entre 0 y 120).
  • Valores faltantes (Nulos): Comprobar si se permiten valores nulos y en qué medida.
  • Unicidad: Verificar que los valores en una columna sean únicos (e.g., IDs de usuario).
  • Pertenencia a un conjunto: Asegurar que los valores de una columna categórica pertenezcan a un conjunto predefinido de valores permitidos (e.g., “Masculino”, “Femenino”, “Otro”).
  • Expresiones regulares: Validar que las cadenas de texto cumplan con un patrón específico (e.g., formato de email, código postal).
  • Longitud: Comprobar la longitud de cadenas de texto o el número de dígitos.
  • Dependencias entre columnas: Validar relaciones entre diferentes columnas (e.g., si país es “España”, código_postal debe tener 5 dígitos).

A continuación, exploraremos dos bibliotecas populares de Python para la validación de datos: pandera y Great Expectations.

Validación de Datos con pandera

pandera es una biblioteca ligera y expresiva para la validación de datos en pandas DataFrames. Permite definir esquemas de validación de forma declarativa y fácil de entender.

Instalación:

pip install 'pandera[pandas]'

o con uv

uv add 'pandera[pandas]'

Ejemplo Básico:

Supongamos que tenemos un DataFrame con información de usuarios y queremos validar sus columnas.

Explicación del esquema pandera:

  • DataFrameSchema: Define el esquema para todo el DataFrame.
  • Column(dtype, checks...): Define las validaciones para una columna específica.
    • dtype: El tipo de dato esperado para la columna (e.g., int, str, float).
    • Check: Permite definir condiciones personalizadas.
      • Check.gt(0): El valor debe ser mayor que 0.
      • Check.in_range(min_value, max_value): El valor debe estar dentro del rango especificado.
      • Check.str_matches(pattern): La cadena debe coincidir con la expresión regular.
      • Check.isin(allowed_values): El valor debe pertenecer a la lista de valores permitidos.
    • unique=True: Todos los valores en la columna deben ser únicos.
    • required=True: La columna no puede faltar en el DataFrame.
    • nullable=False: La columna no puede contener valores nulos.

pandera es muy útil para integrar validaciones directamente en tus pipelines de datos de pandas, asegurando la calidad de los datos en cada paso.

import pandas as pd
import pandera.pandas as pa
from pandera import Column, Check, DataFrameSchema
from pandera.errors import SchemaError

# Datos de ejemplo
data = {
    "id_usuario": [1, 2, 3, 4, 5, 6],
    "edad": [25, 30, 22, 45, 28, 30],  # Corregido: 300 a 30
    "email": [
        "user1@example.com",
        "user2@example.com",
        "user3@example.com",
        "user4@example.com",
        "user5@example.com",
        "user6@example.com",
    ],  # Corregido: "user3" a "user3@example.com"
    "pais": ["España", "México", "España", "Argentina", "Chile", "Colombia"],
    "puntuacion": [4.5, 3.8, 5.0, 2.1, 4.9, 3.5],
}
df = pd.DataFrame(data)
df

id_usuarioedademailpaispuntuacion
0125user1@example.comEspaña4.5
1230user2@example.comMéxico3.8
2322user3@example.comEspaña5.0
3445user4@example.comArgentina2.1
4528user5@example.comChile4.9
5630user6@example.comColombia3.5

Ejemplo Esquema de validación

El propósito de este esquema es asegurar que los datos dentro del DataFrame cumplan a un conjunto específico de reglas y restricciones.

El esquema se construye como un objeto DataFrameSchema, que funciona como un diccionario. Las claves de este diccionario son los nombres de las columnas que se espera encontrar en el DataFrame, y los valores son objetos Column que detallan las reglas de validación para cada columna respectiva.

A continuación, se explican las reglas para cada columna definida en el esquema:

  • "id_usuario":

    • Tipo de dato: Se espera que todos los valores en esta columna sean de tipo entero (int).
    • Condición (Check.gt(0)): Cada valor debe ser estrictamente mayor que cero.
    • Unicidad (unique=True): Todos los valores en esta columna deben ser únicos. No se permiten identificadores de usuario duplicados.
    • Obligatoriedad (required=True): Esta columna es obligatoria y debe estar presente en el DataFrame.
  • "edad":

    • Tipo de dato: Se espera que los valores sean enteros (int).
    • Rango (Check.in_range(0, 120)): Cada valor de edad debe estar comprendido en el rango de 0 a 120, inclusive.
    • Nulos (nullable=False): No se permiten valores nulos (como NaN o None) en esta columna. Cada usuario debe tener una edad registrada.
  • "email":

    • Tipo de dato: Se espera que los valores sean cadenas de texto (str).
    • Formato (Check.str_matches(...)): Cada valor debe cumplir con un patrón de expresión regular específico: r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$". Esta expresión regular está diseñada para validar formatos comunes de direcciones de correo electrónico (por ejemplo, nombre@dominio.com).
    • Nulos (nullable=False): No se permiten valores nulos. Cada usuario debe tener una dirección de correo electrónico.
  • "pais":

    • Tipo de dato: Se espera que los valores sean cadenas de texto (str).
    • Valores permitidos (Check.isin([...])): Cada valor en esta columna debe ser uno de los siguientes: "España", "México", "Argentina", "Chile", "Colombia", o "Perú". Cualquier otro país no estará permitido.
  • "puntuacion":

    • Tipo de dato: Se espera que los valores sean números de punto flotante (float).
    • Rango (Check.in_range(0.0, 5.0)): Cada valor de puntuación debe estar en el rango de 0.0 a 5.0, inclusive.
    • Nulos (nullable=True): Se permiten valores nulos en esta columna. Esto significa que un usuario puede no tener una puntuación asignada.

Cuando este schema se utiliza para validar un DataFrame (por ejemplo, mediante schema.validate(df)), pandera revisará cada columna y sus datos contra estas reglas. Si alguna de las reglas no se cumple para algún dato, se generará un error (específicamente, una excepción SchemaError si no se usa lazy=True, o se recopilarán todos los errores si lazy=True está activado), detallando qué validaciones fallaron y para qué datos.

# Definición del esquema de validación con pandera
schema = DataFrameSchema({
    "id_usuario": Column(int, Check.gt(0), unique=True, required=True),
    "edad": Column(int, Check.in_range(0, 120), nullable=False),
    "email": Column(
        str, Check.str_matches(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"), nullable=False
    ),
    "pais": Column(str, Check.isin(["España", "México", "Argentina", "Chile", "Colombia", "Perú"])),
    "puntuacion": Column(float, Check.in_range(0.0, 5.0), nullable=True),
})

# Validar el DataFrame
try:
    validated_df = schema.validate(df, lazy=True)  # lazy=True para recolectar todos los errores
    print("DataFrame validado exitosamente:")
    print(validated_df)
except SchemaError as err:
    print("Errores de validación encontrados:")
    print(err.failure_cases)  # Muestra los datos que fallaron la validación
DataFrame validado exitosamente:
   id_usuario  edad              email       pais  puntuacion
0           1    25  user1@example.com     España         4.5
1           2    30  user2@example.com     México         3.8
2           3    22  user3@example.com     España         5.0
3           4    45  user4@example.com  Argentina         2.1
4           5    28  user5@example.com      Chile         4.9
5           6    30  user6@example.com   Colombia         3.5

Validación de Datos con Great Expectations

Great Expectations (GX) es una herramienta más completa y potente para la validación de datos. Permite definir “Expectativas” sobre los datos, generar documentación de calidad de datos y perfiles de datos. Es ideal para proyectos más grandes y para mantener la calidad de los datos a lo largo del tiempo.

Instalación:

pip install great-expectations

o con uv

uv add great-expectations

el principio de uso de Great Expectations es definir expectativas sobre los datos y luego validar si los datos cumplen con esas expectativas. Esto se hace a través de un proceso de “expectativa” que se puede aplicar a diferentes partes del flujo de trabajo de datos.

import great_expectations as gx

# usaremos el mismo DataFrame de ejemplo
df_gx_demo = pd.DataFrame(data)

# Crear un Validator directamente desde el DataFrame
# Esto es más simple que configurar un DataContext completo para validaciones rápidas.
validator = gx.from_pandas(df_gx_demo)

# Definir Expectativas directamente en el Validator
# Las expectativas devuelven un objeto de resultado, pero también se añaden al validador.

print("Definiendo expectativas y validando sobre la marcha:")

# Columna id_usuario
validator.expect_column_values_to_be_unique(column="id_usuario")
validator.expect_column_values_to_be_between(column="id_usuario", min_value=0)
validator.expect_column_values_to_not_be_null(column="id_usuario")

# Columna edad
# 'mostly=0.7' significa que la expectativa pasa si al menos el 70% de los valores cumplen.
# Con 2 de 7 valores fuera de rango (28.5% de error), 5/7 (71.4%) cumplen, por lo que debería pasar.
validator.expect_column_values_to_be_between(column="edad", min_value=0, max_value=120, mostly=0.7)
validator.expect_column_values_to_be_of_type(column="edad", type_="int")

# Columna email
validator.expect_column_values_to_match_regex(
    column="email", regex=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", mostly=0.7
)

# Columna pais
validator.expect_column_values_to_be_in_set(
    column="pais",
    value_set=["España", "México", "Argentina", "Chile", "Colombia", "Perú"],
    mostly=0.8,
)

# Columna puntuacion
# allow_cross_type_comparisons es útil si la columna puede tener tipos mixtos (ej. float y None)
validator.expect_column_values_to_be_between(
    column="puntuacion", min_value=0.0, max_value=5.0, allow_cross_type_comparisons=True, mostly=0.7
)
# Permitir algunos nulos para la columna puntuacion (1 de 7 es nulo ~14% nulos)
validator.expect_column_values_to_not_be_null(column="puntuacion", mostly=0.8)


# Validar los datos contra todas las expectativas añadidas al Validator
# El objeto `validator` ahora contiene la suite de expectativas implícita.
validation_result = validator.validate()

# Mostrar resultados de la validación
print("\nResultados de la Validación con Great Expectations (simplificado):")
print(f"Éxito general de la validación: {validation_result.success}")
print(f"Estadísticas: {validation_result.statistics}")
Definiendo expectativas y validando sobre la marcha:

Resultados de la Validación con Great Expectations (simplificado):
Éxito general de la validación: True
Estadísticas: {'evaluated_expectations': 9, 'successful_expectations': 9, 'unsuccessful_expectations': 0, 'success_percent': 100.0}

Explicación del ejemplo Great Expectations:

  • Definición de Expectativas: Se añaden expectativas a la suite usando métodos como:

    • expect_column_values_to_be_unique: Para unicidad.
    • expect_column_values_to_be_between: Para rangos numéricos. se puede solo especificar el rango inferior o superior.
    • expect_column_values_to_not_be_null: Para no nulos.
    • expect_column_values_to_be_between: Para rangos. El parámetro mostly permite un cierto porcentaje de fallos, útil para datos del mundo real.
    • expect_column_values_to_be_of_type: Para tipos de datos.
    • expect_column_values_to_match_regex: Para patrones de texto.
    • expect_column_values_to_be_in_set: Para valores categóricos permitidos.
  • Resultados: Los resultados indican si la validación general fue exitosa y proporcionan detalles sobre cada expectativa.

Great Expectations permite mas validaciones que pandera para configuraciones simples, pero es muy bueno para escenarios donde se necesita un versionado robusto de las expectativas, documentación automática y una gestión continua de la calidad de los datos en pipelines de producción.

Conclusión:

Tanto pandera como Great Expectations son herramientas valiosas para la validación de datos en Python.

  • pandera es ideal para validaciones rápidas, integración directa con pandas y cuando se prefiere una sintaxis más concisa y centrada en el código.
  • Great Expectations es más adecuado para sistemas de calidad de datos a gran escala, donde la documentación, el versionado de expectativas y la colaboración son importantes.

Referencias

Jose R. Zapata

Siguiente