Investigación y fuentes

Crear un diccionario de datos con significados, unidades, tipos y valores permitidos

Documenta qué significa cada columna del conjunto de datos antes del análisis, incluida su unidad, tipo de dato y valores permitidos. Un pequeño conjunto de datos sintético muestra cómo el mismo diccionario también puede servir para una validación automática sencilla.

Ver el índice

La traducción se ha realizado con IA. Comprueba el código, las unidades y los valores junto con el original. La revisión por hablantes nativos de cada idioma aún no se ha completado. English

Para quién esEsta guía está dirigida a investigadores que necesitan una descripción clara, columna por columna, de un conjunto de datos que otras personas puedan leer y revisar.

Preparación
  • Python 3.12 y un comando de terminal que inicie esa versión.
  • Un editor de texto o programa de hojas de cálculo que pueda guardar archivos CSV en UTF-8.
  • Una carpeta de trabajo donde el script pueda crear una nueva carpeta dentro de outputs.
  • Solo se requiere la biblioteca estándar de Python: csv, pathlib y re.

01Tratar el diccionario de datos como parte del conjunto de datos

El nombre de una columna rara vez basta para describir datos de investigación. speed podría significar velocidad del vehículo, velocidad de la rueda o velocidad angular. accel podría significar aceleración longitudinal, lateral o total. Un diccionario de datos registra el significado previsto para que los análisis posteriores no dependan de suposiciones.

Este tutorial registra seis elementos de información para cada columna: nombre de la columna, significado, unidad, tipo de dato, valores permitidos y un ejemplo. El campo de valores permitidos puede describir categorías, rangos numéricos, reglas de unicidad o patrones de texto simples.

02Crear un pequeño conjunto de datos sintético de investigación

El siguiente conjunto de datos es sintético y fue creado específicamente para este artículo. Guárdalo como test_runs.csv. Cuatro filas siguen las reglas previstas. La quinta fila contiene deliberadamente cuatro problemas para que el diccionario pueda utilizarse como referencia de validación.

csv
run_id,speed_kmh,accel_m_s2,road_surface,test_status
R001,30,0.5,dry,complete
R002,50,-1.2,wet,complete
R003,70,0.0,dry,review
R004,40,-0.8,wet,complete
R005,135,fast,snow,done

Hay 5 filas y 5 columnas. R005 tiene un speed por encima del rango permitido, un valor de acceleration no numérico, una categoría de road-surface no admitida y un valor de test-status no admitido. Su run_id sí es válido.

03Escribir manualmente el diccionario de datos esperado

El diccionario debe poder entenderse sin abrir el código de análisis. Mantén el significado lo bastante específico como para que otro investigador pueda distinguir la columna de otras mediciones similares.

column_namesignificadounidadtipovalores permitidosejemplo
run_idIdentificador único de una ejecución de pruebacadenaR seguida de exactamente 3 dígitos; únicoR001
speed_kmhVelocidad del vehículo al inicio del registrokm/henterode 0 a 120 inclusive50
accel_m_s2Aceleración longitudinalm/s^2decimalde -5.0 a 5.0 inclusive-1.2
road_surfaceCondición de la superficie de la carretera utilizada en la pruebacategoríadry;wetwet
test_statusEstado de revisión del registro de pruebacategoríacomplete;reviewcomplete

Una unidad vacía es intencional para identificadores y etiquetas categóricas porque son metadatos adimensionales, no magnitudes físicas medidas. El campo type describe la representación de datos prevista, no lo que una hoja de cálculo pueda inferir automáticamente.

04Generar el diccionario y validar el conjunto de datos

Guarda el siguiente script como data_dictionary_check.py. La especificación de columnas se escribe una sola vez en SPEC. El script exporta esa especificación como data_dictionary.csv y comprueba cada fila con las mismas reglas. El archivo original test_runs.csv solo se lee.

python
import csv
import re
from pathlib import Path

SOURCE = Path("test_runs.csv")
OUTPUT_DIR = Path("outputs") / "data_dictionary_result"
DICTIONARY = OUTPUT_DIR / "data_dictionary.csv"
ISSUES = OUTPUT_DIR / "validation_issues.csv"

SPEC = [
    {
        "column_name": "run_id",
        "meaning": "Unique identifier for one test run",
        "unit": "",
        "type": "string",
        "allowed_values": "R followed by exactly 3 digits; unique",
        "example": "R001",
    },
    {
        "column_name": "speed_kmh",
        "meaning": "Vehicle speed at the start of the record",
        "unit": "km/h",
        "type": "integer",
        "allowed_values": "0 to 120 inclusive",
        "example": "50",
    },
    {
        "column_name": "accel_m_s2",
        "meaning": "Longitudinal acceleration",
        "unit": "m/s^2",
        "type": "float",
        "allowed_values": "-5.0 to 5.0 inclusive",
        "example": "-1.2",
    },
    {
        "column_name": "road_surface",
        "meaning": "Road-surface condition used for the test",
        "unit": "",
        "type": "category",
        "allowed_values": "dry;wet",
        "example": "wet",
    },
    {
        "column_name": "test_status",
        "meaning": "Review state of the test record",
        "unit": "",
        "type": "category",
        "allowed_values": "complete;review",
        "example": "complete",
    },
]


def issue(row_number, column, value, problem):
    return {
        "row_number": row_number,
        "column_name": column,
        "value": value,
        "issue": problem,
    }


def main() -> None:
    if not SOURCE.is_file():
        raise FileNotFoundError(f"Source CSV not found: {SOURCE}")
    if OUTPUT_DIR.exists():
        raise FileExistsError(f"Output folder already exists: {OUTPUT_DIR}")

    expected_columns = [item["column_name"] for item in SPEC]
    issues = []
    seen_run_ids = set()
    row_count = 0

    with SOURCE.open("r", encoding="utf-8-sig", newline="") as stream:
        reader = csv.DictReader(stream)
        if reader.fieldnames != expected_columns:
            raise ValueError(
                f"Header mismatch. Expected {expected_columns}, got {reader.fieldnames}."
            )

        for row_number, row in enumerate(reader, start=2):
            row_count += 1

            run_id = row["run_id"].strip()
            if re.fullmatch(r"R[0-9]{3}", run_id) is None:
                issues.append(issue(row_number, "run_id", run_id, "PATTERN_ERROR"))
            elif run_id in seen_run_ids:
                issues.append(issue(row_number, "run_id", run_id, "DUPLICATE_VALUE"))
            seen_run_ids.add(run_id)

            try:
                speed = int(row["speed_kmh"])
            except ValueError:
                issues.append(issue(row_number, "speed_kmh", row["speed_kmh"], "TYPE_ERROR"))
            else:
                if not 0 <= speed <= 120:
                    issues.append(issue(row_number, "speed_kmh", row["speed_kmh"], "OUT_OF_RANGE"))

            try:
                accel = float(row["accel_m_s2"])
            except ValueError:
                issues.append(issue(row_number, "accel_m_s2", row["accel_m_s2"], "TYPE_ERROR"))
            else:
                if not -5.0 <= accel <= 5.0:
                    issues.append(issue(row_number, "accel_m_s2", row["accel_m_s2"], "OUT_OF_RANGE"))

            if row["road_surface"] not in {"dry", "wet"}:
                issues.append(issue(row_number, "road_surface", row["road_surface"], "ALLOWED_VALUE_ERROR"))

            if row["test_status"] not in {"complete", "review"}:
                issues.append(issue(row_number, "test_status", row["test_status"], "ALLOWED_VALUE_ERROR"))

    OUTPUT_DIR.parent.mkdir(parents=True, exist_ok=True)
    OUTPUT_DIR.mkdir()

    dictionary_fields = [
        "column_name", "meaning", "unit", "type", "allowed_values", "example"
    ]
    with DICTIONARY.open("x", encoding="utf-8", newline="") as stream:
        writer = csv.DictWriter(stream, fieldnames=dictionary_fields)
        writer.writeheader()
        writer.writerows(SPEC)

    issue_fields = ["row_number", "column_name", "value", "issue"]
    with ISSUES.open("x", encoding="utf-8", newline="") as stream:
        writer = csv.DictWriter(stream, fieldnames=issue_fields)
        writer.writeheader()
        writer.writerows(issues)

    print(f"Rows checked: {row_count}.")
    print(f"Dictionary columns: {len(SPEC)}.")
    print(f"Validation issues: {len(issues)}.")
    print(f"Output folder: {OUTPUT_DIR.as_posix()}")


if __name__ == "__main__":
    main()

05Comparar los problemas de validación esperados

Solo R005 debería producir problemas. Como el encabezado del CSV ocupa la fila 1, R005 corresponde físicamente a la fila 6 del CSV. Deberían escribirse cuatro filas de problemas.

csv
row_number,column_name,value,issue
6,speed_kmh,135,OUT_OF_RANGE
6,accel_m_s2,fast,TYPE_ERROR
6,road_surface,snow,ALLOWED_VALUE_ERROR
6,test_status,done,ALLOWED_VALUE_ERROR

La salida de consola esperada que aparece a continuación se obtuvo manualmente a partir del conjunto de datos sintético y del script. No es un registro capturado de una ejecución.

text
Rows checked: 5.
Dictionary columns: 5.
Validation issues: 4.
Output folder: outputs/data_dictionary_result

06Comprobar que el diccionario y los datos sigan alineados

  • Confirma que cada columna del conjunto de datos tenga exactamente una fila en el diccionario.
  • Comprueba que las unidades físicas estén indicadas explícitamente para las magnitudes medidas.
  • Confirma que los valores categóricos permitidos usen la misma ortografía y capitalización que el conjunto de datos.
  • Revisa cada problema de validación en lugar de eliminar automáticamente las filas incorrectas.
  • Ejecuta el script de nuevo sin cambiar OUTPUT_DIR. Debería detenerse con FileExistsError en lugar de sustituir el diccionario y el informe anteriores.
ProblemaQué comprobar
Una nueva columna del conjunto de datos no tiene entrada en el diccionarioActualiza el diccionario antes del análisis para documentar el significado y la unidad.
El mismo concepto aparece con unidades diferentesUsa columnas separadas o estandariza las unidades explícitamente; no dependas de la memoria.
Las etiquetas de categoría cambian con el tiempoDefine los valores permitidos y documenta las adiciones intencionadas, como una nueva condición de carretera.
La hoja de cálculo convierte IDs enteros en númerosGuarda los identificadores como cadenas cuando los ceros iniciales o los patrones sean significativos.
La validación pasa, pero el significado es incorrectoLas comprobaciones estructurales no pueden detectar una definición científica incorrecta ni un canal de sensor mal etiquetado.

07Ampliar el diccionario a medida que crece el proyecto

Un diccionario práctico de datos de investigación suele necesitar más que los seis campos mostrados aquí. Según el proyecto, añade source system, sensor location, coordinate direction, sampling rate, nullable status, precision, calculation method, valid range, missing-value code y responsible owner.

Los valores permitidos deben reflejar el significado científico y no simplemente el mínimo y el máximo observados actualmente. Si en un archivo los valores de speed están entre 30 y 70 km/h, eso no significa automáticamente que de 30 a 70 sea el rango de ingeniería válido.

Versiona el diccionario junto con el conjunto de datos o el código de análisis. Si cambia la definición de una columna, una unidad, la convención de signo o una categoría, registra cuándo se produjo el cambio. Un diccionario de datos resulta más útil cuando describe exactamente la versión de los datos que se está analizando.

Registro de ejecución y verificación

2026-09-20 · ejemplo revisado manualmente · objetivo: Python 3.12 · biblioteca estándar: csv, pathlib, re · sin ejecución

  • Se contaron manualmente 5 filas sintéticas y 5 columnas del conjunto de datos.
  • Se comprobó manualmente que R001 a R004 cumplen las reglas indicadas en el diccionario.
  • Se identificaron cuatro problemas en R005: speed 135 supera el rango 0-120, el valor de accel fast no es numérico, road_surface snow no está permitido y test_status done no está permitido.
  • Se confirmó que R005 sí coincide con el patrón de run_id de R seguida de tres dígitos.
  • Se obtuvo manualmente la fila física 6 del CSV para los cuatro problemas de validación de R005.
  • Se revisó el script para comprobar la coincidencia exacta de encabezados, IDs de ejecución únicos, comprobaciones de rangos numéricos, comprobaciones categóricas, protección frente a colisiones de salida y conservación del CSV original.
Límites de la verificación
  • El código no fue ejecutado por el autor de esta respuesta; no se creó ningún CSV de diccionario ni de validación.
  • Los rangos y categorías sintéticos son específicos de este ejercicio y no representan límites generales de ingeniería automotriz.
  • El significado científico, la calibración de sensores, las convenciones de coordenadas, las políticas de valores ausentes y el versionado de metadatos no se validaron automáticamente.
  • Las URL de la documentación oficial se proporcionaron a partir de ubicaciones de documentación conocidas, pero no se comprobaron en línea.

Criterios de redacción y verificación de todo el sitio

Fuentes de referencia

Las explicaciones y los ejemplos son de elaboración propia. Puedes consultar los comportamientos y conceptos relacionados en las siguientes fuentes oficiales.