Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Metodologı́as de Programación II Arboles de Decisión en Lisp Dr. Alejandro Guerra-Hernández Departamento de Inteligencia Artificial Facultad de Fı́sica e Inteligencia Artificial [email protected] http://www.uv.mx/aguerra Maestrı́a en Inteligencia Artificial 2012 ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Arboles de Decisión I Los árboles de decisión representan hipótesis sobre una clase, como una conjunción de disyunciones de atributos proposicionales. I Buen dı́a para jugar tenis [1]: Atributo Cielo Clase Valor nublado lluvioso soleado Húmedad alta no si Viento fuerte normal si no débil si GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Ejemplos de entrenamiento I La hipótesis explica un conjunto de casos conocido como ejemplos de entrenamiento. I Dı́as donde juego o no al tenis: dı́a ej1 ej2 ej3 ej4 ej5 ej6 ej7 ej8 ej9 ej10 ej11 ej12 ej13 ej14 cielo soleado soleado nublado lluvia lluvia lluvia nublado soleado soleado lluvia soleado nublado nublado lluvia temperatura calor calor calor templado frı́o frı́o frı́o templado frı́o templado templado templado calor templado humedad alta alta alta alta normal normal normal alta normal normal normal alta normal alta viento débil fuerte débil débil débil fuerte fuerte débil débil débil fuerte fuerte débil fuerte jugar-tenis no no si si si no si no si si si si si no GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Clasificación 1: function CLASIFICA(E: ejemplo, A: árbol) 2: Clase ← valor-atributo(raı́z(A),E); 3: if es-hoja(raı́z(A)) then 4: return Clase 5: else 6: clasifica(E, sub-árbol(A,Clase)); 7: end if 8: end function I Dado el árbol de la página anterior, el caso: hCielo = soleado, Temperatura = caliente, Humedad = alta, Viento = fuertei no clasifica como un buen dı́a para jugar tenis. GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 ID3 [2] Inducción de árboles de decisión 1: function ID3(E: ejemplos, A: atributos, C: clase) 2: AD ← ∅; Clase ← clase-mayoritaria(C,E); 3: if E = ∅ then return AD; 4: else if misma-clase(E,C) then return AD ← Clase; 5: else if A = ∅ then return AD ← Clase; 6: else 7: Mejor-Partición ← mejor-partición(E, A); 8: Mejor-Atributo ← primero(Mejor-Partición); 9: AD ← Mejor-Atributo; 10: for all Partición ∈ resto(Mejor-Partición) do 11: Valor-Atributo ← primero(Partición); 12: Sub-E ← resto(Partición); 13: agregar-rama(AD, Valor-Atributo, ID3(Sub-E, {A \ Mejor-Atributo}, C)); 14: end for 15: end if 16: end function GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Entropı́a I Si los posibles n valores del atributo v , ocurren con probabilidades P(vi,...,n ), entonces el contenido de información, o entropı́a, E está dado por: E(P(vi ), . . . , P(vn )) = n X −P(vi ) log2 P(vi ) i=1 I En nuestro caso, de 14 ejemplos 9 son positivos y 5 son negativos: 9 5 E( , ) = 0,940 14 14 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Ganancia de información I Es la reducción de la entropı́a causada por particionar un conj. de entrenamiento S, con respecto a un atributo a ∈ A: ganancia(S, a) = E(S) − X |Sv | v ∈a |S| E(Sv ) I Observen que el segundo término de ganancia/2, es la entropı́a con respecto al atributo a. I Para nuestro ejemplo: ganancia(S, cielo) = 0,24674976 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Mejor atributo I 1 2 3 4 5 Aquel que maximiza la ganancia de información: Information gain of Information gain of 0.029222548 Information gain of Information gain of Highest information attribute CIELO : 0.24674976 attribute TEMPERATURA : attribute HUMEDAD : 0.15183544 attribute VIENTO : 0.048126936 gain: 0.24674976 ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Arboles de Decisión I Podemos representarlos como una lista de listas: CL-USER> (setq arbol ’(cielo (soleado (humedad (normal si) (alta no))) (nublado si) (lluvia (viento (fuerte no) (debil si))))) (CIELO (SOLEADO (HUMEDAD (NORMAL SI) (ALTA NO))) ( NUBLADO SI) (LLUVIA (VIENTO (FUERTE NO) (DEBIL SI )))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Funciones de acceso sobre árboles CL-USER> CIELO CL-USER> (HUMEDAD CL-USER> SI CL-USER> NIL CL-USER> T (root arbol) (sub-tree arbol ’soleado) (NORMAL SI) (ALTA NO)) (sub-tree arbol ’nublado) (leaf (sub-tree arbol ’soleado)) (leaf (sub-tree arbol ’nublado)) Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Implementación funciones de acceso al árbol 1 2 (defun root(Tree) (car Tree)) 3 4 5 (defun sub-tree(Tree Attribute-Value) (second (assoc Attribute-Value (cdr Tree)))) 6 7 8 (defun leaf(Tree) (atom Tree)) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos ¿Cómo funciona assoc? CL-USER> (assoc (UNO 1) CL-USER> (assoc (DOS 2) CL-USER> (assoc (LLUVIA (VIENTO ’uno ’((uno 1) (dos 2) (tres 3))) ’dos ’((uno 1) (dos 2) (tres 3))) ’lluvia (cdr arbol)) (FUERTE NO) (DEBIL SI))) Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Imprimiendo el árbol CL-USER> (print-tree arbol) CIELO - SOLEADO HUMEDAD - NORMAL -> SI - ALTA -> NO - NUBLADO -> SI - LLUVIA VIENTO - FUERTE -> NO - DEBIL -> SI NIL Carga de Archivos Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Definiendo print-tree 1 2 3 4 5 6 7 8 9 10 11 (defun print-tree (tree &optional (depth 0)) (mytab depth) (format t "˜A˜ %" (first tree)) (loop for subtree in (cdr tree) do (mytab (+ depth 1)) (format t "- ˜A" (first subtree)) (if (atom (second subtree)) (format t " -> ˜A˜ %" (second subtree)) (progn (terpri) (print-tree (second subtree) (+ depth 5)))))) 12 13 14 (defun mytab (n) (loop for i from 1 to n do (format t " "))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Ejemplos de entrenamiento I Aunque los ejemplos también pueden representarse como una lista de listas, esto no es buena idea. I Necesitamos una representación que nos permita relacionar un ejemplo dado, con el valor de un atributo dado. Supongan que *examples* es mi repositorio de ejemplos: CL-USER> (get-value ’cielo (car *examples*)) LLUVIA GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Ejemplos, atributos y valores 1 2 (defun put-value (attr inst val) (setf (get inst attr) val)) 3 4 5 (defun get-value (attr inst) (get inst attr)) CL-USER> (put-value ’nombre ’ej1 ’alejandro) ALEJANDRO CL-USER> (get-value ’nombre ’ej1) ALEJANDRO CL-USER> (setq *ejemplos* nil) NIL CL-USER> (push ’ej1 *ejemplos*) (EJ1) CL-USER> (get-value ’nombre (car *ejemplos*)) ALEJANDRO Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Archivos de ejemplos: ARFF y CSV I Un archivo tenis.arff: @RELATION jugar-tenis @ATTRIBUTE @ATTRIBUTE @ATTRIBUTE @ATTRIBUTE @ATTRIBUTE cielo {soleado,nublado,lluvia} temperatura {calor,templado,frio} humedad {alta,normal} viento {debil,fuerte} jugar-tenis {si,no} @DATA soleado, calor, alta, debil, no soleado, calor, alta, fuerte, no nublado, calor, alta, debil, si lluvia, templado, alta, debil, si ... Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 With a little help from your friends I ASFD2 (Another System Definition Facility 2) es una herramienta para describir como están organizados los archivos fuente de un sistema Lisp. I En particular sus dependencias. I Quiklisp es una herramienta que nos permite instalar librerı́as que han sido definidas usando ASDF2. GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Instalando ASDF2 I http://common-lisp.net/project/asdf/ I Descargar la fuente asdf.lisp ó el tarball con la distribución completa del sistema. I Compilar éste archivo I Agregar la siguiente lı́nea al archivo .lispworks o el archivo de inicialización de cualquier otro Lisp: #-:asdf (load "˜/lisp/asdf/asdf") 1 I Si el sı́mbolo ASDF no está definido, Lisp cargará el sistema. ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Instalando Quicklisp I http://www.quicklisp.org/beta/ I Descargar el archivo quicklisp.lisp I Cargarglo en Lisp, evaluar: (ql:add-to-init-file) I Quicklisp se cargará cada vez que llamemos a Lisp! GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Instalando librerı́as: trivial-shell 1 2 3 4 5 6 7 8 9 10 11 12 CL-USER> (ql:quickload "trivial-shell") To load "trivial-shell": Install 1 Quicklisp release: trivial-shell ; Fetching #<QL-HTTP:URL "http://beta.quicklisp.org/archive /trivial-shell/2011-05-22/trivial-shell-20110522-http. tgz"> ; 13.61KB ================================================== 13,937 bytes in 0.00 seconds (13610.35KB/sec) ; Loading "trivial-shell" [package com.metabang.trivial-timeout]............ [package trivial-shell].. ("trivial-shell") ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 GUI Ejecutando comandos shell: grep 1 2 3 4 5 6 7 8 9 CL-USER> (trivial-shell:shell-command "egrep \"@ATTR\" tenis.arff") "@ATTRIBUTE cielo {soleado,nublado,lluvia} @ATTRIBUTE temperatura {calor,templado,frio} @ATTRIBUTE humedad {alta,normal} @ATTRIBUTE viento {debil,fuerte} @ATTRIBUTE jugar-tenis {si,no} " NIL 0 Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Partiendo cadenas: split-sequence 1 2 3 4 5 6 7 8 9 10 11 12 13 CL-USER> (ql:quickload "split-sequence") To load "split-sequence": Install 1 Quicklisp release: split-sequence ; Fetching #<QL-HTTP:URL "http://beta.quicklisp.org/archive/ split-sequence/2011-08-29/split-sequence-1.0.tgz"> ================================================== 2,580 bytes in 0.00 seconds (2519.53KB/sec) ; Loading "split-sequence" [package split-sequence] ("split-sequence") CL-USER> (split-sequence:split-sequence #\, "hola, que, tal") ("hola" " que" " tal") 14 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Ensamblando cajitas 1 2 3 4 5 CL-USER> (split-sequence:split-sequence #\Newline (trivial-shell: shell-command "egrep \"@ATTR\" tenis.arff")) ("@ATTRIBUTE cielo {soleado,nublado,lluvia}" "@ATTRIBUTE temperatura {calor,templado,frio}" "@ATTRIBUTE humedad {alta,normal}" "@ATTRIBUTE viento {debil,fuerte}" " @ATTRIBUTE jugar-tenis {si,no}" "") 184 ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Variables globales 1 2 3 4 5 (defvar (defvar (defvar (defvar (defvar *attributes* nil "The attributes of the problem") *domains* nil "The domain of the attributes") *target* nil "The target concept") *examples* nil "The training set") *trace* nil "Trace the computations") ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Datos crudos 1 2 3 4 5 6 7 8 9 10 11 (defun get-data (arff) (mapcar #’(lambda(x) (mapcar #’read-from-string (split-sequence:split-sequence #\, x))) (butlast (split-sequence:split-sequence #\Newline (trivial-shell:shell-command (concatenate ’string "egrep -v \"ˆ$|[@ %]\" " arff)))))) GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras get-data CL-USER> (get-data "tenis.arff") ((SOLEADO CALOR ALTA DEBIL NO) (SOLEADO CALOR ALTA FUERTE NO) (NUBLADO CALOR ALTA DEBIL SI) (LLUVIA TEMPLADO ALTA DEBIL SI) (LLUVIA FRIO NORMAL DEBIL SI) (LLUVIA FRIO NORMAL FUERTE NO) (NUBLADO FRIO NORMAL FUERTE SI) ( SOLEADO TEMPLADO ALTA DEBIL NO) (SOLEADO FRIO NORMAL DEBIL SI) (LLUVIA TEMPLADO NORMAL DEBIL SI) (SOLEADO TEMPLADO NORMAL FUERTE SI) (NUBLADO TEMPLADO ALTA FUERTE SI) (NUBLADO CALOR NORMAL DEBIL SI) (LLUVIA TEMPLADO ALTA FUERTE NO)) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Clase a predecir 1 2 3 4 5 6 7 8 9 10 11 12 13 1 2 3 (defun get-target (arff) (read-from-string (car (cdr (split-sequence:split-sequence #\Space (car (butlast (split-sequence:split-sequence #\Newline (trivial-shell:shell-command (concatenate ’string "egrep \"@rel|@REL\" " arff)))))))))) CL-USER> (get-target "tenis.arff") JUGAR-TENIS 11 Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Dominios 1 2 3 (defun get-domain (attribute) (nth (position attribute *attributes*) *domains*)) Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Todo junto 1 2 3 4 5 6 7 8 9 10 11 12 13 14 (defun id3-load (arff) (let ((data (get-data arff)) (attribs-doms (get-attribs-doms arff))) (setf *gensym-counter* 1) (setf *attributes* (mapcar #’car attribs-doms)) (setf *domains* (mapcar #’cadr attribs-doms)) (setf *target* (get-target arff)) (loop for d in data do (let ((ej (gensym "ej"))) (setf *examples* (cons ej *examples*)) (loop for attrib in *attributes* as v in d do (put-value attrib ej v)))) (format t "Training set initialized"))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Ejecución 1 2 3 4 5 6 7 8 9 CL-USER> (id3-load "/Users/aguerra/Desktop/Dropbox/2012mpii/codigo/clase06/tenis.arff") Training set initialized NIL CL-USER> *examples* (#:|ej14| #:|ej13| #:|ej12| #:|ej11| #:|ej10| #:|ej9| #:| ej8| #:|ej7| #:|ej6| #:|ej5| #:|ej4| #:|ej3| #:|ej2| #:|ej1|) CL-USER> *attributes* (CIELO TEMPERATURA HUMEDAD VIENTO JUGAR-TENIS) CL-USER> *domains* ((SOLEADO NUBLADO LLUVIA) (CALOR TEMPLADO FRIO) (ALTA NORMAL) (DEBIL FUERTE) (SI NO)) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Y el reseteo 1 2 3 4 5 6 7 8 (defun id3-reset () (setf *examples* nil *target* nil *attributes* nil *domains* nil *trace* nil *root* nil) (format t "The ID3 setting has been reset.")) Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Definición de un sistema ASDF: cl-id3.asd 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 (asdf:defsystem :cl-id3 :depends-on (:split-sequence) :components ((:file "cl-id3-package") (:file "cl-id3-algorithm" :depends-on ("cl-id3-package")) (:file "cl-id3-load" :depends-on ("cl-id3-package" "cl-id3-algorithm")) (:file "cl-id3-classify" :depends-on ("cl-id3-package" "cl-id3-algorithm" "cl-id3-load")) (:file "cl-id3-cross-validation" :depends-on ("cl-id3-package" "cl-id3-algorithm" "cl-id3-load" "cl-id3-classify")) (:file "cl-id3-gui" :depends-on ("cl-id3-package" "cl-id3-algorithm" "cl-id3-load" "cl-id3-classify" "cl-id3-cross-validation")))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Definiendo un paquete: cl-id3-package 1 2 3 4 5 6 7 8 9 (defpackage :cl-id3 (:use :cl :capi :split-sequence) (:export :load-file :induce :print-tree :classify :classify-new-instance :cross-validation :gui)) Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Leyendo archivos: cl-id3-load 1 (in-package :cl-id3) 2 3 ;;; Auxiliar functions 4 5 6 7 8 9 10 (defun read-lines-from-file (file) "It reads the FILE into a list of strings" (remove-if (lambda (x) (equal x "")) (with-open-file (in file) (loop for line = (read-line in nil ’end) until (eq line ’end) collect line)))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 GUI Portabilidad: Bye, bye grep 1 2 3 4 5 6 7 8 (defun arff-get-data (lines) "It extracts the value for *data* from the lines of a ARFF file" (mapcar #’(lambda(x) (mapcar #’read-from-string (split-sequence #\, x))) (remove-if (lambda (x) (string-equal "@" (subseq x 0 1))) lines))) 9 10 11 12 13 14 (defun csv-get-data (lines) "It extracts the value for *data* from the lines of a CSV file" (mapcar #’(lambda(x) (mapcar #’read-from-string (split-sequence #\, x))) (cdr lines))) Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Ejemplo arff-get-data 1 2 CL-ID3> (arff-get-data (read-lines-from-file "tenis. arff")) ((SOLEADO CALOR ALTA DEBIL NO) (SOLEADO CALOR ALTA FUERTE NO) (NUBLADO CALOR ALTA DEBIL SI) (LLUVIA TEMPLADO ALTA DEBIL SI) (LLUVIA FRIO NORMAL DEBIL SI) (LLUVIA FRIO NORMAL FUERTE NO) (NUBLADO FRIO NORMAL FUERTE SI) (SOLEADO TEMPLADO ALTA DEBIL NO) (SOLEADO FRIO NORMAL DEBIL SI) (LLUVIA TEMPLADO NORMAL DEBIL SI) (SOLEADO TEMPLADO NORMAL FUERTE SI) (NUBLADO TEMPLADO ALTA FUERTE SI) (NUBLADO CALOR NORMAL DEBIL SI) (LLUVIA TEMPLADO ALTA FUERTE NO)) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Load 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 (defun load-file (file) "It initializes the learning setting from FILE" (labels ((get-examples (data) (loop for d in data do (let ((ej (gensym "ej"))) (setf *examples* (cons ej *examples*)) (loop for attrib in *attributes* as v in d do (put-value attrib ej v)))))) (if (probe-file file) (let ((file-ext (car (last (split-sequence #\. file)))) (file-lines (read-lines-from-file file))) (reset) (cond ((equal file-ext "arff") (let ((attribs-doms (arff-get-attribs-doms file-lines))) (setf *attributes* (mapcar #’car attribs-doms)) (setf *domains* (mapcar #’cadr attribs-doms)) (setf *target* (arff-get-target file-lines)) (setf *data* (arff-get-data file-lines)) (get-examples *data*) (format t "Training setting initialized after ˜s.˜ %" file))) ((equal file-ext "csv") (let ((attribs-doms (csv-get-attribs-doms file-lines))) (setf *attributes* (mapcar #’car attribs-doms)) ... (t (error "File’s ˜s extension can not be determined." file)))) (error "File ˜s does not exist.˜ %" file)))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Cargando un archivo 1 2 3 4 5 6 7 8 9 10 CL-ID3> (load-file "tenis.arff") The ID3 setting has been reset. Training setting initialized after "tenis.arff". NIL CL-ID3> *target* JUGAR-TENIS CL-ID3> *attributes* (CIELO TEMPERATURA HUMEDAD VIENTO JUGAR-TENIS) CL-ID3> *examples* (#:|ej14| #:|ej13| #:|ej12| #:|ej11| #:|ej10| #:|ej9| #:|ej8| #:|ej7| #:|ej6| #:|ej5| #:|ej4| #:|ej3| #:|ej2| #:|ej1|) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Algoritmo principal 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 (defun id3 (examples attribs) "It induces a decision tree runing ID3 over EXAMPLES and ATTRIBS)" (let ((class-by-default (get-value *target* (car examples)))) (cond ;; Stop criteria ((same-class-value-p *target* class-by-default examples) class-by-default) ;; Failure ((null attribs) (target-most-common-value examples)) ;; Recursive call (t (let* ((partition (best-partition attribs examples)) (node (first partition))) (cons node (loop for branch in (cdr partition) collect (list (first branch) (id3 (cdr branch) (remove node attribs)))))))))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Todos somos de la misma clase? 1 2 3 4 5 6 1 2 3 4 (defun same-class-value-p (attrib value examples) "Do all EXAMPLES have the same VALUE for a given ATTRIB ?" (every #’(lambda(e) (eq value (get-value attrib e))) examples)) CL-ID3> (same-class-value-p *target* ’si *examples*) NIL CL-ID3> (same-class-value-p *target* ’no *examples*) NIL GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Valor mayoritario de Clase 1 2 3 4 5 6 7 8 9 1 2 (defun target-most-common-value (examples) "It gets the most common value for *target* in EXAMPLES" (let ((domain (get-domain *target*)) (vals (mapcar #’(lambda(x) (get-value *target* x)) examples))) (caar (sort (loop for v in domain collect (list v (count v vals))) #’(lambda(x y) (>= (cadr x) (cadr y))))))) CL-ID3> (target-most-common-value *examples*) SI ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Partición 1 2 3 4 5 6 7 8 9 10 11 12 1 2 (defun get-partition (attrib examples) "It gets the partition induced by ATTRIB in EXAMPLES" (let (result vlist v) (loop for e in examples do (setq v (get-value attrib e)) (if (setq vlist (assoc v result)) ;;; value v existed, the example e is added ;;; to the cdr of vlist (rplacd vlist (cons e (cdr vlist))) ;;; else a pair (v e) is added to result (setq result (cons (list v e) result)))) (cons attrib result))) CL-ID3> (get-partition ’cielo *examples*) (CIELO (SOLEADO #:|ej1| #:|ej2| #:|ej8| #:|ej9| #:| ej11|) (NUBLADO #:|ej3| #:|ej7| #:|ej12| #:|ej13 |) (LLUVIA #:|ej4| #:|ej5| #:|ej6| #:|ej10| #:| ej14|)) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Entropı́a 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 2 (defun entropy (examples attrib) "It computes the entropy of EXAMPLES with respect to an ATTRIB" (let ((partition (get-partition attrib examples)) (number-of-examples (length examples))) (apply #’+ (mapcar #’(lambda(part) (let* ((size-part (count-if #’atom (cdr part))) (proportion (if (eq size-part 0) 0 (/ size-part number-of-examples)))) (* -1.0 proportion (log proportion 2)))) (cdr partition))))) CL-ID3> (entropy *examples* ’jugar-tenis) 0.9402859 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 GUI Ganancia de Información 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2 (defun information-gain (examples attribute) "It computes information-gain for an ATTRIBUTE in EXAMPLES" (let ((parts (get-partition attribute examples)) (no-examples (count-if #’atom examples))) (- (entropy examples *target*) (apply #’+ (mapcar #’(lambda(part) (let* ((size-part (count-if #’atom (cdr part))) (proportion (if (eq size-part 0) 0 (/ size-part no-examples)))) (* proportion (entropy (cdr part) *target*)))) (cdr parts)))))) CL-ID3> (information-gain *examples* ’cielo) 0.2467497 Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Mejor partición 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2 3 (defun best-partition (attributes examples) "It computes one of the best partitions induced by ATTRIBUTES over EXAMPLES" (let* ((info-gains (loop for attrib in attributes collect (let ((ig (information-gain examples attrib)) (p (get-partition attrib examples))) (when *trace* (format t "Partición inducida por el atributo ˜s:˜ %˜s˜ %" attrib p) (format t "Ganancia de información: ˜s˜ %" ig)) (list ig p)))) (best (cadar (sort info-gains #’(lambda(x y) (> (car x) (car y))))))) (when *trace* (format t "Best partition: ˜s˜ %-------------˜ %" best)) best)) CL-ID3> (best-partition (remove *target* *attributes*) *examples*) (CIELO (SOLEADO #:|ej1| #:|ej2| #:|ej8| #:|ej9| #:|ej11 |) (NUBLADO #:|ej3| #:|ej7| #:|ej12| #:|ej13|) ( LLUVIA #:|ej4| #:|ej5| #:|ej6| #:|ej10| #:|ej14|)) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Induciendo un árbol 1 2 3 4 5 1 2 (defun induce (&optional (examples *examples*)) "It induces the decision tree using learning sertting" (when (not (member *target* *attributes*)) (error "The target is defined incorrectly: Maybe Weka modified your ARFF")) (id3 examples (remove *target* *attributes*))) CL-ID3> (induce) (CIELO (SOLEADO (HUMEDAD (NORMAL SI) (ALTA NO))) ( NUBLADO SI) (LLUVIA (VIENTO (FUERTE NO) (DEBIL SI )))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Y con print-tree 1 2 3 4 5 6 7 8 9 10 11 12 CL-ID3> (print-tree (induce)) CIELO - SOLEADO HUMEDAD - NORMAL -> SI - ALTA -> NO - NUBLADO -> SI - LLUVIA VIENTO - FUERTE -> NO - DEBIL -> SI NIL Carga de Archivos Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 La interfaz gráfica del sistema Carga de Archivos Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras capi:contain I 1 2 Podemos probar codigo de la GUI como sigue: CL-USER> (capi:contain (capi:display-message "CL-ID3˜ %˜ %Universidad Veracruzana˜ %Departamento de Inteligencia Artificial˜ %Sebastián Camacho No 5˜ %Xalapa, Ver., México 91000˜ %http://www. uv.mx/aguerra˜ %[email protected]")) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Variables globales (habilitar menus) 1 2 3 4 5 (defvar *examples-on* nil "t enables the examples menu") (defvar *attributes-on* nil "t enables the attributes menu") (defvar *induce-on* nil "t enables the induce menu") (defvar *classify-on* nil "t enables the classify menu") (defvar *cross-validation-on* nil "t enables the cross-validation menu") GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Ventana principal: paneles de texto 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 (define-interface cl-id3-gui () () (:panes (source-id-pane text-input-pane :accessor source-id-pane :text "" :enabled nil) (num-attributes-pane text-input-pane :accessor num-attributes-pane :text "" :enabled nil) (num-examples-pane text-input-pane :accessor num-examples-pane :text "" :enabled nil) (class-pane text-input-pane :accessor class-pane :text "" :enabled nil) (efficiency-pane text-input-pane :text "" :enabled nil) (k-value-pane text-input-pane :text "0")... Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Ventana principal: Otros paneles 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ... (tree-pane graph-pane :title "Decision Tree" :title-position :frame :children-function ’node-children :edge-pane-function #’(lambda(self from to) (declare (ignore self from)) (make-instance ’labelled-arrow-pinboard-object :data (princ-to-string (node-from-label to)))) :visible-min-width 450 :layout-function :top-down) (state-pane title-pane :accessor state-pane :text "Welcome to CL-ID3.")) ... Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras ID3 Ventana principal: Menus 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ... (:menus (file-menu "File" (("Open" :selection-callback ’gui-load-file :accelerator #\o) ("Quit" :selection-callback ’gui-quit :accelerator #\q))) (view-menu "View" (("Attributes" :selection-callback ’gui-view-attributes :accelerator #\a :enabled-function #’(lambda (menu) (declare (ignore menu)) *attributes-on*)) ("Examples" :selection-callback ’gui-view-examples :accelerator #\e :enabled-function #’(lambda (menu) (declare (ignore menu)) *examples-on*)))) GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Ventana principal: Menus 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ... (id3-menu "id3" (("Induce" :selection-callback ’gui-induce :accelerator #\i :enabled-function #’(lambda (menu) (declare (ignore menu)) *induce-on*)) ("Classify" :selection-callback ’gui-classify :accelerator #\k :enabled-function #’(lambda (menu) (declare (ignore menu)) *classify-on*)) ("Cross-validation" :selection-callback ’gui-cross-validation :accelerator #\c :enabled-function #’(lambda (menu) (declare (ignore menu)) * cross-validation-on*)))) (help-menu "Help" (("About" :selection-callback ’gui-about)))) (:menu-bar file-menu view-menu id3-menu help-menu) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Ventana principal: Layouts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 (:layouts (main-layout column-layout ’(panes state-pane)) (panes row-layout ’(info-pane tree-pane)) (titles column-layout ’()) (matrix-pane row-layout ’(titles confusion) :title "Confusion Matrix" :x-gap ’10 :y-gap ’30 :title-position :frame :visible-min-width ’200) (confusion grid-layout ’()) (info-pane column-layout ’(setting-pane id3-pane matrix-pane)) (setting-pane grid-layout ’("Source File" source-id-pane "No. Attributes" num-attributes-pane "No. Examples" num-examples-pane "Class" class-pane) :y-adjust :center :title "Trainning Set" :title-position :frame :columns ’2) (id3-pane grid-layout ’("K value" k-value-pane "Efficiency" efficiency-pane) :y-adjust :center :title "Cross Validation" :title-position :frame :columns ’2)) Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Ventana principal: datos iniciales 1 2 3 4 (:default-initargs :title "CL-ID3" :visible-min-width 840 :visible-min-height 600)) Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Llamadas: gui-load-file 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 (defun gui-load-file (data interface) (declare (ignore data)) (let ((file (prompt-for-file nil :filter "*.arff" :filters ’("WEKA files" "*.arff" "Comme Separated Values" "*.csv")))) (when file (let* ((path (princ-to-string file)) (setting (car (last (split-sequence #\/ path))))) (load-file path) (setf (text-input-pane-text (source-id-pane interface)) setting) (setf (text-input-pane-text (num-attributes-pane interface)) (princ-to-string (length *attributes*))) (setf (text-input-pane-text (num-examples-pane interface)) (princ-to-string (length *examples*))) (setf (text-input-pane-text (class-pane interface)) (princ-to-string *target*)) (setf (title-pane-text (state-pane interface)) (format nil "The setting ˜s has been loaded" path)) (setf *examples-on* t *attributes-on* t *induce-on* t))))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Llamadas: gui-quit 1 2 3 (defun gui-quit (data interface) (declare (ignore data)) (quit-interface interface)) Carga de Archivos Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Llamadas: gui-view-attributes 1 1 2 3 4 5 6 7 8 9 (defun gui-view-attributes (data interface) (declare (ignore data interface)) (let* ((max-length-attrib (apply #’max (mapcar #’length (mapcar #’princ-to-string *attributes*)))) (pane-total-width (list ’character (* max-length-attrib (+ 1 (length *attributes*))))))... ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Llamadas: gui-view-attributes 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 (define-interface gui-domains () () (:panes (attributes-pane multi-column-list-panel :columns ’((:title "Attrib/Class" :adjust :left :visible-min-width (character 10)) (:title "Attributes" :adjust :left :visible-min-width (character 20)) (:title "Domains" :adjust :left :visible-min-width (character 20))) :items (loop for a in *attributes* collect (list (if (eql *target* a) ’c ’a ) a (get-domain a))) :visible-min-width pane-total-width :visible-min-height :text-height :vertical-scroll t) (button-pane push-button :text "Close" :callback ’gui-quit)) (:default-initargs :title "CL-ID3:attributes")) (display (make-instance ’gui-domains)))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Dibujando el árbol: listas → nodos 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 (defstruct node (inf nil) (sub-trees nil) (from-label nil)) (defun make-tree (tree-as-lst) "It makes a tree of nodes with TREE-AS-LST" (make-node :inf (root tree-as-lst) :sub-trees (make-sub-trees (children tree-as-lst)))) (defun make-sub-trees (children-lst) "It makes de subtrees list of a tree with CHILDREN" (loop for child in children-lst collect (let ((sub-tree (second child)) (label (first child))) (if (leaf-p sub-tree) (make-node :inf sub-tree :sub-trees nil :from-label label) (make-node :inf (root sub-tree) :sub-trees (make-sub-trees (children sub-tree)) :from-label label))))) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Dibujando el árbol 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 (defmethod print-object ((n node) stream) (format stream "˜s " (node-inf n))) (defun display-tree (root interface) "It displays the tree with ROOT in its pane in INTERFACE" (with-slots (tree-pane) interface (setf (graph-pane-roots tree-pane) (list root)) (map-pane-children tree-pane ;;; redraw panes correcting x/y-adjustments (lambda (item) (update-pinboard-object item))))) (defun node-children (node) "It gets the children of NODE to be displayed" (let ((children (node-sub-trees node))) (when children (if (leaf-p children) (list children) children)))) ;;; induce (defun gui-induce (data interface) "It induces the decisicion tree and displays it in the INTERFACE" (declare (ignore data)) (setf *current-tree* (induce)) (display-tree (make-tree *current-tree*) interface)) ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Función principal 1 2 3 (defun gui () (reset) (display (make-instance ’cl-id3-gui))) Mejoras ID3 GUI Introducción Representaciones Librerı́as ASDF2 Carga de Archivos Mejoras Bibliografı́a T. Mitchell. Machine Learning. Computer Science Series. McGraw-Hill International Editions, Singapore, 1997. J. Quinlan. Induction of decision trees. Machine Learning, 1(1):81–106, 1986. ID3 GUI