📚 Documentación Completa

Guía Técnica de FLAI

Referencia completa de la API, guías de instalación, tutoriales paso a paso y mejores prácticas para implementar fairness en tus modelos de IA.

🚀 Instalación

Requisitos del Sistema

  • Python: >= 3.9 (recomendado 3.10+)
  • Memoria: Mínimo 4GB RAM
  • Espacio: ~500MB para dependencias

Instalación desde PyPI

# Versión más reciente (Python >= 3.9)
pip install flai-causal

# Para Python <= 3.9
pip install flai-causal==2.0.0

# Con dependencias opcionales para visualización
pip install flai-causal[viz]

Instalación desde GitHub

# Versión de desarrollo
pip install git+https://github.com/rugonzs/FLAI.git

# Versión específica
pip install git+https://github.com/rugonzs/FLAI.git@v3.0.4

Verificación de Instalación

import FLAI
from FLAI import data, causal_graph
print(f"FLAI instalado correctamente. Versión disponible.")

⚡ Inicio Rápido

import pandas as pd
from FLAI import data, causal_graph

# 1. Cargar y preparar datos
df = pd.read_csv('tu_dataset.csv')  # O usar pickle, parquet, etc.
flai_dataset = data.Data(df, transform=True)

# 2. Detectar sesgos con métrica bidimensional
df_fairness, datos_detalle = flai_dataset.fairness_eqa_eqi(
    features=['education', 'age'],      # Variables explicativas
    target_column='income',             # Variable objetivo
    column_filter=['gender'],           # Variable sensible
    plot=True                          # Visualizar resultados
)

print("📊 Métricas de Fairness:")
print(df_fairness)

# 3. Crear modelo causal
flai_graph = causal_graph.CausalGraph(
    flai_dataset, 
    target='income'
)

# 4. Mitigar sesgos
flai_graph.mitigate_edge_relation(sensible_feature=['gender'])
flai_graph.mitigate_calculation_cpd(sensible_feature=['gender'])

# 5. Generar datos justos
fair_data = flai_graph.generate_dataset(
    n_samples=1000, 
    methodtype='bayes'
)

# 6. Verificar mejora
df_fairness_new, _ = fair_data.fairness_eqa_eqi(
    features=['education', 'age'],
    target_column='income',
    column_filter=['gender'],
    plot=True
)

print("✅ Después de mitigación:")
print(df_fairness_new)

📊 Clase Data

La clase Data es el punto de entrada principal para el análisis de fairness. Encapsula un dataset y proporciona métodos para detectar y medir sesgos.

Constructor

Data(data=None, transform=True, verbose=0)
data
pandas.DataFrame, required

Dataset a analizar. Debe contener variables categóricas y numéricas.

transform
bool, default=True

Si True, transforma automáticamente variables categóricas a numéricas usando OrdinalEncoder.

verbose
int, default=0

Nivel de verbosidad (0=silencioso, 1=básico, 2=detallado).

# Cargar datos con transformación automática
import pandas as pd
from FLAI import data

df = pd.read_csv('adult.csv')
flai_dataset = data.Data(df, transform=True, verbose=1)

# Acceder a datos transformados
print(flai_dataset.data.head())
print(f"Forma del dataset: {flai_dataset.data.shape}")

# Ver mapeo de categorías originales
print("Mapeo de categorías:", flai_dataset.map_cat)

fairness_eqa_eqi()

🏆 Método principal: Calcula la métrica bidimensional EQA-EQI que distingue igualdad de equidad.

fairness_eqa_eqi(features, target_column, column_filter, plot=True)
features
list of str, required

Lista de columnas que representan características no sensibles (ej: ['education', 'age']).

target_column
str, required

Nombre de la columna objetivo/predicción a analizar.

column_filter
list of str, required

Lista de columnas sensibles para análisis de fairness (ej: ['gender', 'race']).

plot
bool, default=True

Si True, genera visualizaciones automáticas de las métricas.

🔄 Retorna

tuple: (df_fairness, datos_detalle)

  • df_fairness: DataFrame con métricas EQI, EQA y F para cada grupo
  • datos_detalle: DataFrame con análisis detallado por grupo y característica
# Ejemplo: Análisis de fairness por género
df_f, datos_f = flai_dataset.fairness_eqa_eqi(
    features=['education'],           # Variable explicativa
    target_column='income_high',      # Variable a predecir
    column_filter=['gender'],         # Variable sensible
    plot=True                        # Mostrar gráficos
)

print("📊 Resultados:")
print(df_f)
# Salida esperada:
#        group     reference   EQI    EQA     F
# 0  gender_0     gender_1   -0.04  0.08  0.09

# Interpretación:
# EQI = -0.04: Diferencia en oportunidades (negativo = grupo 0 desfavorecido)
# EQA = 0.08:  Diferencia en resultados generales  
# F = 0.09:    Unfairness global = √(EQA² + EQI²)

fairness_metrics()

Calcula métricas tradicionales de fairness para comparación con EQA-EQI.

fairness_metrics(target_column, predicted_column, columns_fair)
target_column
str, required

Columna con etiquetas verdaderas (ground truth).

predicted_column
str, required

Columna con predicciones del modelo.

columns_fair
dict, required

Diccionario especificando grupos privilegiados/no privilegiados.

# Métricas tradicionales para comparar
metrics = flai_dataset.fairness_metrics(
    target_column='true_label',
    predicted_column='predicted_label', 
    columns_fair={
        'gender': {'privileged': 1, 'unprivileged': 0},
        'age': {'privileged': 1, 'unprivileged': 0}
    }
)

# Obtener DataFrames organizados
df_performance, df_fairness = flai_dataset.get_df_metrics(metrics)

print("🎯 Métricas de Performance:")
print(df_performance[['ACC', 'TPR', 'FPR', 'PPP']])

print("⚖️ Métricas de Fairness:")
print(df_fairness[['EOD', 'DI', 'SPD', 'OD']])

🧠 Clase CausalGraph

La clase CausalGraph implementa redes bayesianas causales para modelar y mitigar sesgos algorítmicos.

Constructor

CausalGraph(flai_dataset, node_edge=None, CPD=None, indepence_test=True, root_node=None, target=None, verbose=0)
flai_dataset
FLAI.data.Data, required

Instancia de la clase Data con el dataset a modelar.

target
str, required

Variable objetivo del modelo causal.

node_edge
list of tuples, optional

Lista de aristas para construir el grafo manualmente. Si None, se aprende automáticamente.

indepence_test
bool, default=True

Si True, aplica test de independencia para validar aristas.

# Construcción automática del grafo
flai_graph = causal_graph.CausalGraph(
    flai_dataset=flai_dataset,
    target='income',
    verbose=1
)

# Visualizar el grafo
flai_graph.plot(directed=True)

# Ver las aristas aprendidas
print("🔗 Aristas del grafo:", flai_graph.graph['model_edges'])

# Construcción manual del grafo
manual_edges = [
    ('age', 'income'),
    ('education', 'income'),
    ('gender', 'education'),
    ('gender', 'income')
]

flai_graph_manual = causal_graph.CausalGraph(
    flai_dataset=flai_dataset,
    node_edge=manual_edges,
    target='income'
)

mitigate_edge_relation()

🛠️ Mitigación estructural: Modifica las relaciones causales para eliminar conexiones discriminatorias.

mitigate_edge_relation(sensible_feature)
sensible_feature
list of str, required

Lista de variables sensibles cuyas relaciones causales se van a mitigar.

🔄 Retorna

list: Lista de aristas del grafo mitigado

# Antes de la mitigación
print("📊 Aristas originales:")
print(flai_graph.graph['model_edges'])

# Mitigar relaciones de variables sensibles
mitigated_edges = flai_graph.mitigate_edge_relation(
    sensible_feature=['gender', 'age']
)

print("✅ Aristas después de mitigación:")
print(mitigated_edges)

# Visualizar cambios
flai_graph.plot(directed=True)

# Ejemplo de transformación:
# Antes: [('gender', 'income'), ('age', 'income'), ('education', 'income')]
# Después: [('education', 'income'), ('gender', 'education'), ('age', 'education')]
# Las variables sensibles ya no afectan directamente al resultado

mitigate_calculation_cpd()

📊 Mitigación probabilística: Ajusta las tablas de probabilidad condicional para reducir sesgos.

mitigate_calculation_cpd(sensible_feature, fix_proportion=True, verbose=0)
sensible_feature
list of str, required

Variables sensibles cuyas distribuciones se van a ajustar.

fix_proportion
bool, default=True

Si True, iguala las proporciones de variables sensibles.

# Aplicar mitigación probabilística
flai_graph.mitigate_calculation_cpd(
    sensible_feature=['gender', 'age'],
    fix_proportion=True,
    verbose=1
)

# Comparar probabilidades antes y después
print("📊 Inferencia antes de mitigación:")
original_inference = flai_graph.inference(
    variables=['gender', 'income'], 
    evidence={}
)
print(original_inference)

print("✅ Inferencia después de mitigación:")
# Ahora las probabilidades son iguales independientemente del género

generate_dataset()

🔄 Generación de datos justos: Crea datasets sintéticos libres de sesgo usando el modelo mitigado.

generate_dataset(n_samples=1000, methodtype='bayes', verbose=0)
n_samples
int, default=1000

Número de muestras a generar.

methodtype
str, default='bayes'

Método de muestreo ('bayes', 'rejection', etc.).

🔄 Retorna

FLAI.data.Data: Nueva instancia con datos sintéticos justos

# Generar datos justos
fair_data = flai_graph.generate_dataset(
    n_samples=5000,
    methodtype='bayes',
    verbose=1
)

print(f"📈 Dataset justo generado: {fair_data.data.shape}")
print(fair_data.data.head())

# Verificar que el sesgo se ha eliminado
df_fair, _ = fair_data.fairness_eqa_eqi(
    features=['education'],
    target_column='income',
    column_filter=['gender'],
    plot=True
)

print("✅ Métricas en datos justos:")
print(df_fair)
# Esperado: EQI ≈ 0, EQA ≈ 0, F ≈ 0

# Usar para entrenar nuevos modelos
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

X = fair_data.data.drop('income', axis=1)
y = fair_data.data['income']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
model = RandomForestClassifier()
model.fit(X_train, y_train)

inference()

🔮 Realiza inferencia bayesiana en el modelo causal.

inference(variables, evidence={}, verbose=0)
# Inferencia simple
result = flai_graph.inference(
    variables=['gender', 'income'],
    evidence={}
)
print("🔮 Probabilidades conjuntas:")
print(result)

# Inferencia condicional
result_conditional = flai_graph.inference(
    variables=['income'],
    evidence={'gender': 1, 'education': 3}
)
print("🎯 P(income | gender=1, education=3):")
print(result_conditional)

📚 Ejemplos Completos

🎯 Caso 1: Dataset Adult (Census Income)

# Pipeline completo para dataset Adult
import pandas as pd
from FLAI import data, causal_graph
import matplotlib.pyplot as plt

# 1. Cargar datos
df = pd.read_csv('adult.csv')
print(f"📊 Dataset cargado: {df.shape}")

# 2. Preparar con FLAI
flai_dataset = data.Data(df, transform=True)

# 3. Análisis inicial de fairness
print("🔍 Análisis inicial de sesgos...")
df_original, _ = flai_dataset.fairness_eqa_eqi(
    features=['education-num', 'age'],
    target_column='income',
    column_filter=['sex'],
    plot=True
)
print("📈 Fairness original:")
print(df_original)

# 4. Construir modelo causal
flai_graph = causal_graph.CausalGraph(
    flai_dataset, 
    target='income',
    verbose=1
)

# 5. Aplicar mitigación completa
print("🛠️ Aplicando mitigación...")
flai_graph.mitigate_edge_relation(sensible_feature=['sex', 'age'])
flai_graph.mitigate_calculation_cpd(sensible_feature=['sex', 'age'])

# 6. Generar datos justos
fair_data = flai_graph.generate_dataset(n_samples=2000)

# 7. Verificar mejora
df_mitigated, _ = fair_data.fairness_eqa_eqi(
    features=['education-num', 'age'],
    target_column='income',
    column_filter=['sex'],
    plot=True
)
print("✅ Fairness después de mitigación:")
print(df_mitigated)

# 8. Comparación visual
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))

# Plot original
original_values = df_original[['EQI', 'EQA', 'F']].values[0]
ax1.bar(['EQI', 'EQA', 'F'], original_values, color=['red', 'orange', 'darkred'])
ax1.set_title('Original Dataset')
ax1.set_ylabel('Unfairness Score')

# Plot mitigated  
mitigated_values = df_mitigated[['EQI', 'EQA', 'F']].values[0]
ax2.bar(['EQI', 'EQA', 'F'], mitigated_values, color=['green', 'lightgreen', 'darkgreen'])
ax2.set_title('After FLAI Mitigation')
ax2.set_ylabel('Unfairness Score')

plt.tight_layout()
plt.show()

print(f"🎯 Mejora en Fairness Global: {original_values[2]:.3f} → {mitigated_values[2]:.3f}")

⚖️ Caso 2: Dataset COMPAS (Recidivism)

# Análisis de algoritmos de justicia penal
import pandas as pd
from FLAI import data, causal_graph

# Cargar datos COMPAS
df_compas = pd.read_csv('compas-scores.csv')

# Preparar datos
flai_compas = data.Data(df_compas, transform=True)

# Análisis específico por raza
df_racial_bias, _ = flai_compas.fairness_eqa_eqi(
    features=['priors_count', 'age'],
    target_column='two_year_recid',
    column_filter=['race'],
    plot=True
)

print("⚖️ Sesgo racial en COMPAS:")
print(df_racial_bias)

# Construir modelo específico para justicia
compas_graph = causal_graph.CausalGraph(
    flai_compas,
    target='two_year_recid',
    verbose=1
)

# Mitigación enfocada en raza
compas_graph.mitigate_edge_relation(sensible_feature=['race'])
compas_graph.mitigate_calculation_cpd(sensible_feature=['race'])

# Evaluar impacto
fair_compas = compas_graph.generate_dataset(n_samples=1000)
df_compas_fair, _ = fair_compas.fairness_eqa_eqi(
    features=['priors_count', 'age'],
    target_column='two_year_recid', 
    column_filter=['race'],
    plot=True
)

print("✅ COMPAS después de mitigación:")
print(df_compas_fair)

✨ Mejores Prácticas

🎯 Preparación de Datos

  • Limpieza previa: Elimina valores faltantes y outliers antes de usar FLAI
  • Variables categóricas: Asegúrate de que estén bien codificadas (usa transform=True)
  • Tamaño mínimo: Datasets con al menos 1000 registros dan mejores resultados
  • Balance de clases: Verifica que no haya clases extremadamente desbalanceadas

📊 Interpretación de Métricas

# Guía de interpretación
def interpretar_fairness(df_fairness):
    """Interpreta automáticamente los resultados de fairness"""
    for _, row in df_fairness.iterrows():
        eqi, eqa, f = row['EQI'], row['EQA'], row['F']
        
        print(f"🔍 Grupo: {row['group']} vs {row['reference']}")
        
        # Interpretación EQI (Equidad)
        if abs(eqi) < 0.02:
            print("  ✅ EQI: Equidad excelente")
        elif abs(eqi) < 0.05:
            print("  ⚠️ EQI: Ligera inequidad")
        else:
            print("  ❌ EQI: Inequidad significativa")
            
        # Interpretación EQA (Igualdad)  
        if abs(eqa) < 0.02:
            print("  ✅ EQA: Igualdad excelente")
        elif abs(eqa) < 0.05:
            print("  ⚠️ EQA: Ligera desigualdad")
        else:
            print("  ❌ EQA: Desigualdad significativa")
            
        # Recomendación
        if f < 0.03:
            print("  🎯 Recomendación: Dataset justo, no necesita mitigación")
        elif f < 0.08:
            print("  🔧 Recomendación: Considerar mitigación ligera")
        else:
            print("  🚨 Recomendación: Mitigación urgente necesaria")
        print()

# Uso
interpretar_fairness(df_fairness)

🛠️ Estrategias de Mitigación

  • Mitigación suave: Para F entre 0.03-0.08, usa solo mitigate_calculation_cpd()
  • Mitigación completa: Para F > 0.08, combina ambos métodos
  • Validación cruzada: Siempre valida en datos de test independientes
  • Trade-offs: Monitorea accuracy vs fairness para encontrar el balance óptimo

🚀 Optimización de Performance

# Configuración para datasets grandes
import warnings
warnings.filterwarnings('ignore')  # Silenciar warnings no críticos

# Para datasets > 10K registros
flai_dataset = data.Data(
    large_df.sample(5000),  # Muestreo para acelerar
    transform=True,
    verbose=0  # Reducir output
)

# Construcción rápida de grafo
flai_graph = causal_graph.CausalGraph(
    flai_dataset,
    target='label',
    indepence_test=False,  # Omitir test para acelerar
    verbose=0
)

# Generación eficiente de datos
fair_data = flai_graph.generate_dataset(
    n_samples=min(1000, len(original_data)),  # Limitar tamaño
    methodtype='bayes'
)

⚠️ Limitaciones y Consideraciones

  • Causalidad vs Correlación: FLAI asume relaciones causales, valida con conocimiento del dominio
  • Variables proxy: Cuidado con variables que indirectamente codifican información sensible
  • Contexto legal: Siempre consulta regulaciones locales sobre fairness algorítmica
  • Validación humana: Los resultados deben ser validados por expertos en el dominio

📚 Recursos Adicionales