Salta al contenuto principale

Data Governance e Data Quality per AI Affidabile

Guida completa a Data Governance e Data Quality per AI Affidabile: architettura, implementazione pratica e best practices per developer e team tecnici.

Cosa ne pensi di questo articolo?

Data Governance e Data Quality per AI Affidabile
Data & AI BusinessFoto:RDNE Stock projectPexels

In Breve

Guida completa a Data Governance e Data Quality per AI Affidabile: architettura, implementazione pratica e best practices per developer e team tecnici.

Data Governance e Data Quality per AI Affidabile

Il 72% dei progetti AI aziendali fallisce prima di arrivare in produzione. Non per mancanza di algoritmi sofisticati, non per architetture inadeguate, non per talento mancante nel team. Falliscono per dati di qualità insufficiente, per assenza di governance, per pipeline che producono silenziosamente risultati errati senza che nessuno se ne accorga.

In un contesto in cui l'AI Act EU impone per la prima volta requisiti legali sulla qualità dei dati di addestramento per i sistemi ad alto rischio, e in cui le PMI italiane stanno investendo sempre più in progetti data-driven grazie al PNRR Transizione 5.0, costruire una fondazione solida di data governance e data quality non e più una scelta: e un prerequisito per competere e per restare conformi.

Questo articolo ti guida attraverso i framework operativi, gli strumenti open source e le implementazioni pratiche che consentono di costruire sistemi AI affidabili: dalla definizione delle dimensioni di qualità dei dati, all'implementazione di test automatici con Great Expectations e dbt, fino alla gestione della data lineage con OpenMetadata e alla compliance con l'AI Act.

Cosa Imparerai in Questo Articolo

  • Le 6 dimensioni DAMA di data quality e come misurarle in modo automatizzato
  • Implementazione di data quality checks con Great Expectations e dbt-expectations
  • Data catalog e data lineage con OpenMetadata e Apache Atlas
  • Data governance framework: ruoli, processi e struttura organizzativa
  • Requisiti AI Act EU (Articolo 10) per i dati di addestramento: cosa fare prima di agosto 2026
  • Data observability con Soda Core e Monte Carlo per pipeline in produzione
  • Bias detection nei dataset ML e strategie di mitigazione
  • Case study: framework di data governance per una PMI manifatturiera italiana

La Serie Data Warehouse, AI e Trasformazione Digitale

# Articolo Focus
1Evoluzione del Data WarehouseDa SQL Server a Data Lakehouse
2Data Mesh e Architettura DecentralizzataDomain ownership dei dati
3ETL vs ELT Modernodbt, Airbyte e Fivetran
4Orchestrazione PipelineAirflow, Dagster e Prefect
5AI nella ManifatturaPredictive Maintenance e Digital Twin
6AI nel FinanceFraud Detection e Credit Scoring
7AI nel RetailDemand Forecasting e Recommendation
8AI in HealthcareDiagnostica e Drug Discovery
9AI nella LogisticaRoute Optimization e Warehouse Automation
10LLM in AziendaRAG Enterprise e Guardrails
11Vector Database Enterprisepgvector, Pinecone e Weaviate
12MLOps per BusinessModelli AI in Produzione con MLflow
13Sei qui - Data GovernanceData Quality per AI Affidabile
14Roadmap Data-Driven per PMICome adottare AI e DWH

Il Problema della qualità dei Dati nell'Era AI

"Garbage in, garbage out" e un principio che i data engineer conoscono da decenni, ma con l'AI generativa e i modelli di machine learning in produzione, le conseguenze di dati scadenti sono diventate esponenzialmente più gravi. Un modello di fraud detection addestrato su dati sbilanciati genera falsi positivi che bloccano transazioni legittime. Un sistema di raccomandazione addestrato su dati con bias demografici amplifica le discriminazioni. Un modello di previsione della domanda addestrato su dati inconsistenti genera ordini errati con impatto diretto sul cash flow.

Il Costo dei Dati di Scarsa qualità - Dati 2025

Indicatore Valore Fonte
Costo medio per azienda (dati scarsa qualità) $12.9 milioni/anno Gartner 2024
Progetti AI che falliscono per qualità dati 72% McKinsey 2025
Tempo data scientist su data cleaning 45-60% Multiple surveys
PMI italiane con programma data quality formale 18% Osservatorio AI Polimi 2025
Riduzione errori ML con data governance fino al 35% IBM Institute 2025

La distinzione fondamentale che molte organizzazioni non colgono e la differenza tra data quality per analytics e data quality per AI. Nel reporting tradizionale, un dato anomalo produce un numero sbagliato su un dashboard - qualcuno lo nota, lo corregge, si va avanti. Nel machine learning, un dato anomalo nel training set contamina silenziosamente il modello, che poi si comporta in modo errato in produzione per mesi prima che il problema venga identificato. La latenza tra il problema e la sua manifestazione e infinitamente più alta.

Le 6 Dimensioni DAMA della Data Quality

Il framework DAMA-DMBOK (Data Management Body of Knowledge) definisce 6 dimensioni fondamentali di qualità dei dati, che nel 2025 rimangono il riferimento standard per qualsiasi programma di data quality enterprise:

Dimensioni DAMA per AI - Framework Esteso

Dimensione Definizione Metrica AI-Specifica Soglia Critica
Accuracy I dati rappresentano correttamente la realta % label corrette nel training set >99% per classificazione critica
Completeness Tutti i dati necessari sono presenti % valori non-null per feature critiche >95% per feature di input
Consistency I dati sono uniformi tra sistemi diversi % record concordanti tra sorgenti >98% per feature condivise
Timeliness I dati sono aggiornati e disponibili quando servono Lag medio dati di produzione vs training <24h per modelli real-time
Validity I dati rispettano formati e vincoli definiti % violazioni di schema e range <0.1% violazioni
Uniqueness Assenza di duplicati non intenzionali % record duplicati nel training set <0.5% duplicati

Implementazione Pratica: Data Quality con Great Expectations

Great Expectations e il framework open source Python più diffuso per i test di data quality. L'approccio e simile ai unit test per il codice: si definiscono "expectations" (aspettative) sui dati, si eseguono automaticamente nella pipeline, e si genera documentazione automatica. L'integrazione con Airflow, Prefect e dbt lo rende un componente naturale di qualsiasi data stack moderno.

# data_quality_pipeline.py
# Framework completo di data quality con Great Expectations

import great_expectations as gx
from great_expectations.core.batch import RuntimeBatchRequest
import pandas as pd
import numpy as np
from datetime import datetime
import logging

logger = logging.getLogger(__name__)

class DataQualityFramework:
    """
    Framework di data quality per pipeline ML enterprise.
    Implementa le 6 dimensioni DAMA con Great Expectations.
    """

    def __init__(self, datasource_name: str = "ml_training_data"):
        self.context = gx.get_context()
        self.datasource_name = datasource_name
        self.validation_results = {}

    def build_expectation_suite_for_ml(
        self,
        suite_name: str,
        target_column: str,
        feature_columns: list[str]
    ):
        """
        Crea una suite di expectations per dataset ML.
        Copre tutte le 6 dimensioni DAMA.
        """
        suite = self.context.add_expectation_suite(
            expectation_suite_name=suite_name
        )

        # === DIMENSIONE: COMPLETENESS ===
        # Feature critiche devono avere meno del 5% di valori nulli
        for col in feature_columns:
            suite.add_expectation(
                gx.core.ExpectationConfiguration(
                    expectation_type="expect_column_values_to_not_be_null",
                    kwargs={
                        "column": col,
                        "mostly": 0.95  # 95% non-null
                    }
                )
            )

        # Target column deve essere 100% non-null
        suite.add_expectation(
            gx.core.ExpectationConfiguration(
                expectation_type="expect_column_values_to_not_be_null",
                kwargs={"column": target_column}
            )
        )

        # === DIMENSIONE: VALIDITY ===
        # Valori numerici in range atteso (es. eta 0-120)
        suite.add_expectation(
            gx.core.ExpectationConfiguration(
                expectation_type="expect_column_values_to_be_between",
                kwargs={
                    "column": "customer_age",
                    "min_value": 18,
                    "max_value": 120,
                    "mostly": 0.999
                }
            )
        )

        # === DIMENSIONE: UNIQUENESS ===
        # Chiavi primarie devono essere uniche
        suite.add_expectation(
            gx.core.ExpectationConfiguration(
                expectation_type="expect_column_values_to_be_unique",
                kwargs={"column": "transaction_id"}
            )
        )

        # === DIMENSIONE: CONSISTENCY ===
        # Il target deve avere solo valori attesi (no label noise)
        suite.add_expectation(
            gx.core.ExpectationConfiguration(
                expectation_type="expect_column_values_to_be_in_set",
                kwargs={
                    "column": target_column,
                    "value_set": [0, 1],  # Classificazione binaria
                }
            )
        )

        # === DIMENSIONE: ACCURACY - Distribuzione statistica ===
        # La distribuzione non deve essere degenere
        suite.add_expectation(
            gx.core.ExpectationConfiguration(
                expectation_type="expect_column_proportion_of_unique_values_to_be_between",
                kwargs={
                    "column": "customer_id",
                    "min_value": 0.3,   # Almeno 30% utenti unici
                    "max_value": 1.0
                }
            )
        )

        # Bilanciamento classi per training set (max 10:1 ratio)
        suite.add_expectation(
            gx.core.ExpectationConfiguration(
                expectation_type="expect_column_most_common_value_to_be_in_set",
                kwargs={
                    "column": target_column,
                    "value_set": [0, 1],
                    "ties_okay": True
                }
            )
        )

        # === DIMENSIONE: TIMELINESS ===
        # Dati non più vecchi di 90 giorni
        suite.add_expectation(
            gx.core.ExpectationConfiguration(
                expectation_type="expect_column_values_to_be_between",
                kwargs={
                    "column": "event_timestamp",
                    "min_value": "2024-11-01",  # Rolling window
                    "max_value": datetime.now().strftime("%Y-%m-%d"),
                    "parse_strings_as_datetimes": True,
                    "mostly": 0.99
                }
            )
        )

        self.context.save_expectation_suite(suite)
        logger.info(f"Suite {suite_name} creata con {len(suite.expectations)} expectations")
        return suite

    def validate_dataset(
        self,
        df: pd.DataFrame,
        suite_name: str,
        run_name: str = None
    ) -> dict:
        """
        Valida un DataFrame contro la suite definita.
        Restituisce risultati strutturati per monitoring.
        """
        run_name = run_name or f"run_{datetime.now().isoformat()}"

        batch_request = RuntimeBatchRequest(
            datasource_name=self.datasource_name,
            data_connector_name="runtime_connector",
            data_asset_name="training_data",
            runtime_parameters={"batch_data": df},
            batch_identifiers={"run_id": run_name}
        )

        checkpoint = self.context.add_or_update_checkpoint(
            name="ml_data_checkpoint",
            validations=[
                {
                    "batch_request": batch_request,
                    "expectation_suite_name": suite_name
                }
            ]
        )

        results = checkpoint.run(run_name=run_name)

        # Estrai metriche aggregate
        validation_result = results.list_validation_results()[0]
        stats = validation_result.statistics

        quality_report = {
            "run_name": run_name,
            "timestamp": datetime.now().isoformat(),
            "success": results.success,
            "evaluated_expectations": stats["evaluated_expectations"],
            "successful_expectations": stats["successful_expectations"],
            "unsuccessful_expectations": stats["unsuccessful_expectations"],
            "success_rate": stats["success_percent"] / 100,
            "failed_checks": [
                {
                    "expectation": r.expectation_config.expectation_type,
                    "column": r.expectation_config.kwargs.get("column"),
                    "details": r.result
                }
                for r in validation_result.results
                if not r.success
            ]
        }

        self.validation_results[run_name] = quality_report
        return quality_report


# Utilizzo nella pipeline
def run_data_quality_checks(raw_data_path: str):
    framework = DataQualityFramework()

    # Definisci le expectations per il dataset
    framework.build_expectation_suite_for_ml(
        suite_name="ml_training_v1",
        target_column="churn_label",
        feature_columns=["customer_age", "tenure_months", "monthly_charges",
                        "total_charges", "contract_type", "payment_method"]
    )

    # Carica e valida i dati
    df = pd.read_parquet(raw_data_path)
    report = framework.validate_dataset(df, "ml_training_v1")

    if not report["success"]:
        failed = report["unsuccessful_expectations"]
        logger.error(f"Data quality FALLITA: {failed} check falliti su {report['evaluated_expectations']}")
        for check in report["failed_checks"]:
            logger.error(f"  - {check['expectation']} su colonna '{check['column']}'")
        raise DataQualityError(f"Dataset non conforme agli standard di qualità")

    logger.info(f"Data quality OK: {report['success_rate']:.1%} success rate")
    return report

Data Quality con dbt: Test Dichiarativi nella Pipeline di Trasformazione

Per i team che usano dbt come layer di trasformazione, il pacchetto dbt-expectations porta le stesse capabilities di Great Expectations direttamente nei modelli dbt, definendo i test in YAML vicino al codice SQL. Questo approccio "quality as code" garantisce che ogni trasformazione venga validata automaticamente.

# models/schema.yml
# Test di data quality con dbt-expectations

version: 2

models:
  - name: ml_features_customer
    description: "Feature store per modello churn prediction"
    columns:
      - name: customer_id
        description: "Identificativo univoco cliente"
        tests:
          - unique
          - not_null
          - dbt_expectations.expect_column_values_to_be_of_type:
              column_type: VARCHAR

      - name: customer_age
        description: "Eta del cliente in anni"
        tests:
          - not_null
          - dbt_expectations.expect_column_values_to_be_between:
              min_value: 18
              max_value: 120
              mostly: 0.999

      - name: monthly_charges
        description: "Addebiti mensili in EUR"
        tests:
          - not_null
          - dbt_expectations.expect_column_values_to_be_between:
              min_value: 0
              max_value: 10000
          - dbt_expectations.expect_column_mean_to_be_between:
              min_value: 50
              max_value: 200

      - name: churn_label
        description: "Label target: 1=churned, 0=retained"
        tests:
          - not_null
          - accepted_values:
              values: [0, 1]
          # Verifica che il dataset non sia troppo sbilanciato
          - dbt_expectations.expect_column_proportion_of_unique_values_to_be_between:
              min_value: 0.01  # Almeno 1% di churn (altrimenti dataset anomalo)
              max_value: 0.5   # Max 50% di churn (dataset equilibrato)

      - name: event_date
        description: "Data dell'evento"
        tests:
          - not_null
          - dbt_expectations.expect_column_values_to_be_between:
              min_value: "2023-01-01"
              max_value: "{{ var('max_date', modules.datetime.date.today().isoformat()) }}"
              parse_strings_as_datetimes: true

  - name: ml_features_customer
    tests:
      # Test a livello di tabella: volumetria attesa
      - dbt_expectations.expect_table_row_count_to_be_between:
          min_value: 10000
          max_value: 10000000

      # Nessuna riga duplicata su chiave composta
      - dbt_expectations.expect_compound_columns_to_be_unique:
          column_list: ["customer_id", "snapshot_date"]

Data Catalog e Data Lineage con OpenMetadata

La data lineage - la capacità di tracciare il percorso di un dato dalla sorgente fino al modello AI finale - e diventata un requisito imprescindibile per due ragioni convergenti: la compliance con l'AI Act EU (che richiede documentazione dell'origine dei dati di addestramento) e la necessità pratica di debugging quando un modello produce risultati inaspettati.

OpenMetadata e la piattaforma open source più avanzata per data catalog e lineage nel 2025, costruita da ex-ingegneri di Uber e fondatori di Apache Hadoop. Supporta lineage a livello di colonna, integrazione nativa con dbt, Airflow, Spark e i principali data warehouse.

# openmetadata_lineage.py
# Registrazione automatica della data lineage per pipeline ML

from metadata.ingestion.api.workflow import Workflow
from metadata.generated.schema.entity.data.pipeline import Pipeline
from metadata.generated.schema.entity.data.table import Table
from metadata.generated.schema.type.entityLineage import (
    ColumnLineage,
    EntitiesEdge,
    LineageDetails
)
from metadata.generated.schema.api.lineage.addLineage import AddLineageRequest
from metadata.ingestion.ometa.ometa_api import OpenMetadata
from metadata.generated.schema.security.client.openMetadataJWTClientConfig import (
    OpenMetadataJWTClientConfig
)
import json
from typing import Optional


class MLPipelineLineageTracker:
    """
    Tracker automatico di data lineage per pipeline ML.
    Registra ogni trasformazione in OpenMetadata.
    """

    def __init__(self, server_url: str, jwt_token: str):
        from metadata.generated.schema.entity.services.connections.metadata.openMetadataConnection import (
            OpenMetadataConnection
        )
        server_config = OpenMetadataConnection(
            hostPort=server_url,
            authProvider="openmetadata",
            securityConfig=OpenMetadataJWTClientConfig(jwtToken=jwt_token)
        )
        self.metadata = OpenMetadata(server_config)

    def register_training_data_lineage(
        self,
        source_tables: list[str],
        feature_store_table: str,
        ml_model_name: str,
        transformation_description: str
    ):
        """
        Registra il percorso: raw_data -> feature_store -> ml_model
        Essenziale per compliance AI Act (Art. 10 - Data Governance)
        """

        # 1. Recupera entità sorgente
        source_entities = []
        for table_fqn in source_tables:
            table = self.metadata.get_by_name(
                entity=Table,
                fqn=table_fqn
            )
            if table:
                source_entities.append(table)

        # 2. Recupera/crea feature store table
        feature_table = self.metadata.get_by_name(
            entity=Table,
            fqn=feature_store_table
        )

        # 3. Costruisci lineage con dettagli di trasformazione
        for source in source_entities:
            lineage_request = AddLineageRequest(
                edge=EntitiesEdge(
                    fromEntity={
                        "id": str(source.id.__root__),
                        "type": "table"
                    },
                    toEntity={
                        "id": str(feature_table.id.__root__),
                        "type": "table"
                    },
                    lineageDetails=LineageDetails(
                        description=transformation_description,
                        columnsLineage=[
                            ColumnLineage(
                                fromColumns=[f"{source.fullyQualifiedName.__root__}.customer_id"],
                                toColumn=f"{feature_store_table}.customer_id"
                            ),
                            ColumnLineage(
                                fromColumns=[f"{source.fullyQualifiedName.__root__}.event_date"],
                                toColumn=f"{feature_store_table}.snapshot_date"
                            )
                        ]
                    )
                )
            )
            self.metadata.add_lineage(lineage_request)

        # 4. Aggiungi tag di compliance (AI Act)
        self._tag_for_ai_act_compliance(feature_store_table, ml_model_name)

    def _tag_for_ai_act_compliance(
        self,
        table_fqn: str,
        model_name: str
    ):
        """
        Aggiunge tag AI Act per tracciabilita compliance.
        Essenziale per sistemi high-risk (AI Act Art. 10).
        """
        table = self.metadata.get_by_name(entity=Table, fqn=table_fqn)

        # Tag strutturati per AI Act
        compliance_tags = {
            "ai_act_article_10": "training_data",
            "ai_system": model_name,
            "data_governance_reviewed": "true",
            "bias_assessment_date": "2025-01-15",
            "data_quality_score": "98.5"
        }

        # Aggiorna custom properties
        self.metadata.patch_entity(
            entity=Table,
            source=table,
            destination=table.copy(
                update={"customMetrics": compliance_tags}
            )
        )

        print(f"Compliance tags aggiunti per {table_fqn} -> modello {model_name}")


# Utilizzo pratico
def setup_ml_lineage():
    tracker = MLPipelineLineageTracker(
        server_url="http://openmetadata.internal:8585/api",
        jwt_token="your-jwt-token"
    )

    tracker.register_training_data_lineage(
        source_tables=[
            "default.raw_crm.customers",
            "default.raw_billing.transactions",
            "default.raw_support.tickets"
        ],
        feature_store_table="default.feature_store.ml_churn_features_v3",
        ml_model_name="churn_prediction_xgboost_v2",
        transformation_description="Feature engineering per churn prediction: "
                                   "aggregazioni mensili, calcolo tenure, "
                                   "encoding categoriche. Approvato data steward 2025-01-15."
    )

Data Governance Framework: Struttura Organizzativa e Processi

La data governance non e uno strumento software: e un sistema di persone, processi e tecnologie che garantisce che i dati siano gestiti come un asset strategico. Per le PMI italiane che si avvicinano all'AI, costruire questa struttura in modo pragmatico e essenziale.

I Ruoli Chiave della Data Governance

Struttura di Governance per PMI (50-500 dipendenti)

Ruolo Responsabilità FTE Stimato Profilo
Chief Data Officer (CDO) Strategia dati, sponsor esecutivo, budget, compliance AI Act 0.25 FTE (parziale) C-level o manager senior
Data Steward Ownership dominio dati, definizione standard, approvazione modifiche 1 per dominio dati Business + tecnica
Data Engineer Pipeline, qualità tecnica, strumenti di monitoring 1-2 FTE Profilo tecnico
Data Quality Analyst Definizione KPI qualità, audit, reportistica 0.5 FTE Analitico/ibrido
DPO (Data Protection Officer) GDPR, AI Act, sicurezza dati, privacy by design 0.25-0.5 FTE Legale/tecnica

Data Governance Policy: I 5 Processi Fondamentali

Un programma di data governance operativo si basa su 5 processi ricorrenti che devono essere documentati, assegnati e monitorati:

  • Data Classification: Ogni dataset classificato per sensibilita (pubblico, interno, confidenziale, segreto) e per tipo (PII, dati finanziari, dati operativi, dati di training ML). Questa classificazione determina i controlli di accesso, la retention policy e i requisiti di qualità applicabili.
  • Data Quality SLA: Per ogni dataset critico, definizione formale di SLA di qualità: completeness > 98%, latency < 2h, accuracy validata trimestralmente. Gli SLA devono essere misurabili e monitorati automaticamente.
  • Change Management: Processo formale per modifiche agli schema dei dati critici. Nessuna modifica senza impatto assessment, test di regression e approvazione del data steward di dominio.
  • Data Access Management: Principio del minimo privilegio applicato ai dati. Accesso ai dati di training ML limitato al team ML con audit log completo. Review trimestrale degli accessi.
  • Incident Response: Procedura di escalation per data quality incidents: rilevamento automatico (alerting), triage (<4h), remediation, post-mortem e aggiornamento dei check automatici.

AI Act EU e Requisiti per i Dati di Training

L'AI Act EU introduce per la prima volta nella storia requisiti legalmente vincolanti sulla qualità dei dati di addestramento per i sistemi AI ad alto rischio. L'Articolo 10 del regolamento e specificamente dedicato a "Data and Data Governance" ed e diventato operativo per i GPAI models dal 2 agosto 2025. Per i sistemi high-risk, la piena compliance e richiesta entro il 2 agosto 2026.

Timeline AI Act EU - Cosa Fare Prima di Agosto 2026

Data Milestone Azione Richiesta
Feb 2025 Pratiche AI vietate operative Audit dei sistemi AI per pratiche proibite
Ago 2025 GPAI models e governance operativi Governance per LLM e modelli fondazionali
Ago 2026 High-risk AI systems full compliance Data governance Art. 10 completamente implementata
Ago 2027 Legacy systems compliance Sistemi AI esistenti adeguati

Articolo 10 AI Act: Requisiti Tecnici per i Dati

L'Articolo 10 dell'AI Act impone requisiti specifici per i dataset usati nell'addestramento, validazione e test dei sistemi AI ad alto rischio. Ecco cosa deve essere documentato e implementato concretamente:

# ai_act_compliance_checker.py
# Verifica compliance AI Act Art. 10 per dataset di training

from dataclasses import dataclass, field
from typing import Optional
import pandas as pd
import numpy as np
from scipy import stats
import json
from datetime import datetime


@dataclass
class DatasetComplianceReport:
    """Report di compliance AI Act Articolo 10."""
    dataset_name: str
    assessment_date: str
    assessor: str
    compliant: bool = False
    checks: dict = field(default_factory=dict)
    recommendations: list = field(default_factory=list)


class AIActArticle10Checker:
    """
    Verifica conformità AI Act Art. 10 per dataset di training high-risk.

    Art. 10 richiede che i dataset siano:
    1. Rilevanti e sufficientemente rappresentativi
    2. Liberi da errori per quanto possibile
    3. Completi rispetto allo scopo
    4. Con proprietà statistiche appropriate
    5. Privi di bias che potrebbero discriminare gruppi protetti
    """

    def __init__(self, dataset_name: str, assessor: str):
        self.report = DatasetComplianceReport(
            dataset_name=dataset_name,
            assessment_date=datetime.now().isoformat(),
            assessor=assessor
        )

    def check_representativeness(
        self,
        df: pd.DataFrame,
        demographic_columns: list[str],
        reference_distributions: dict
    ) -> bool:
        """
        Art. 10(3): Verifica rappresentativita demografica.
        Confronta distribuzione del dataset con popolazione di riferimento.
        """
        is_representative = True
        self.report.checks["representativeness"] = {}

        for col in demographic_columns:
            if col not in df.columns:
                continue

            # Distribuzione nel dataset
            observed = df[col].value_counts(normalize=True).to_dict()

            # Distribuzione attesa (es. ISTAT per demografia italiana)
            expected = reference_distributions.get(col, {})

            if not expected:
                continue

            # Test chi-quadro per significativita statistica
            categories = list(set(observed.keys()) | set(expected.keys()))
            obs_counts = [df[col].value_counts().get(c, 0) for c in categories]
            exp_props = [expected.get(c, 0.001) for c in categories]

            # Normalizza expected
            total_exp = sum(exp_props)
            exp_normalized = [p / total_exp * len(df) for p in exp_props]

            chi2, p_value = stats.chisquare(obs_counts, exp_normalized)

            deviation = {
                "chi2_statistic": chi2,
                "p_value": p_value,
                "is_representative": p_value > 0.05,  # p > 0.05 = no significant deviation
                "observed_distribution": observed,
                "expected_distribution": expected
            }

            self.report.checks["representativeness"][col] = deviation

            if p_value <= 0.05:
                is_representative = False
                self.report.recommendations.append(
                    f"CRITICO: Colonna '{col}' non e rappresentativa della popolazione target "
                    f"(chi2={chi2:.2f}, p={p_value:.4f}). "
                    f"Richiesta oversampling o raccolta dati aggiuntiva."
                )

        return is_representative

    def check_bias_protected_attributes(
        self,
        df: pd.DataFrame,
        target_column: str,
        protected_attributes: list[str]
    ) -> bool:
        """
        Art. 10(5): Verifica assenza bias su attributi protetti.
        Usa disparate impact ratio (soglia 0.8 = 80% rule).
        """
        is_unbiased = True
        self.report.checks["bias_assessment"] = {}

        for attr in protected_attributes:
            if attr not in df.columns:
                continue

            groups = df[attr].unique()
            positive_rates = {}

            for group in groups:
                mask = df[attr] == group
                group_df = df[mask]
                if len(group_df) == 0:
                    continue
                positive_rate = (group_df[target_column] == 1).mean()
                positive_rates[str(group)] = positive_rate

            if len(positive_rates) < 2:
                continue

            max_rate = max(positive_rates.values())
            min_rate = min(positive_rates.values())

            # Disparate Impact = min_rate / max_rate
            # AI Act richiede > 0.8 (80% rule)
            disparate_impact = min_rate / max_rate if max_rate > 0 else 1.0

            bias_result = {
                "disparate_impact": disparate_impact,
                "compliant": disparate_impact >= 0.8,
                "group_rates": positive_rates,
                "max_group": max(positive_rates, key=positive_rates.get),
                "min_group": min(positive_rates, key=positive_rates.get)
            }

            self.report.checks["bias_assessment"][attr] = bias_result

            if disparate_impact < 0.8:
                is_unbiased = False
                self.report.recommendations.append(
                    f"CRITICO: Bias rilevato su attributo protetto '{attr}'. "
                    f"Disparate impact = {disparate_impact:.3f} (soglia AI Act: 0.80). "
                    f"Applicare re-weighting, resampling o fairness constraints."
                )

        return is_unbiased

    def check_completeness_and_errors(
        self,
        df: pd.DataFrame,
        critical_features: list[str]
    ) -> bool:
        """
        Art. 10(2): Verifica completezza e assenza di errori.
        """
        is_complete = True
        self.report.checks["completeness"] = {}

        for col in critical_features:
            null_rate = df[col].isna().mean()
            is_col_complete = null_rate < 0.05  # Soglia 5%

            self.report.checks["completeness"][col] = {
                "null_rate": null_rate,
                "compliant": is_col_complete
            }

            if not is_col_complete:
                is_complete = False
                self.report.recommendations.append(
                    f"AVVISO: Feature '{col}' ha {null_rate:.1%} valori mancanti. "
                    f"Applicare imputation strategy o raccogliere dati aggiuntivi."
                )

        return is_complete

    def generate_compliance_report(self) -> str:
        """Genera report JSON per audit AI Act."""
        self.report.compliant = all([
            check.get("is_representative", True)
            for check in self.report.checks.get("representativeness", {}).values()
        ] + [
            check.get("compliant", True)
            for check in self.report.checks.get("bias_assessment", {}).values()
        ] + [
            check.get("compliant", True)
            for check in self.report.checks.get("completeness", {}).values()
        ])

        return json.dumps({
            "dataset": self.report.dataset_name,
            "assessment_date": self.report.assessment_date,
            "assessor": self.report.assessor,
            "ai_act_article_10_compliant": self.report.compliant,
            "checks": self.report.checks,
            "recommendations": self.report.recommendations,
            "next_review_date": "2025-04-15"
        }, indent=2, default=str)


# Esempio di utilizzo per un sistema HR high-risk
def assess_hr_model_dataset(df: pd.DataFrame):
    checker = AIActArticle10Checker(
        dataset_name="hr_promotion_training_v3",
        assessor="Maria Rossi, Data Steward HR"
    )

    # Distribuzione di riferimento: composizione forza lavoro italiana
    reference_distributions = {
        "gender": {"M": 0.54, "F": 0.46},
        "age_group": {"18-30": 0.20, "31-45": 0.40, "46-60": 0.35, "60+": 0.05}
    }

    # Esegui tutti i check
    checker.check_representativeness(df, ["gender", "age_group"], reference_distributions)
    checker.check_bias_protected_attributes(df, "promoted", ["gender", "age_group", "nationality"])
    checker.check_completeness_and_errors(df, ["performance_score", "tenure", "education_level"])

    report = checker.generate_compliance_report()
    print(report)
    return report

Data Observability: Monitoring Continuo delle Pipeline in Produzione

La data quality non si garantisce solo al momento dell'ingestion: i dati si degradano nel tempo. Il fenomeno del data drift - in cui la distribuzione dei dati in produzione si discosta progressivamente dal training set - e una delle cause principali di degradazione silente dei modelli AI. La data observability affronta questo problema con monitoring continuo e alerting proattivo.

Confronto Strumenti Data Observability 2025

Strumento Tipo Punti di Forza Caso d'Uso Ideale
Soda Core Open source YAML-based, CLI, integrabile in CI/CD PMI con budget limitato, pipeline dbt
Monte Carlo SaaS (enterprise) ML-powered, zero-config anomaly detection Enterprise, volume elevato, team piccolo
Great Expectations Open source Python-native, flessibile, documentazione auto Team data engineering, pipeline Python
dbt tests Open source Quality as code, integrato nel workflow dbt Teams che usano dbt come layer principale
Metaplane SaaS (mid-market) Lineage + observability, UI intuitiva Scale-up con più data sources

Data Drift Detection con Soda Core

Soda Core permette di definire check di qualità in YAML e di eseguirli in modo schedulato o on-demand. Per il monitoring del data drift, e possibile confrontare le distribuzioni di feature critiche tra periodi diversi, rilevando automaticamente cambiamenti significativi che potrebbero degradare i modelli AI.

# soda_checks_ml_pipeline.yml
# Check Soda Core per data observability pipeline ML

checks for ml_features_customer:

  # === FRESHNESS: timeliness dei dati ===
  - freshness(event_date) < 24h:
      name: "Dati non più vecchi di 24 ore"
      fail:
        when freshness(event_date) > 24h
      warn:
        when freshness(event_date) > 12h

  # === VOLUME: anomalie di volumetria ===
  - row_count > 50000:
      name: "Minimo 50K record per inference affidabile"

  - row_count between 50000 and 5000000:
      name: "Volume nel range atteso (no spike anomali)"

  # === COMPLETENESS ===
  - missing_count(customer_age) = 0:
      name: "Customer age: zero null tollerati"

  - missing_percent(monthly_charges) < 2%:
      name: "Monthly charges: max 2% null"

  # === VALIDITY ===
  - invalid_percent(customer_age) < 0.1%:
      name: "Customer age nel range 18-120"
      valid min: 18
      valid max: 120

  - duplicate_count(customer_id) = 0:
      name: "Nessun customer_id duplicato"

  # === DISTRIBUTION DRIFT ===
  # Confronto con baseline storica (riferimento: settimana precedente)
  - distribution_difference_index(monthly_charges) < 0.1:
      name: "Monthly charges: drift < 10% vs baseline"
      method: psi  # Population Stability Index
      baseline: soda://ml_features_customer/monthly_charges_baseline

  - distribution_difference_index(customer_age) < 0.1:
      name: "Customer age: drift < 10% vs baseline"
      method: ks   # Kolmogorov-Smirnov test

  # === BUSINESS RULES ===
  - failed_rows(monthly_charges_anomaly):
      name: "Nessun addebito negativo"
      fail condition: monthly_charges < 0

  - failed_rows(contract_consistency):
      name: "Contratti annuali: addebito >= 100 EUR"
      fail condition: contract_type = 'annual' AND monthly_charges < 100

# Configurazione alerting
alert config:
  slack:
    webhook: "https://hooks.slack.com/services/..."
    channel: "#data-quality-alerts"
  email:
    to:
      - "data-team@azienda.it"
      - "ml-team@azienda.it"
  severity:
    fail: immediate
    warn: daily_digest

Bias Detection nei Dataset ML: Approccio Sistematico

Il bias nei dati e uno dei problemi più insidiosi nel machine learning aziendale: silenzioso, difficile da rilevare senza metodologie appropriate, e potenzialmente discriminatorio verso gruppi protetti. Con l'AI Act che classifica come "high-risk" i sistemi AI usati in decisioni su accesso al lavoro, credito, servizi pubblici e istruzione, la bias detection e diventata un requisito di compliance oltre che di etica professionale.

I bias nei dati di training derivano da tre sorgenti principali: historical bias (dati che riflettono discriminazioni passate, es. tassi di promozione storicamente sbilanciati), representation bias (gruppi sottorappresentati nel training set), e measurement bias (feature che servono come proxy per attributi protetti, es. codice postale come proxy del reddito e dell'etnia).

Metriche di Fairness - Standard IBM AIF360 e AI Act

Metrica Formula Soglia AI Act Uso Tipico
Disparate Impact P(Y=1|A=0) / P(Y=1|A=1) >= 0.80 Hiring, credit
Equal Opportunity TPR(A=0) - TPR(A=1) |diff| < 0.05 Healthcare, justice
Demographic Parity P(Y=1|A=0) - P(Y=1|A=1) |diff| < 0.05 Recommendations
Calibration P(Y=1|score=s, A=a) uniforme RMSE < 0.02 Risk scoring

Case Study: Data Governance per una PMI Manifatturiera Italiana

Una PMI manifatturiera lombarda con 180 dipendenti ha avviato nel 2024 un programma di data governance per supportare tre iniziative AI: un modello di predictive maintenance per i macchinari CNC, un sistema di quality control visivo basato su computer vision, e un demand forecasting per la pianificazione della produzione.

Sfida: I Dati Erano Ovunque e Nessuno ne Era Responsabile

La situazione iniziale era tipica delle PMI italiane: sensori IoT che scrivevano dati in formati proprietari, dati di produzione in un ERP SAP Business One, dati di qualità in fogli Excel condivisi via email, dati di vendita in un CRM non integrato. Il team IT aveva una visione tecnica dell'infrastruttura ma nessuna governance formale.

Risultati Programma Data Governance (12 mesi)

Indicatore Prima Dopo 12 mesi Impatto
Data quality score medio 61% 94% +33 punti
Tempo preparazione dati ML 3-4 settimane 2-3 giorni -90%
Dataset con lineage documentata 0% 87% +87 punti
Modelli AI in produzione 0 3 +3 sistemi
Conformità AI Act Art. 10 Non valutata Conforme Pronto per audit

Il Roadmap Implementativo in 4 Fasi

Il programma e stato strutturato in 4 fasi trimestrali, con un investimento totale di circa 85.000 EUR (in parte coperto dal PNRR Transizione 5.0):

  • Fase 1 - Inventario e Assessment (Q1 2024): Mappatura di tutti i sistemi dati, classificazione dei dataset per criticita AI, assessment qualità iniziale. Strumenti: foglio di inventario + questionario self-assessment per i responsabili di dominio. Output: mappa completa dei dati critici con gap analysis.
  • Fase 2 - Foundation (Q2 2024): Deployment di OpenMetadata on-premise, configurazione dei primi cataloghi dati, definizione dei data steward per ogni dominio (produzione, qualità, vendite). Implementazione dei primi check automatici con dbt tests.
  • Fase 3 - Quality Automation (Q3 2024): Deploy Great Expectations per validazione automatica dei dataset ML, integrazione con Airflow per alerting, definizione delle SLA di qualità per i 3 progetti AI. Prima valutazione AI Act Art. 10.
  • Fase 4 - Optimization e Governance Matura (Q4 2024): Data Council mensile attivo, KPI di qualità su dashboard Metabase, processo di change management formale, training al personale. I 3 modelli AI sono stati deployati in produzione con data governance completa.

Lezioni Apprese: i 5 Errori da Evitare

  • Partire dagli strumenti invece che dai processi: La tecnologia viene dopo le persone e i processi. Nominare i data steward prima di installare qualsiasi software.
  • Voler fare tutto subito: Un programma di governance evolutivo e più sostenibile di un big bang. Iniziare dai dataset critici per l'AI, espandere gradualmente.
  • Sottovalutare la formazione: Il 40% del budget è stato investito in training e change management. Senza questo, gli strumenti vengono ignorati.
  • Non coinvolgere il business: I data steward devono essere figure ibride business-tecnica, non solo IT. Il business sa quali dati sono critici, l'IT sa come misurarli.
  • Ignorare la compliance fin dall'inizio: I requisiti AI Act non sono un vincolo: sono la struttura che giustifica l'investimento in governance agli occhi del management.

Best Practices e Anti-Pattern

Best Practices Fondamentali

  • Quality as Code: Definisci i requisiti di qualità nel codice (YAML, Python) versionato in Git, non in documenti Word. Questo rende i check automatici, riproducibili e parte del processo di CI/CD.
  • Fail Fast, Fail Loud: I check di data quality devono bloccare la pipeline (non solo generare un warning) quando i dati sono fuori soglia. Un modello addestrato su dati scadenti causa danni peggiori di una pipeline ferma.
  • Separate Validation da Transformation: Valida i dati prima di trasformarli (validazione schema e range a ingestion), durante la trasformazione (test dbt nei modelli), e prima dell'uso in ML (Great Expectations sul feature store). La qualità si verifica in più punti, non solo alla fine.
  • Monitora il Drift, Non Solo la qualità Statica: I dati cambiano nel tempo. PSI (Population Stability Index) e test KS (Kolmogorov-Smirnov) sono strumenti standard per rilevare derive distribuzionali che degradano i modelli silenziosamente.
  • Documenta le Decisioni di Governance: Ogni scelta (soglia di qualità, strategia di imputation, esclusione di un dataset) deve essere documentata con data, autore e razionale. Questa documentazione e richiesta dall'AI Act per i sistemi high-risk.

Anti-Pattern da Evitare

Anti-Pattern Critici nella Data Governance per AI

  • Data quality "best effort": Definire SLA vaghi ("dati il più possibile completi") invece di soglie numeriche precise e misurabili. Senza metriche, non c'e governance reale.
  • Silencing degli alerts: Configurare i check di qualità e poi silenziare gli alert perchè "disturbano". Ogni alert ignorato e un futuro problema di modello in produzione.
  • Governance solo per i nuovi progetti: I dataset legacy usati per riaddestramento dei modelli hanno gli stessi requisiti di qualità. Spesso sono i più problematici.
  • Bias check "one-shot": Verificare il bias solo prima del training iniziale. Il bias può emergere con i nuovi dati di produzione nel tempo (concept drift).
  • Confondere data quality per analytics e per ML: Soglie accettabili per un dashboard (5% null in una colonna) possono essere catastrofiche per un feature di input ML. I due contesti richiedono standard diversi.

Conclusioni e Next Steps

La data governance e la data quality per AI non sono burocrazia: sono l'infrastruttura invisibile che determina se i tuoi modelli funzionano in produzione o falliscono silenziosamente. Con l'AI Act EU che porta requisiti legalmente vincolanti sui dati di training, investire in governance non e solo una buona pratica - e un prerequisito per operare nel mercato europeo con sistemi AI ad alto rischio.

Il punto di partenza pratico per qualsiasi organizzazione - PMI o enterprise - e lo stesso: identifica i 3-5 dataset più critici per le tue iniziative AI, nomina un data steward per ognuno, implementa i check automatici con gli strumenti open source descritti in questo articolo (Great Expectations, dbt-expectations, Soda Core), e costruisci gradualmente la struttura di governance attorno a questi dataset.

La perfezione non e il requisito iniziale: il 94% di data quality score raggiunto dalla PMI manifatturiera del nostro case study dopo 12 mesi e partita dal 61%. Il viaggio conta quanto la destinazione, e ogni punto percentuale di miglioramento della qualità dei dati si traduce direttamente in modelli AI più affidabili, meno incidenti in produzione, e decisioni aziendali più solide.

Checklist Avvio Programma Data Governance per AI

  • Inventario dei dataset critici per AI completato
  • Data steward nominati per ogni dominio dati chiave
  • SLA di qualità definiti e approvati (completeness, freshness, validity)
  • Check automatici implementati in pipeline (GE, dbt-expectations o Soda)
  • Data catalog con lineage configurato (OpenMetadata o Apache Atlas)
  • Bias assessment eseguito per tutti i dataset usati in sistemi high-risk
  • Documentazione AI Act Art. 10 per sistemi high-risk avviata
  • Alerting configurato e canali di escalation definiti
  • Primo Data Council mensile pianificato
  • Formazione al team completata

Approfondimenti Correlati

  • MLOps per Business: Come monitorare il drift dei modelli in produzione con MLflow - Articolo #12 di questa serie
  • LLM in Azienda: Data governance per RAG enterprise e sicurezza dei dati nei Large Language Models - Articolo #10 di questa serie
  • AI Engineering: Feature store e embedding governance per sistemi RAG enterprise - Serie AI Engineering
  • PostgreSQL AI: pgvector e data quality per vector databases - Serie PostgreSQL AI

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti