Juan Diego Andrés PRADA··RAMÍREZ Entrar
Lección 3 de 7

Pandas: registrar y reportar resultados

¿Qué es Pandas?

Pandas es la librería estándar de Python para trabajar con datos tabulares: filas y columnas, como una hoja de cálculo, pero programable. Su estructura central es el DataFrame (una tabla) y la Series (una columna). Por debajo, cada columna es un array de NumPy, así que hereda toda su velocidad.

¿Cómo funciona?

Un DataFrame guarda los datos en columnas con nombre y un índice de filas. Sobre esa tabla puedes filtrar, agrupar, calcular y exportar sin bucles, usando operaciones vectorizadas. Lees datos de una lista, un diccionario, un CSV o un Excel; los transformas; y los vuelves a guardar.

import pandas as pd

# Un DataFrame a partir de un diccionario: claves = columnas
df = pd.DataFrame({
 "estudiante": ["Ana", "Luis", "Marta"],
 "aciertos": [18, 12, 20],
 "total": [20, 20, 20],
})

print(df)
print(df.shape) # (3, 3) -> 3 filas, 3 columnas
print(df["aciertos"]) # una Series (la columna)

¿Para qué sirve? (y qué pieza del OMR construye)

En el proyecto final del calificador OMR, OpenCV nos dará, por cada hoja, una lista de respuestas detectadas. Pandas es la pieza que convierte esas detecciones en una tabla de resultados: calcula la nota de cada estudiante, saca estadísticas del grupo (promedio, pregunta más fallada) y exporta un CSV que el profesor puede abrir en Excel. Es el "acta de calificaciones" automática.

De respuestas detectadas a una tabla

Simulamos lo que nos entregará OpenCV: para cada estudiante, la letra que marcó en cada pregunta. Tenemos también la plantilla (las respuestas correctas).

import pandas as pd

plantilla = ["A", "C", "B", "D", "A"] # respuestas correctas

# Lo que OpenCV "leyó" de cada hoja
detectado = {
 "Ana": ["A", "C", "B", "D", "A"],
 "Luis": ["A", "B", "B", "C", "A"],
 "Marta": ["A", "C", "D", "D", "B"],
}

# Construimos una fila por estudiante
filas = []
for nombre, respuestas in detectado.items():
 aciertos = sum(r == c for r, c in zip(respuestas, plantilla))
 filas.append({
 "estudiante": nombre,
 "aciertos": aciertos,
 "total": len(plantilla),
 })

df = pd.DataFrame(filas)
print(df)

Calcular la nota (columnas derivadas)

Crear una columna nueva a partir de otras es vectorizado: opera sobre toda la columna a la vez.

# Nota sobre 5.0 y aprobado/reprobado
df["nota"] = (df["aciertos"] / df["total"] * 5).round(1)
df["estado"] = df["nota"].apply(lambda n: "Aprobó" if n >= 3.0 else "Reprobó")

print(df)

apply recorre la columna aplicando una función. Para reglas simples prefiere operaciones vectorizadas (df["nota"] >= 3.0); apply es para lógica que no se expresa con aritmética directa.

Filtrar, ordenar y resumir

# Solo quienes aprobaron, ordenados de mayor a menor nota
aprobados = df[df["nota"] >= 3.0].sort_values("nota", ascending=False)
print(aprobados)

# Estadísticas del grupo
print("Promedio del curso:", df["nota"].mean().round(2))
print("Mejor nota:", df["nota"].max())
print("Aprobados:", (df["nota"] >= 3.0).sum(), "de", len(df))

df[df["nota"] >= 3.0] filtra filas; df[["nota", "estado"]] selecciona columnas. Un par de corchetes con una condición filtra; un doble corchete con una lista elige columnas. Confundirlos es el error más común al empezar.

¿Qué pregunta se falló más? (análisis por columna)

Para depurar la plantilla o el examen, conviene saber qué pregunta fue la más difícil.

import pandas as pd

plantilla = ["A", "C", "B", "D", "A"]
detectado = {
 "Ana": ["A", "C", "B", "D", "A"],
 "Luis": ["A", "B", "B", "C", "A"],
 "Marta": ["A", "C", "D", "D", "B"],
}

# Tabla: una fila por estudiante, una columna por pregunta
respuestas_df = pd.DataFrame(detectado).T
respuestas_df.columns = [f"P{i+1}" for i in range(len(plantilla))]

# ¿Acertó cada celda? Comparamos contra la plantilla columna a columna
correctas = respuestas_df.eq(plantilla, axis=1)
fallos_por_pregunta = (~correctas).sum()
print(fallos_por_pregunta.sort_values(ascending=False))

Exportar el acta

df.to_csv("resultados_omr.csv", index=False)
print("Guardado: resultados_omr.csv")

Tech English: DataFrame = marco/tabla de datos; row = fila; column = columna; to filter = filtrar; to export = exportar.

Ejercicios

  1. Añade un cuarto estudiante a detectado, recalcula el DataFrame con aciertos, nota y estado, y exporta el resultado a resultados_omr.csv. Abre el CSV para confirmar.
  2. A partir de respuestas_df, calcula el porcentaje de acierto por pregunta (no el número de fallos) y ordénalo de menor a mayor para identificar la pregunta más difícil del examen.
Tu progreso se guarda en este navegador. Inicia sesión para guardarlo en tu cuenta y verlo desde cualquier dispositivo.