Calidad de Datos: Explicación Exhaustiva con Ejemplos Prácticos
Principio Fundamental: “Garbage In, Garbage Out” (GIGO)
El principio “Garbage In, Garbage Out” es un concepto fundamental en ciencia de datos que establece que la calidad de los resultados de cualquier análisis, modelo o sistema depende directamente de la calidad de los datos de entrada. Este principio, que tiene sus raíces en los primeros días de la computación, es más relevante que nunca en la era actual de inteligencia artificial y análisis de datos masivos.
Implicaciones del Principio GIGO
- Modelos de Machine Learning: Incluso los algoritmos más sofisticados producirán resultados incorrectos si se entrenan con datos de mala calidad
- Decisiones Empresariales: Las estrategias basadas en datos deficientes pueden llevar a pérdidas económicas significativas
- Cumplimiento Regulatorio: Los datos incorrectos pueden resultar en violaciones de normativas y sanciones
Dimensiones de Calidad de Datos
1. Completitud (Completeness)
La completitud mide si todos los datos necesarios están presentes y disponibles para el análisis. Se refiere a la ausencia de valores faltantes o nulos en el conjunto de datos.
Fórmula de Completitud:
Características:
- Evalúa la presencia de todos los atributos requeridos
- Distingue entre datos críticos y opcionales
- Impacta directamente en la validez del análisis
# Ejemplo de análisis de completitud
import pandas as pd
import numpy as np
# Dataset con valores faltantes
data = {
'nombre': ['Juan', 'María', None, 'Carlos', 'Ana'],
'edad': [25, 30, 35, None, 32],
'salario': [3000, 4500, 5500, 3800, None]
}
df = pd.DataFrame(data)
# Calcular completitud por columna
completitud = (1 - df.isnull().sum() / len(df)) * 100
print("Completitud por columna:")
print(completitud)
# Output:
# nombre 80.0%
# edad 80.0%
# salario 80.0%
2. Consistencia (Consistency)
La consistencia se refiere a la uniformidad de los datos a través de diferentes sistemas, bases de datos o puntos temporales. Los datos consistentes mantienen el mismo formato, estructura y representación en todos los lugares donde aparecen.
Tipos de Consistencia:
- Consistencia de valor: Los mismos datos tienen valores idénticos en diferentes sistemas
- Consistencia de formato: Mantener formatos uniformes (fechas, números, texto)
- Consistencia estructural: Preservar relaciones y estructuras de datos compatibles
# Ejemplo de problemas de consistencia
data_inconsistent = {
'ciudad': ['Madrid', 'MADRID', 'madrid', 'Barcelona', 'BARCELONA'],
'telefono': ['123-456-789', '123456789', '+34-123-456-789', '987654321', '987-654-321']
}
df_inconsistent = pd.DataFrame(data_inconsistent)
# Normalizar consistencia
df_inconsistent['ciudad'] = df_inconsistent['ciudad'].str.title()
print("Ciudades después de normalización:")
print(df_inconsistent['ciudad'].unique())
# Output: ['Madrid', 'Barcelona']
3. Precisión (Accuracy)
La precisión mide el grado en que los datos reflejan correctamente la realidad o una fuente verificable. Los datos precisos representan fielmente las entidades del mundo real que pretenden describir.
Formas de Verificar Precisión:
- Comparación con fuentes autoritativas
- Validación cruzada con sistemas externos
- Pruebas de veracidad (ej.: verificar números de teléfono)
# Ejemplo de detección de outliers (problemas de precisión)
import numpy as np
# Datos con outlier obvio
salarios = [3000, 4500, 5500, 3800, 4200, 300000] # 300000 es outlier
# Método IQR para detectar outliers
Q1 = np.percentile(salarios, 25)
Q3 = np.percentile(salarios, 75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = [x for x in salarios if x < lower_bound or x > upper_bound]
print(f"Outliers detectados: {outliers}")
# Output:
4. Validez (Validity)
La validez indica si los datos cumplen con las reglas de negocio, restricciones y formatos predefinidos. Los datos válidos se ajustan a los estándares y definiciones establecidos para cada campo.
Ejemplos de Reglas de Validez:
- Códigos postales con formato correcto
- Fechas dentro de rangos válidos
- Categorías pertenecientes a conjuntos predefinidos
# Ejemplo de validación de reglas de negocio
def validate_data(df):
validation_results = {}
# Validar códigos postales (5 dígitos)
if 'codigo_postal' in df.columns:
valid_cp = df['codigo_postal'].astype(str).str.match(r'^\d{5}$')
validation_results['codigo_postal'] = valid_cp.mean() * 100
# Validar categorías
if 'categoria' in df.columns:
valid_categories = ['A', 'B', 'C']
valid_cat = df['categoria'].isin(valid_categories)
validation_results['categoria'] = valid_cat.mean() * 100
return validation_results
# Ejemplo de uso
data_validation = {
'codigo_postal': ['28001', '08001', '123', 'ABCDE', '41001'],
'categoria': ['A', 'B', 'X', 'C', 'A']
}
df_val = pd.DataFrame(data_validation)
results = validate_data(df_val)
print("Resultados de validación:")
print(f"Códigos postales válidos: {results['codigo_postal']:.1f}%")
print(f"Categorías válidas: {results['categoria']:.1f}%")
5. Unicidad (Uniqueness)
La unicidad asegura que no existan registros duplicados cuando no deberían existir. Esta dimensión es crucial para mantener la integridad referencial y evitar distorsiones en los análisis.
# Ejemplo de detección y eliminación de duplicados
data_duplicates = {
'id': [1, 2, 3, 2, 4],
'nombre': ['Juan', 'María', 'Carlos', 'María', 'Ana'],
'email': ['juan@email.com', 'maria@email.com', 'carlos@email.com', 'maria@email.com', 'ana@email.com']
}
df_dup = pd.DataFrame(data_duplicates)
# Detectar duplicados
duplicados = df_dup.duplicated().sum()
print(f"Registros duplicados encontrados: {duplicados}")
# Eliminar duplicados manteniendo el primero
df_unique = df_dup.drop_duplicates()
print(f"Registros después de eliminar duplicados: {len(df_unique)}")
6. Oportunidad (Timeliness)
La oportunidad se refiere a si los datos están disponibles cuando se necesitan y si están actualizados. Los datos oportunos son aquellos que llegan en el momento correcto para la toma de decisiones.
# Ejemplo de análisis temporal
from datetime import datetime, timedelta
# Datos con timestamps
data_temporal = {
'evento': ['Venta A', 'Venta B', 'Venta C'],
'timestamp': ['2023-01-01 10:00:00', '2023-12-01 15:30:00', '2025-01-01 09:15:00']
}
df_temporal = pd.DataFrame(data_temporal)
df_temporal['timestamp'] = pd.to_datetime(df_temporal['timestamp'])
# Calcular antigüedad de los datos
now = datetime.now()
df_temporal['dias_antiguedad'] = (now - df_temporal['timestamp']).dt.days
print("Análisis de oportunidad:")
print(df_temporal[['evento', 'dias_antiguedad']])
# Identificar datos desactualizados (más de 365 días)
datos_desactualizados = df_temporal[df_temporal['dias_antiguedad'] > 365]
print(f"\nEventos con datos desactualizados: {len(datos_desactualizados)}")
Procesos de Limpieza de Datos
1. Tratamiento de Valores Ausentes
Los valores ausentes son uno de los problemas más comunes en la calidad de datos. Existen diferentes tipos de valores faltantes:
Tipos de Valores Faltantes:
- MCAR (Missing Completely at Random): Los valores faltantes son completamente aleatorios
- MAR (Missing at Random): Los valores faltantes están relacionados con otras variables observadas
- MNAR (Missing Not at Random): Los valores faltantes están relacionados con el valor faltante mismo
Técnicas de Imputación
a) Imputación por Media, Mediana y Moda:
# Imputación por diferentes estadísticos
from sklearn.impute import SimpleImputer
# Para variables numéricas
def impute_numerical(df, column, strategy='median'):
"""
Imputa valores faltantes en columnas numéricas
strategy: 'mean', 'median', 'most_frequent'
"""
if strategy == 'mean':
# Usar media para distribuciones normales
df[column].fillna(df[column].mean(), inplace=True)
elif strategy == 'median':
# Usar mediana para distribuciones sesgadas
df[column].fillna(df[column].median(), inplace=True)
return df
# Para variables categóricas
def impute_categorical(df, column):
"""Imputa valores faltantes con la moda"""
mode_value = df[column].mode().iloc if not df[column].mode().empty else 'Desconocido'
df[column].fillna(mode_value, inplace=True)
return df
# Ejemplo de aplicación
data_missing = {
'edad': [25, 30, np.nan, 28, np.nan],
'salario': [3000, 4500, 5500, np.nan, 4200],
'ciudad': ['Madrid', np.nan, 'Barcelona', 'Valencia', 'Madrid']
}
df_missing = pd.DataFrame(data_missing)
# Aplicar imputaciones
df_missing = impute_numerical(df_missing, 'edad', 'median')
df_missing = impute_numerical(df_missing, 'salario', 'mean')
df_missing = impute_categorical(df_missing, 'ciudad')
print("Datos después de imputación:")
print(df_missing)
b) Imputación KNN (K-Nearest Neighbors):
from sklearn.impute import KNNImputer
# KNN Imputation considera las relaciones entre variables
knn_imputer = KNNImputer(n_neighbors=3)
# Datos de ejemplo
data_knn = {
'edad': [25, 30, np.nan, 28, np.nan, 45],
'salario': [3000, 4500, 5500, np.nan, 4200, 6000],
'experiencia': [2, 5, 8, 3, np.nan, 15]
}
df_knn = pd.DataFrame(data_knn)
print("Antes de KNN imputation:")
print(df_knn)
# Aplicar KNN imputation
df_knn_imputed = pd.DataFrame(
knn_imputer.fit_transform(df_knn),
columns=df_knn.columns
)
print("\nDespués de KNN imputation:")
print(df_knn_imputed)
2. Tratamiento de Valores Extremos (Outliers)
Los outliers pueden afectar significativamente el rendimiento de los modelos y la validez de los análisis estadísticos.
Métodos de Detección de Outliers
a) Método IQR (Interquartile Range):
def detect_outliers_iqr(df, column):
"""Detecta outliers usando el método IQR"""
Q1 = df[column].quantile(0.25)
Q3 = df[column].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df[column] < lower_bound) | (df[column] > upper_bound)]
return outliers, lower_bound, upper_bound
# Ejemplo
data_outliers = {
'salario': [3000, 4500, 5500, 3800, 4200, 6000, 4800, 50000, 3500, 5200]
}
df_outliers = pd.DataFrame(data_outliers)
outliers, lower, upper = detect_outliers_iqr(df_outliers, 'salario')
print(f"Límites: [{lower:.0f}, {upper:.0f}]")
print(f"Outliers encontrados: {outliers['salario'].tolist()}")
b) Método Z-Score:
def detect_outliers_zscore(df, column, threshold=3):
"""Detecta outliers usando Z-score"""
z_scores = np.abs((df[column] - df[column].mean()) / df[column].std())
outliers = df[z_scores > threshold]
return outliers
outliers_zscore = detect_outliers_zscore(df_outliers, 'salario')
print(f"Outliers por Z-score: {outliers_zscore['salario'].tolist()}")
Técnicas de Tratamiento de Outliers
a) Eliminación:
# Eliminar outliers
df_no_outliers = df_outliers[~df_outliers.index.isin(outliers.index)]
print(f"Registros después de eliminar outliers: {len(df_no_outliers)}")
b) Transformación Logarítmica:
# Transformación logarítmica para reducir impacto de outliers
df_outliers['salario_log'] = np.log1p(df_outliers['salario'])
print("Datos originales vs transformados:")
print(df_outliers[['salario', 'salario_log']].head())
c) Capping (Limitación):
# Limitar valores extremos al percentil 95
percentil_95 = df_outliers['salario'].quantile(0.95)
df_outliers['salario_capped'] = df_outliers['salario'].clip(upper=percentil_95)
print(f"Valor máximo después de capping: {df_outliers['salario_capped'].max()}")
3. Normalización de Variables Categóricas
Label Encoding
from sklearn.preprocessing import LabelEncoder
# Para variables categóricas ordinales
le = LabelEncoder()
education_levels = ['Básico', 'Medio', 'Superior', 'Básico', 'Superior']
education_encoded = le.fit_transform(education_levels)
print("Mapeo de educación:")
for i, level in enumerate(le.classes_):
print(f"{level} -> {i}")
print(f"Valores codificados: {education_encoded}")
One-Hot Encoding
# Para variables categóricas nominales
colors = ['Rojo', 'Verde', 'Azul', 'Rojo', 'Verde']
colors_df = pd.DataFrame({'color': colors})
# Crear variables dummy
colors_encoded = pd.get_dummies(colors_df, prefix='color')
print("One-Hot Encoding:")
print(colors_encoded)
4. Escalamiento de Datos
El escalamiento de datos es crucial para que las variables con diferentes unidades y rangos tengan el mismo peso en los algoritmos de machine learning.
Min-Max Scaling (Normalización)
Escala los datos a un rango específico, típicamente :
from sklearn.preprocessing import MinMaxScaler
# Min-Max Scaling
scaler_minmax = MinMaxScaler()
data_numeric = [[25, 3000], [30, 4500], [35, 5500], [28, 3800]]
data_minmax = scaler_minmax.fit_transform(data_numeric)
print("Datos después de Min-Max Scaling:")
print(data_minmax)
Z-Score Standardization
Escala los datos para tener media 0 y desviación estándar 1:
from sklearn.preprocessing import StandardScaler
# Z-Score Standardization
scaler_zscore = StandardScaler()
data_zscore = scaler_zscore.fit_transform(data_numeric)
print("Datos después de Z-Score Standardization:")
print(data_zscore)
Comparación de Métodos de Escalamiento
| Aspecto | Min-Max Scaling | Z-Score Standardization |
|---|---|---|
| Fórmula | (x - min) / (max - min) | (x - mean) / std |
| Rango | o [-1, 1] | Media = 0, std = 1 |
| Sensible a outliers | Sí | No |
| Caso de uso | Datos acotados, redes neuronales | Datos con outliers, clustering |
| Distribución resultante | Mantiene distribución original | Distribución normal |
Implementación Práctica Completa
Métricas de Calidad de Datos
def calculate_quality_metrics(df):
"""Calcula métricas comprehensivas de calidad de datos"""
metrics = {}
# Completitud
completeness = (1 - df.isnull().sum() / len(df)) * 100
metrics['completeness'] = completeness.mean()
# Unicidad
duplicates = df.duplicated().sum()
metrics['uniqueness'] = (1 - duplicates / len(df)) * 100
# Consistencia (ejemplo para variables categóricas)
categorical_cols = df.select_dtypes(include=['object']).columns
consistency_scores = []
for col in categorical_cols:
if not df[col].empty:
# Medir variabilidad en formato
unique_formats = len(df[col].dropna().astype(str).str.len().unique())
consistency_score = 100 / unique_formats if unique_formats > 0 else 100
consistency_scores.append(consistency_score)
metrics['consistency'] = np.mean(consistency_scores) if consistency_scores else 100
return metrics
# Ejemplo de uso
sample_data = {
'id': [1, 2, 3, 4, 5],
'name': ['Juan', 'María', None, 'Carlos', 'Ana'],
'age': [25, 30, 35, 28, None],
'city': ['Madrid', 'madrid', 'MADRID', 'Barcelona', 'barcelona']
}
df_sample = pd.DataFrame(sample_data)
quality_metrics = calculate_quality_metrics(df_sample)
print("Métricas de Calidad:")
print(f"Completitud: {quality_metrics['completeness']:.2f}%")
print(f"Unicidad: {quality_metrics['uniqueness']:.2f}%")
print(f"Consistencia: {quality_metrics['consistency']:.2f}%")
Mejores Prácticas y Recomendaciones
1. Establecer un Pipeline de Calidad de Datos
class DataQualityPipeline:
def __init__(self):
self.steps = []
def add_step(self, step_name, step_function):
self.steps.append((step_name, step_function))
def process(self, df):
processed_df = df.copy()
quality_report = {}
for step_name, step_function in self.steps:
print(f"Ejecutando: {step_name}")
processed_df = step_function(processed_df)
# Calcular métricas después de cada paso
metrics = calculate_quality_metrics(processed_df)
quality_report[step_name] = metrics
return processed_df, quality_report
# Ejemplo de uso del pipeline
def remove_duplicates(df):
return df.drop_duplicates()
def fill_missing_values(df):
for col in df.select_dtypes(include=[np.number]).columns:
df[col].fillna(df[col].median(), inplace=True)
for col in df.select_dtypes(include=['object']).columns:
df[col].fillna(df[col].mode().iloc if not df[col].mode().empty else 'Unknown', inplace=True)
return df
def standardize_categorical(df):
for col in df.select_dtypes(include=['object']).columns:
df[col] = df[col].astype(str).str.strip().str.title()
return df
# Crear y ejecutar pipeline
pipeline = DataQualityPipeline()
pipeline.add_step("Eliminar Duplicados", remove_duplicates)
pipeline.add_step("Imputar Valores Faltantes", fill_missing_values)
pipeline.add_step("Estandarizar Categóricas", standardize_categorical)
clean_df, report = pipeline.process(df_sample)
print("\nReporte de Calidad:")
for step, metrics in report.items():
print(f"{step}: Completitud {metrics['completeness']:.1f}%")
2. Validación Continua
La calidad de los datos debe monitorearse continuamente. Implementar sistemas de alerta para detectar degradación en la calidad:
def monitor_data_quality(df, baseline_metrics, tolerance=5):
"""Monitorea la calidad de datos comparando con métricas base"""
current_metrics = calculate_quality_metrics(df)
alerts = []
for metric, current_value in current_metrics.items():
baseline_value = baseline_metrics.get(metric, current_value)
difference = abs(current_value - baseline_value)
if difference > tolerance:
alerts.append(f"ALERTA: {metric} ha cambiado {difference:.2f}% respecto a la línea base")
return alerts, current_metrics
# Ejemplo de monitoreo
baseline = {'completeness': 95.0, 'uniqueness': 100.0, 'consistency': 85.0}
alerts, current = monitor_data_quality(clean_df, baseline)
if alerts:
print("Alertas de Calidad:")
for alert in alerts:
print(f"- {alert}")
else:
print("✓ Calidad de datos dentro de los parámetros esperados")
Conclusión
La calidad de los datos es fundamental para el éxito de cualquier iniciativa de análisis de datos, machine learning o inteligencia artificial. Las seis dimensiones principales (completitud, consistencia, precisión, validez, unicidad y oportunidad) proporcionan un marco comprensivo para evaluar y mejorar la calidad de los datos.
Puntos Clave para Recordar:
- El principio GIGO es más relevante que nunca en la era de la IA
- La prevención es mejor que la corrección: implementar controles de calidad desde el origen
- La calidad es un proceso continuo, no un evento único
- Cada dimensión de calidad requiere técnicas específicas de medición y mejora
- La automatización de los procesos de limpieza mejora la eficiencia y consistencia
La implementación de un programa robusto de calidad de datos no solo mejora la precisión de los análisis, sino que también reduce costos, mejora la toma de decisiones y aumenta la confianza en los datos organizacionales. En un mundo cada vez más impulsado por datos, la calidad no es opcional: es un requisito fundamental para el éxito empresarial.
Hi :)
Matemáticas
Vectores
Álgebra Lineal
Geometría Analítica
Producto Punto
Espacios Vectoriales
Ortogonalidad
Normalización
Funciones
Álgebra
Composición de Funciones
Función Inversa
Combinación de Funciones
Transformaciones Gráficas
Aplicaciones Económicas
Interés Compuesto
Proporcionalidad
R
Data
Machine Learning
Aprendizaje Supervisado
Inteligencia Artificial
Clasificación
Regresión
Deep Learning