¿Qué pregunta separa mejor a los alumnos?
Un árbol de decisión es un modelo que hace preguntas de sí o no, una tras otra, hasta dar una respuesta. Para construirlo se elige en cada paso la pregunta que mejor separa los casos. Eso se mide con la entropía y la ganancia de información.
Una tutora quiere avisar a quien corre riesgo de suspender. Tiene dos datos de cada alumno. ¿Cuál debe preguntar primero?
Al final de esta lección
Nota
Puedo elegir la mejor pregunta para dividir un conjunto de datos con la ganancia de información.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Árbol de decisión | un modelo hecho de preguntas encadenadas |
| Hoja | el final de una rama, con la respuesta |
| Entropía | cuánto desorden hay en las etiquetas de un grupo |
| División | repartir las filas según una pregunta |
| Ganancia de información | cuánta entropía baja con una división |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
La entropía mide el desorden de un grupo
Un grupo donde todos aprueban es ordenado: la entropía es 0. Un grupo mitad y mitad es lo más desordenado con dos etiquetas: la entropía es 1.
Para cada etiqueta se toma su parte p del grupo. La entropía es la suma de -p × log2(p). No hace falta calcularlo a mano: la tabla da los casos típicos.
Ejemplo resuelto: la entropía de cinco grupos
| Grupo de 10 | Aprueban | Suspenden | Entropía |
|---|---|---|---|
| Todos igual | 10 | 0 | 0 |
| Casi todos | 9 | 1 | 0,469 |
| Una mayoría clara | 8 | 2 | 0,722 |
| Una mayoría corta | 6 | 4 | 0,971 |
| Mitad y mitad | 5 | 5 | 1 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Calcula la entropía de cuatro grupos
docker exec jupyter python3 -c "import math; print([round(-sum(p * math.log2(p) for p in (a, 1 - a)), 3) for a in (0.5, 0.6, 0.8, 0.9)])"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
La ganancia mide cuánto ordena una pregunta
Una pregunta reparte los alumnos en grupos. Tras la división se calcula la entropía de cada grupo y se pondera por su tamaño.
La ganancia de información es la entropía de antes menos la de después. Gana la pregunta con más ganancia.
Ejemplo resuelto: dos preguntas sobre diez alumnos
| Pregunta | Grupos (aprueban de 5) | Entropía después | Ganancia |
|---|---|---|---|
| ¿Asistencia alta? | alta 4, baja 2 | 0,847 | 0,125 |
| ¿Prácticas completas? | completas 5, incompletas 1 | 0,361 | 0,610 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Calcula la ganancia de cada pregunta
import math
rows = [["alta", "completas", "aprueba"], ["alta", "completas", "aprueba"],
["alta", "incompletas", "aprueba"], ["alta", "incompletas", "suspende"],
["alta", "completas", "aprueba"], ["baja", "completas", "aprueba"],
["baja", "incompletas", "suspende"], ["baja", "incompletas", "suspende"],
["baja", "completas", "aprueba"], ["baja", "incompletas", "suspende"]]
def entropy(labels):
total = 0.0
for label in ["aprueba", "suspende"]:
p = labels.count(label) / len(labels)
if p > 0:
total = total - p * math.log2(p)
return total
def gain(column):
groups = {}
for row in rows:
if row[column] in groups:
groups[row[column]].append(row[2])
else:
groups[row[column]] = [row[2]]
after = 0.0
for value in groups:
after = after + len(groups[value]) / len(rows) * entropy(groups[value])
return entropy([row[2] for row in rows]) - after
print("asistencia", round(gain(0), 3))
print("prácticas", round(gain(1), 3))
# Cambia el resultado de la última fila a "aprueba" y vuelve a ejecutar.
El árbol crece hasta tener grupos claros
Tras la primera pregunta, cada rama se trata como un conjunto nuevo. Se repite el cálculo con las preguntas que quedan.
Una rama se cierra en una hoja cuando todos sus casos tienen la misma etiqueta, o cuando quedan muy pocos para seguir dividiendo.
Un error muy común
Advertencia
Mucha gente cree que un árbol más profundo es siempre mejor, porque acierta todos los casos que ha visto. Pero con pocos casos por hoja, solo memoriza. Para a un nivel razonable y juzga el árbol con datos que no vio.
Con los días de bicicletas gana la temperatura
Ahora el grupo son los 365 días de bicicletas, con la etiqueta «movido» (300 alquileres o más). Hay 131 días movidos y 234 tranquilos.
Compara dos preguntas: ¿qué tiempo hizo? (soleado, nublado o lluvioso) y ¿hizo 12 grados o más?
Mide la entropía y dos ganancias
docker exec jupyter python3 -c "import csv, math; d=list(csv.DictReader(open('hires.csv'))); y=[int(r['hires'])>=300 for r in d]; H=lambda l: -sum(l.count(c)/len(l)*math.log2(l.count(c)/len(l)) for c in set(l)); g=lambda f: H(y)-sum(len(s)/len(y)*H(s) for s in ([b for b, r in zip(y, d) if f(r)==v] for v in set(f(r) for r in d))); print(round(H(y), 3), round(g(lambda r: r['weather']), 3), round(g(lambda r: float(r['temp_c'])>=12), 3))"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Para ir más lejos: el umbral de temperatura
Una pregunta numérica tiene un umbral. Prueba 8, 10, 12, 14 y 16 grados con el programa de la lección. ¿Cuál da más ganancia? Así decide un árbol dónde cortar una columna numérica.