Saltar al contenido principal

7.2.2 Procesamiento de datos

En el mundo real, los ficheros suelen venir "sucios": líneas vacías inesperadas, espacios extra, codificaciones extrañas o formatos inconsistentes. El procesamiento de datos es el arte de transformar ese caos en estructuras utilizables.


1️⃣ El Pipeline de Procesamiento​

Un buen procesador de archivos sigue siempre un esquema mental claro.

  1. Iteración → recorrer el fichero.
  2. Limpieza (Sanitización) → eliminar ruido.
  3. Filtrado → descartar lo irrelevante.
  4. Transformación → convertir tipos.
  5. Almacenamiento o cálculo → usar el dato.

Este flujo es clave. Saltarse pasos genera errores silenciosos.

🟩 Iteración eficiente​

Siempre que sea posible, recorre línea a línea:

with open("datos.txt", "r", encoding="utf-8") as f:
for linea in f:
print(linea)

Ventaja:

  • No cargas todo en memoria.
  • Puedes procesar archivos grandes.

🟦 Limpieza básica: strip()​

Al leer de un fichero, las líneas incluyen \n.

linea = " Ana , 25 \n"
print(linea.strip())

Resultado:

Ana , 25

strip() elimina espacios y saltos al inicio y al final.

tip

También existen:

  • lstrip() → izquierda
  • rstrip() → derecha

🟨 Filtrado inteligente​

No todo lo que se lee es útil.

Ejemplo típico:

if not linea or linea.startswith("#"):
continue
en este ejemplo
  • Ignorando líneas vacías.
  • Ignorando comentarios.

Este patrón es muy común en logs y configuraciones.

🟧 Transformación de tipos​

El fichero solo contiene texto. Si necesitas números, debes convertirlos.

partes = linea.split("|")
id_item = int(partes[0])
valor = float(partes[1])
en este ejemplo

Si no conviertes, todo será string y los cálculos fallarán.

🟥 Pipeline completo ejemplo​

def procesar_log(ruta):
datos_limpios = []

with open(ruta, "r", encoding="utf-8") as f:
for linea in f:
linea = linea.strip()

if not linea or linea.startswith("#"):
continue

partes = linea.split("|")
id_item = int(partes[0].strip())
valor = float(partes[1].strip())

datos_limpios.append({
"id": id_item,
"valor": valor
})

return datos_limpios
en este ejemplo

Aquí vemos claramente las 5 fases del procesamiento.


2️⃣ Problemas comunes en datos reales​

🟩 Separadores inconsistentes​

A veces el fichero mezcla espacios:

Ana , 25 , Madrid

Solución profesional:

datos = [d.strip() for d in linea.split(",")]

Esto limpia cada elemento individualmente.

🟦 Valores faltantes​

Ejemplo:

Ana|25
Luis|

Si haces:

int(partes[1])

Fallará.

Solución defensiva:

if partes[1]:
edad = int(partes[1])
else:
edad = None

🟨 Tipos incorrectos​

Si esperas un número y aparece texto:

Juan|veinte

Sin control, el programa se detiene.

🟧 Procesamiento defensivo​

def extraer_puntos(linea):
try:
nombre, puntos = linea.split(":")
return int(puntos)
except ValueError:
print(f"Línea corrupta ignorada: {linea}")
return None

Esto permite que el programa continúe.


3️⃣ Procesamiento eficiente y memoria​

No siempre necesitamos guardar todo.

Ejemplo incorrecto:

datos = []
for linea in f:
datos.append(linea)

Si el archivo es enorme, puede consumir demasiada RAM.

🟩 Cálculo incremental​

Si solo quieres sumar valores:

total = 0

with open("ventas.txt", "r", encoding="utf-8") as f:
for linea in f:
total += float(linea.strip())

print(total)
en este ejemplo

Aquí nunca almacenamos todas las líneas.

🟦 Generadores (nivel intermedio)​

En lugar de listas intermedias:

valores = (float(l.strip()) for l in f)
en este ejemplo

Esto genera valores “sobre la marcha”.


4️⃣ Validación básica antes de procesar​

Antes de procesar un fichero grande conviene:

  • Verificar que no esté vacío.
  • Verificar número mínimo de columnas.
  • Manejar excepciones.
  • Confirmar formato esperado.

Ejemplo simple:

if "|" not in linea:
continue

✅ Buenas prácticas en procesamiento​

buenas prácticas
  • Limpiar siempre antes de transformar.
  • Convertir tipos lo antes posible.
  • Manejar errores de conversión.
  • No asumir que el dato es perfecto.
  • Evitar cargar todo si no es necesario.
  • Separar lectura de lógica de negocio.

🧪 Ejercicios prácticos – Aditoría del sistema​

Después de restaurar el sistema (7.1.1), el equipo necesita una auditoría. El sistema ya arranca, pero los datos siguen “brutos” y hay que convertirlos en información útil.

Dispones de estos ficheros: 👉 Descárgalos aquí

  • eventos_brutos.txt → eventos sin limpiar del sistema
  • configuracion_sistema.txt → configuración activa con parámetros legacy
  • accesos_usuarios.txt → registros de acceso con duplicados e inconsistencias

Tu misión es limpiar, validar, transformar y generar informes.

🟢 Fase 1 – Limpieza del registro de eventos​

🟩 Ejercicio 1 – Normalización del registro (eventos_brutos.txt)​

El registro está lleno de ruido (comentarios, líneas vacías y espacios irregulares). Crea un archivo eventos_limpios.txt que:

  • Ignore líneas que empiecen por #
  • Ignore líneas vacías
  • Elimine espacios sobrantes en cada campo
  • Guarde las líneas con el formato exacto:
fecha|nivel|usuario|mensaje

Ejemplo de salida:

2026-02-16|INFO|admin|inicio del sistema

🟦 Ejercicio 2 – Resumen rápido de severidad​

El equipo necesita una visión global del estado del sistema. Recorre eventos_brutos.txt y calcula (sin cargar todo en memoria):

  • Total de eventos válidos
  • Total de eventos INFO
  • Total de eventos DEBUG
  • Total de eventos ERROR

Muestra el resultado por pantalla.

🟡 Fase 2 – Validación de integridad del log​

🟨 Ejercicio 3 – Detección de eventos incompletos​

No se puede auditar un sistema con eventos corruptos.

En eventos_brutos.txt, cuenta cuántos registros tienen problemas como:

  • Menos de 4 campos separados por |
  • El campo usuario vacío

Muestra por pantalla:

  • Total de eventos incompletos
  • Ejemplos de líneas descartadas (solo 2 o 3, no todas)

🟧 Ejercicio 4 – Archivo de incidentes críticos​

El equipo de seguridad solo quiere el listado de incidentes (errores).

Crea un archivo incidentes.txt que contenga solo los mensajes de los eventos ERROR (sin fecha, sin nivel, sin usuario), por ejemplo:

fallo autenticacion
error en base de datos
timeout conexion

🔵 Fase 3 – Reconstrucción de la configuración real​

🟥 Ejercicio 5 – Cargar configuración activa (configuracion_sistema.txt)​

La configuración está mezclada con comentarios y parámetros legacy. Construye un diccionario en memoria con los valores reales:

  • Ignora comentarios # y líneas vacías
  • Extrae pares clave = valor
  • Aplica strip() a ambos lados

Resultado esperado (ejemplo):

{
"modo": "produccion",
"max_usuarios": "100",
"timeout": "30",
"debug": "true",
...
}

🟪 Ejercicio 6 – Conversión de tipos (configuración lista para usar)​

Ahora el equipo quiere usar esa configuración en el programa, por tanto necesita tipos correctos:

  • Convertir valores numéricos a int
  • Convertir true/false (ignorando mayúsculas/minúsculas) a booleanos reales True/False

Muestra el diccionario final ya tipado.

🔴 Fase 4 – Auditoría de accesos y cuentas​

🟫 Ejercicio 7 – Duplicados en el sistema (accesos_usuarios.txt)​

El equipo sospecha que hay usuarios repetidos.

En accesos_usuarios.txt:

  • Ignora comentarios y líneas vacías
  • Detecta usuarios que aparecen más de una vez
  • Muestra por pantalla el listado de usuarios duplicados

🟪 Ejercicio 8 – Lista de usuarios activos válidos​

Necesitamos generar una lista real de usuarios activos.

Filtra accesos_usuarios.txt y quédate solo con:

  • Usuarios cuyo campo activo sea True
  • Registros completos (sin campos vacíos)

Muestra por pantalla la lista final.

🟣 Fase Final – Informe consolidado para auditoría​

🟥 Ejercicio 9 – Generar informe del sistema​

Crea un archivo informe_sistema.txt con:

  • Total de eventos válidos
  • Total de errores (ERROR)
  • Total de eventos incompletos descartados
  • Total de usuarios activos válidos
  • Usuarios duplicados detectados

Cada dato en una línea con un formato claro, por ejemplo:

Eventos validos: 7
Errores: 3
Eventos incompletos: 1
Usuarios activos validos: 2
Usuarios duplicados: admin