UNIVERSIDAD AUTONOMA METROPOLITANA
UNIDAD IZTAPALAPA
CIENCIAS BASICAS E INGENIEHA
LIC. EN COMPUTACION
TLASIFICACIÓN POR ARBOLES DE DECISION. ’’
México D. F. Febrero de I99 7.
UNIVERSIDAD A UTONOMA METROPOLITANA
UNIDAD IZTAPALAPA
CIENCIAS BASICAS E INGENIERIA
LIC. EN COMPUTACION
“CLASIFICACION POR ARBOLES DE DECISION. ”
ALUMNAS :
AMADOR CUEVAS SARA ROSA. SALAS HERNANDEZ ELIZABETH M.
PROFESORA : & Y I ~ ~-~C.,&QJ).
C2@?Ol)
ALMA EDITH MARTINEZ LICONA
México D. F. Febrero de I997
......._. ..... ....._... .:..:: ..._ ............._..... .._. . .. i................. . .../.... .:... :. . ..:. . .. ... . . . . . . . . . . ... ..... . .. . . . . . . . . . . . . . . . . . . . . . . .:.. .__. _ _ ._,... > ..._.._. ..............,.. ”....,. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .,. ... ................................................. . . . . . . . . . . ...... . . . . . . . . . . . . . ..... .. ,
I N D I C E
Introduccion. Capítulo l. Instalación del clasificador de casos.
Requerimientos mínimos del sistema. Instalación.
Capítulo 2. Ejecución del clasificador de casos. Especificaciones del archivo de entrada. Ejecución del Clasificador de Casos.
Capítulo 3. Salida del Clasificador de Casos. Reglas de producción.
9 9
10 22
13 13
INTRODUCCION
Muchas aplicaciones de Inteligencia Artificial de practica importancia están
basados en la construcción de un modelo del conocimiento usado por un humano. En
algunos casos, las tareas que un experto realiza pueden ser pensadas como una
clasificación -asignando cosas a categorías o a clases determinadas por sus propiedades.
Por ejemplo, muchas diagnósticos médicos involucran una clasificación. En el Garvan
Institute of Medical Research, mas de 600 muestras de tiroides producidos cada año son
analizados por un sistema experto. Una muestra en particular puede contener ya
comentarios de diagnósticos, pero el proceso puede ser pensado como una secuencia de
pequeñas decisiones sobre cada una de los setenta y tantos posibles diagnósticos
comentados son relevantes para la muestra en cuestión. Cada una de tales decisiones
son conceptualmente una clasificación SVNO basada en propiedades que incluyen las
medidas de la muestra y la información de respaldo tal como la fuente de la muestra. En
un modelo de clasificación, la conexión entre clases y propiedades puede ser definida por
algunos tan simple como un flujo o un tan complicado y estructurado como un proceso
manual. Si nosotros restringimos nuestra discusión a modelos ejecutables - estos pueden
ser representados como un programa de computadora - estos son dos muy diferentes
sentidos en los que pueden ser construidos. En el presente trabajo y corno parte medular
del mismo analizaremos un algoritmo llamado ID3 el cual forma parte un conjunto de
programas llamado C4.5.
Revisemos algunos términos que serán de gran utilidad:
Descripción valor-atributo: Los datos que serán analizados deben estar en un archivo
plano -toda la información sobre un objeto o caso debe ser expresada en términos de
una colección fija de propiedades o atributos. Cada atributo puede ser discreto o tener
1
MANUAL DE USUARIO.
valores numéricos, pero los atributos usados para describir un caso deben no variar de
una caso a otro.
Clases predefinidas: Las categorías que para los casos han sido asignadas deben
haber sido establecidas con anterioridad.
Clases discretas: Este requisito tiene to do con las categorías que para cada caso esta
asignado. Las clases deben ser cuidadosamente delineadas -cada caso pertenece o no
a una clase en particular - y este debe tener mas casos que clases. Un grupo de tareas
que no tienen clases discretas son considerados con predicción de valores continuos
tal como el precio del oro o la temperatura a la cual una aleación se fundirá.
Similarmente tareas en las cuales clases con valores continuos son rotas dentro de
categorías tal como duro, flexible, suave deben ser aproximadas con cuidado.
Datos suficientes: Procesos de generalización inductiva para identificar patrones en
datos, como nota acerca de esto. El tema fundamental si vale, patrones robustos no
pueden ser distinguidos con coincidencias cambiantes. Como esta diferenciación
usualmente depende de pruebas estadísticas de un género u otro, deben ser
suficientes casos los que pertenezcan a estas pruebas para que estas sean efectivas.
La cantidad de datos requerido es afectado por factores tal como el numero de
propiedades y clases y la complejidad del modelo de clasificación; cuando este
aumenta, mas datos serán necesarios para construir un modelo formal, Un modelo
sencillo puede algunas veces ser identificado con un manojo de casos, pero un modelo
de clasificación detallado usualmente requiere cientos o algunos miles de casos
preparados.
Modelos lógicos de clasificación: El programa construye solo clasificadores que
pueden ser expresados como un árbol de decisión o conjuntos de reglas de
producción. Estas formas, esencialmente restringen la descripción de una clase a una
expresión lógica donde las primitivas son sentencias sobre 10s valores de atributos
Particulares. Una forma común de modelo de clasificación que no satisface este
requerimiento es el discriminante lineal.
2
INTRODUCCION
Ahora revisemos algunos temas que facilitaran el entendimiento del programa
desarrollado.
0 Arboles de decisión: Este programa genera una clasificación en la forma de un &bol
de decisión, una estructura que es :
a) una hoja, que indicaría un clase, o
b) un nodo de decisión, que indicaría algunas pruebas que contiene el valor de un atributo
simple, con una rama y un subarbol por cada posible resultado de la prueba.
Un árbol de decisión puede ser usado para clasificar un caso comenzando por la raíz del
árbol y moviéndose atravez de este hasta que una hoja es encontrada. En cada nodo de
decisión (no una hoja), los resultados del caso para la prueba, en el nodo son
determinados por la raíz del subarbol correspondiente a su resultado. Donde estos
procesos finalmente nos llevan a una hoja, la clase del caso es determinada por el
recorrido hacia la hoja.
3
CAPITULO 1 INSTALACION
INSTALACIóN DEL CLASIFICADOR DE CASOS.
REQUERIMIENTOS MíNIMOS DEL SISTEMA.
Antes de realizar la instalación del CLASlflCADOR DE CASOS es necesario que
se asegure de que su sistema de computo cuente con las siguientes características
mínimas:
8 El disco para realizar la instalación del CLASlFlCADOR DE CASOS.
8 8 megabytes de memoria RAM.
8 Un procesador 386SX para agilizar la ejecución.
e Sistema operativo MS-DOS versión 3.3.
8 Microsoft Windows 3.1.
8 Un drive A de alta densidad de 3.5”.
8 9 Mb de espacio disponible en disco duro, para almacenar el software.
8 Un monitor de resolución EGA (recomendado uno VGA a colores).
0 Un mouse que sea soportado por la versión de Windows con la que cuente
INSTALACI~N.
Para instalar el CLASIFICADOR DE CASOS realize los siguiente pasos:
1. Introduzca el disco número 3 que contiene el archivo de instalación en la
unidad A de 3.5”
2. Cambie a la raíz de la unidad C y asegurece que no exista el directorio
C:\PROYECTO, de existir este renombrelo.
3. Teclee la siguiente línea de comando
C:\A:INSTALA
4. El sistema le irá pidiendo los discos de instalación conforme los vaya
necesitando.
5
MANUAL DE USUARIO
5. Entre a WINDOWS. Desde el Administrador de Programas de Windows
proceda como lo muestran las siguientes figuras:
Haga "click" en la opción - Nuevo
Haga "click" en el botón Aceptar
CAPITULO I INSTALACION
Teclee la palabra PROYECTO en la línea Descripción y haga "cllck" en Aceptar.
Haga "click" en la opción - Nuevo
$T&$:.:.:.:.:.:.:..:: :. .. i".".
. . . . . . . . . . , . . . . . . . . . . . .
MANUAL DE USUARIO
Haga “click” en el botón Aceptar
En Descripción teclee CLASIFICADOR y en la Línea de comando C:\PROYECTO\PROYECTO.EXE, después haga “click” en el botón - Cambiar icono para selecionar una imagen, haga “click” en Aceptar.
Archivo Opciones Yeniana Ayuda Administrador de proqrarnas
L ínea de comando: IC~\moyEcro\PROYFCTO E
I ” I , . . ................ #mFj ...... ..*.:.... , ,
8
CAPITULO 2 EECUCION DEL CLASIFICADOR
EJECUCIóN DEL CLASIFICADOR DE CASOS.
Para poder ejecutar el CLASlFlCADOR DE CASOS es necesario contar con el
archivo que contenga los casos que se clasificaran.
a) Especificaciones del archivo de entrada.
1. Debe ser un archivo tipo texto (con extensión “txt”) escrito en un editor de
palabras no muy sofisticado, es decir, un editor que no introduzca caracteres
especiales dentro del formato de escritura y de guardado.
2. Debe ser escrito en forma sencilla, no debe contener titulos ni frases centradas.
3. Debe contener como primer renglon los nombres de los atributos separados por
un espacio solamente, colocando la palabra “clase” como última columna.
4. Los casos deben ser escritos en forma horizontal, es decir, se escribirán los
valores de los atributos separados por un espacio y al final la clase a la que
pertenece el caso, no se permiten casos que contengan valores desconocidos en
algún atributo.
5. Los casos deben ser separados por un ENTER.
6. En caso de introducir valores numéricos éstos deberan ser escritos en forma
común, es decir, se deberá escribir la cifra incluyendo el punto decimal si así lo
requiere.
9
MANUAL DE USUARIO
Un ejemplo de un archivo de entrada sería:
outlook temp humidity windy class
sunny 75 70 true play
overcast 81 75 false play
sunn!^ 85 85 false !play
rain 68 80 false play
sumy 69 70 false play
rain 75 80 false play
overcast 72 90 false play
rain 70 96 true play
sulug~ 80 90 true !pia\.
overcast 64 65 true pia!.
rain 71 80 true !play
overcast 83 75 false p lq .
rain 65 70 true !play
sulmy 72 95 false !play
b) Ejecución del CLASlflCADOR DE CASOS.
Una vez de que este seguro de que el formato del (los) archivo (S) de entrada
cumplen con lo especificado anteriormente se debe ejecutar el clasificador, para esto se
debe proceder como sigue:
De “click” en el icono correspondiente al CLASIFICADOR.
CAPITULO 2 EJECUCION DEL CLASIFICADOR
Haga menú
“click’ en la opción Abrir del - Procesamiento
inicia Aplicacion: Procesamiento del archivo que contiene los casos a clasificar. Revisión Archivos: Visualización de archivos con extensión TXT. Salir: Finalizar el procesamiento.
Seleccione la unidad, el directorio y el nombre del archivo que se procesará, y espere
unos momentos. En caso de desear visualizar los archivos generados que contienen las
reglas de producción seleccione el botón correspondiente.
Para dar por terminada la aplicación haga “click> en el botón Salir de la ventana
Procesamiento de Archivos,después seleccione la opción Salir del menú Archivo.
11
CAPITULO 3
SALIDA DEL CLASIFICADOR DE CASOS:
Como resultado de la ejecución del clasificador son generados dos archivos tipo
texto que son:
1. REGLASN.TXT. Contiene las reglas de producción obtenidas del recorrido del árbol
generado a partir del archivo de entrada.
2. REGLASP.TXT. Contiene las reglas de producción obtenidas del recorrido del árbol
podado derivado del árbol original.
En donde la interpretación de ambos archivos será la siguiente:
Si outlook = overcast entonces Play
Si outlook = rain y windy = false entonces Play
Si outlook = rain y windy = true entonces !Play
Si outlook = sunny y humidity <=82.00 entonces Play
Si outlook = sunny y humidity ~ 8 2 . 0 0 entonces !Play
Las palabras en negritas no incluyen en el archivo, pero es la interpretación que
se deberá dar al leer las reglas de producción.
I N D I C E
Introduccion. Capítulo 1. Construyendo árboles de decisión.
Divide y vencerás Una ilustración Evaluación de pruebas Criterio de ganancia Criterio de razón de ganancia
Capítulo 2. De los arboles a las reglas. Generalizando reglas simples Clase conjunto de reglas. Clasificando clase y escogiendo una por default.
Capítulo 3. Podando arboles de decisión. ¿Cuándo simplificar?. Error basado en el podado. Ejemplo: Demócratas y Republicanos. Estimación de porcentajes de error para arboles
Capítulo 4. Implementación del algoritmo ID3. Estructuras utilizadas Descripción del programa Código fuente
13 16 17 22
27 28 30 34 35
37 37 40 43
INTRODUCCION
INTRODUCCION
En el presente trabajo y como parte medular del mismo analizaremos un
algoritmo llamado ID3 el cual forma parte de un conjunto de programas llamado C4.5.
La base de clasificación de estos programas es un metodo inductivo.
Se mencionará el algoritmo y se explicará la implementación, que se realizara
en el presente trabajo, mencionaremos las estructuras utilizadas para su
implementación as¡ como la interpretación de los resultados obtenidos con la
ejecución del algoritmo añadiendo el archivo fuente..
1
CAPITULO 1 CONSTRUYENDO ARBOLES DE DECISION
CONSTRUYENDO ARBOLES DE DECISIóN
DIVIDE Y VENCERAS El esqueleto del método de Hunt's para la construcción de árboles de decisión de
un conjunto T de casos preparados es elegantemente simple. Sean las clases
denotadas por { C I , C2, . . . , Ck}. Se tienen tres posibilidades:
O T contiene uno o más casos, todos pertenecientes a una clase simple Cj: El árbol
de decisión para T es una hoja que identifica a la clase Cj
O T no contiene casos: El árbol de decisión es nuevamente una hoja, pero la clase
asociada con la hoja debe ser determinada de otra información distinta a la de T. Por
ejemplo, la hoja deber ser escogida de acuerdo con algún conocimiento profundo del
dominio, tal como la clase global mayoritaria. C4.5 usa la clase más frecuente de el
padre de este nodo.
0 T contiene casos que pertenecen a una mezcla de clases: En esta situación la
idea es depurar T en subconjuntos de casos que son, o que parecen ser dirigidos
hacia, colecciones de clases simples de casos. Una prueba T 70 es escogida,
basada en un atributo simple, que tiene una o más salidas mutuamente exclusivas {
O,, O2 , . . . , O, }. T es dividido en subconjuntos T,, T2 ,...., T,, donde Ti contiene todos los
casos en T que tiene salida Oi de la prueba elegida. El árbol de decisión de T
consiste de un nodo de decisión identificando la prueba, y una rama para cada
posible salida. (The same tree-building machinery). El mismo mecanismo de
construcción de árboles es aplicado recursivamente a cada subconjunto de casos
preparados, tal que la i-ésima rama conduce a el árbol de decisión construido del
subconjunto Ti de casos preparados.
3
MANUAL TECNICO
UNA ILUSTRACIóN
La división sucesiva del conjunto de casos procede hasta que todos los
subconjuntos consisten de casos pertenecientes de una clase simple. La ilustración
siguiente involucra el pequeño conjunto preparado de la figura 1 .I en el cual hay 4
atributos y 2 clases. Los casos han sido agrupados en el primer atributo outlook como
se puede apreciar en la figura 1.2 ,para simplificar la discusión siguiente.
figura l . I
4
CAPITULO 1 CONSTRUYENDO ARBOLES DE DECISION
Particion de casos:
outlook = sunny
I humidity <= 75
I outlook temp ('9 humidity (%) windy ? I desicion I
sunny 75 70 true Play
I sunny 69 70 false I Play I I I I
humidity > 75
outlook temp ("9 humidity (YO) windy ?
sunny 72 95 false
! play sunny 85 85 false
!play sunny 80 90 true
desicion
!play
outlook = overcast
outlook temp ("9 humidity (YO) windy ?
overcast 72 90 true
overcast 83 78 false
overcast 64 65 true
overcast 81 75 false
outlook = rain
I windy =true
desicion
outlook temp ("9 humidity (%) windy ?
rain 72 80 true
desicion
! play rain 65 70 true ! play
~
I windy = false
outlook temp ("9 humidity (%) windy ?
rain 70 96 false Play rain 68 80 false Play rain 75 80 false
desicion
Play
figura 1.2
5
MANUAL TECNICO
Puesto que estos casos no todos pertenecen a la misma clase, el algoritmo divide
y venceras intenta dividirlos en subconjuntos. Aún no se ha discutido la manera en que
una prueba es escogida, para este ejemplo, supóngase que la prueba es outlook con
tres salidas, outlook = sunny, outlook = overcast y outlook = rain. El grupo de enmedio
contiene sólo casos de clase Play pero el primero y el tercer subconjuntos todavía
tienen clases mezcladas. Si el primer subconjunto está además dividido por una prueba
sobre humidity, con salidas humidity <= 75 y humidity > 75, y el tercer subconjunto por
una prueba sobre windy, con salidas windy = true y windy = false, cada uno de los
subconjuntos puede ahora contener casos de una clase simple. Las divisiones finales
de los subconjuntos y el correspondiente árbol de decisión es mostrado en la figura 1.2
EVALUACIóN DE PRUEBAS
Cualquier prueba que divide a T en una forma no trivial, para que por lo menos
dos de los subconjuntos {Ti} no estén vacíos, eventualmente resultarán en una partición
dentro de subconjuntos de clase simple, aunque todos o más de ellos contienen un caso
preparado. Sin embargo, el proceso de construcción de árboles no tiene la intención de
sólo encontrar alguna partición, sino construir un árbol que descubra la estructura de el
dominio y así tener un poder predictivo. A causa de que, necesitamos un número
significativo de casos para cada hoja o, ponerla de otra manera, la partición debe tener
tan pocos bloques como posibles. Idealmente, nos gustaría escoger una prueba en
cada etapa para que el árbol final sea pequeño.
Puesto que estamos buscando para un árbol de decisión compacto, ¿ Porqué no
exploramos todos los posibles árboles y seleccionamos el más simple ?.
Desafortunadamente, el problema de encontrar el árbol de decisión más pequeño
consistente con el conjunto entrenador es NP-completo. Un número asombroso de
árboles podría haber sido examinado -- por ejemplo, existen más de 4 x106 árboles de
decisión que son consistentes con el conjunto pequeñito preparado de la figura 1-1 .
6
CAPITULO 1 CONSTRUYENDO ARBOLES DE DECISION
CRITERIO DE GANANCIA.
Supóngase nuevamente que tenemos una posible prueba con n salidas que
particionan al conjunto T de casos preparados en subconjuntos T,, T2, , , , , T,. Si esta
prueba es evaluada sin explorar subsecuentes divisiones de las Ti’s, la única
información disponible como guía es la distribución de clases en T y sus subconjuntos.
Ya que necesitaremos frecuentemente referirnos a la distribución de clases en esta
sección, alguna notación nos ayudará. Si S es cualquier conjunto de casos, freq(Ci,S)
representa el número de casos en S que pertenecen a la clase Ci. Usaremos también la
notación universal en la cual IS1 denota el número de casos en el conjunto S.
El experimento original CLS de Hunt consideraba varias rúbricas bajo las cuales
una prueba debe ser evaluada. Muchas de estas fueron basadas en el criterio de
fecuencia de clase. Por ejemplo, CLSl fue restringido a problemas con dos clases,
positivo y negativo, y prefería pruebas con una salida cuyo subconjunto de casos
asociados contenía:
0 Sólo casos positivos; o, aquel faltante,
0 Sólo casos negativos; o aquellos faltantes,
El mayor número de casos positivos.
Aunque su programa usaba un criterio simple en este género, Hunt sugirió que
una aproximación basada en información teórica podría tener ventajas. Cuando construí
el precursor de ID3, olvidé este sugerencia hasta que la posibilidad de usar información
basada en métodos fue promovida independientemente por Peter Gacs.
El ID3 original usaba un criterio llamado ganador, definido abajo. La información
teórica que refuerza este criterio puede ser dada en una declaración: La información
transmitida por un mensaje depende de su probabilidad y puede ser medida en bits
como menos el algoritmo en base 2 de esta probabilidad. Así, por ejemplo, si hay ocho
mensajes igualmente probables, la información transmitida por cualquiera de ellos es -
10g2(l/8) o 3 bits.
Imagine que se selecciona un caso aleatoriamente de el conjunto S de casos y se
declara que este pertenece a alguna clase C,. Este mensaje tiene probabilidad:
7
MANUAL TECNICO
f ~ ( Cj, S )
IS1
y así la información que este transmite es
- log2 freq(C,,S) bits
IS1 Para encontrar la información esperada de tal mensaje *referente a los miembros
de la clase*, sumamos sobre las clases en proporción a sus precuencias en S, dando:
Cuando aplicamos a el conjunto de casos preparados, info(T) mide la cantidad
promedio de información necesaria para identificar la clase de un caso en T. (Esta
cantidad es también conocida como la entropia de el conjunto S.)
Ahora considere una medida similar después de que T ha sido particionada de
acuerdo con las n salidas de una prueba X . La información esperada requerida puede
ser encontrada como la suma pesada sobre los subconjuntos, como:
n
info, (TI = IT,I X info(Ti) i = l IT1
La cantidad
gain(X) = info (T) - info,(T)
mide la información ganada por la partición de T de acuerdo con la prueba X. El
criterio ganador, entonces, seleccciona un conjunto para maximizar esta información
ganada ( la cual es también conocida como la información mutua entre la prueba X y la
clase ) .
Como una ilustración concreta, considere nuevamente el conjunto preparado de
la figura 1 .l. Hay dos clases, nueve casos pertenecen a Play y cinco a Don’t Play, así
info(T) = -9114 X IOg2(9/14) - 5/14 X IOg2(5/14) = 0.940 bits.
8
CAPITULO 1 CONSTRUYENDO ARBOLES DE DECISION
(Recuerde, esta representa la información promedio necesaria para identificar la
clase de un caso en T.) Después de usar outlook para dividir T en tres subconjuntos, el
resultado es dado por
infox(T) =5/14 X (-2/5 X IOg2(2/5) - 315 X l0g2(3/5))
+ 4/14 X (-414 X IOg2(4/4) - 014 X IOg2(O/4))
+ 5/14 X (-3/5 X IOg2(3/5) - 215 X IOg2(2/5))
= 0.694 bits.
La información ganada por esta prueba es por Io tanto 0.940 - 0.694 = 0.246 bits.
Ahora suponga que, en lugar de dividir T en el atributo outlook, lo hemos particionado
en el atributo windy. Esto podría haber dado dos subconjuntos, uno con tres casos Play
y tres Don’t Play, el otro con seis casos Play y dos Don’t Play. El cálculo similar es
infoX(T) = 6/14 X (-3/6 X l0g2(3/6) - 3/6 X l0g2(3/6))
+ 8/14 x (-6/8 x 10g2(6/8) - 218 x 10g2(2/8))
= 0.892 bits.
Para una ganancia de 0.048 bits, la cual es menor que el resultado ganador de la
prueba previa. El criterio de ganancia podría entonces preferir la prueba en outlook
sobre la prueba más reciente en windy.
CRITERIO RAZóN DE GANANCIA.
Por algunos años la selección de una prueba en ID3 fue hecha en base a el
criterio de ganancia. Aunque este da bastantes buenos resultados, este criterio tiene
una seria deficiencia ( este tiene una tendencia marcada en favor de pruebas con
muchas salidas). Podemos ver esto considerando una labor de diagnóstico médico
hipotético en la cual uno de los atributos contiene una identificación del paciente. Ya
que cada identificación es pensada a ser única, particionando cualquier conjunto de
casos preparados en los valores de este atributo conducirá a un número grande de
subconjuntos, cada uno conteniendo justo un caso. Ya que todos estos subconjuntos de
casos únicos necesariamente contienen casos de una clase simple, infox(T) = O, así la
información de gananciasal usar este atributo para particionar el conjunto de casos
9
MANUAL TECNICO
preparados es máxima. Desde el punto de vista de la predicción, sin embargo, tal
dlvisión es totalmente inútil.
La tendencia inherente en el criterio de ganancia puede ser rectificada por un
género de normalización en el cual la ganancia evidente atribuible para pruebas con
muchas salidas es ajustada. Considera el volumen de información de un mensaje
perteneciente a un caso que no indica la clase a la cual pertenece el caso, excepto la
salida de la prueba. Por analogía con la definición de info(S), tenemos n
splithfo(X) = i = l
esta representa la información potencial generada por la división de T en n
subconjuntos, mientras que la información de ganancia mide la información pertinente
para la clasificación que surge de la misma división. Entonces,
gain ratio (X) = gain (X) / split info (X)
expresa la proporción de información generada por la división que es útil, es decir, que
parece útil para clasificación. Si la divisón es casi trivial, la información dividida será
pequeña y esta razón será inestable. Para evitar esto, el criterio de razón de ganancia
selecciona una prueba para maximizar la razón de arriba, sujeta a la restricción de que
la información de ganancia debe ser grande ( por lo menos tan grande como el
promediode ganancias sobre todas las pruebas examinadas).
Es evidente que el atributo de identificación del paciente no será clasificado
hondamente por este criterio. Si hay k clases, como antes, el numerador (información de
ganancia) es cuando más log2(k). El denominador, en cambio, es log2(n) donde n es el
número de casos preparados, ya que cada caso tiene una única salida. Parece
razonable suponer que el número de casos preparados es mucho más grande que el
número de clases, así la razón debería tener un valor pequeño.
Para continuar la ilustración previa, la prueba en outlook produce tres
subconjuntos conteniendo cinco, cuatro, y cinco casos respectivamente. La información
dividida es calculada como
10
CAPITULO 1 CONSTRUYENDO ARBOLES DE DECISION
-5/14 X l0g2(5/14) - 4/14 X IOg2(4/I 4) - 511 4 X IOg2(5/I 4)
o 1.577 bits. Para esta prueba, cuya ganancia es 0.246 (como antes), la razón de
ganancia es 0.246/1.577 = O. 156.
11
CAPITULO 2 DE LOS ARBOLES A LAS REGLAS
DE LOS ARBOLES A LAS REGLAS
Como se observó en la sección previa, es posible podar un árbol de decisión
para que sea más simple y más exacto. Aunque los árboles podados son más
compactos que los originales, pueden a pesar de eso ser engorrosos, complejos e
inescrutables. Si deseamos nuestra clasificación para proveer un discernimiento de
una predicción exacta en casos no vistos, hay aún una forma de hacerlo.
Los árboles de decisión grandes son difíciles de entender porque cada nodo
tiene un contexto especíifco establecido por las salidas de las pruebas de nodos
antecedentes. El árbol de decisión de la figura 2-1 a cerca de la detección de las
condiciones de hipotiroides fue generado de datos suministrados por el Instituto
Garvan de Investigación Médica en Sidney. El último nodo de la prueba TT4
measured, da la clase compensated hypothyroid si la respuesta es t, esto no sugiere
que la presencia de TT4 entre los ensayos pedidos es suficiente para diagnosticar
compensated hypothyroidism. Esta prueba tiene sentido sólo cuando lee en
conjunción con las salidas de pruebas anteriores. Cada prueba en el árbol tiene un
Único contexto que es crucial para entenderlo y puede ser verdaderamente difícil
seguir una huella de los cambios continuos de contexto mientras se busca a lo largo
del árbol.
Otra complicación surge porque la estructura del árbol puede causar
subconceptos individuales al ser fragmentado. Considere la tarea artificial simple en
la cual hay cuatro atributos binarios, F, G I J, y K, y dos clases, YES y NO. Cada
caso de clase YES tiene cualquiera de los dos F y G ambos con valor 1 , o J y K con
valor 1 , como se expresa en el árbol de decisión de la figura 2-2. El i rbo l contiene
dos subárboles idénticos de esa prueba para J y K ambos siendo 1 , Este
subconcepto simple ha sido dividido para que aparezca dos veces en el árbol, lo
cual hace al árbol más difícil de entender. La réplica no es precisamente una
13
MANUAL TECNICO
aberración de este árbol en particular ( cualquier árbol para este concepto debe
necesariamente dividir cualquiera de los dos el subconcepto F=G=I o el
subconcepto J=K=I. Hay sólo dos maneras de ir a todas partes con este problema:
definiendo atributos nuevos, y más tareas específicas tales como F=G=I, como
FRINGE, o trasladando lejos de la representación del árbol de decisión
clasificador. Esta sección se enfoca a la última aproximación.
del
I TSH <= 6: negativo
TSH > 6:
FTI <= 64:
TSH medido = f: negativo
TSH medido = t:
T4U medido = f:
TSH <= 17: hipotiroides compensada
TSH < 17: hipotiroides primaria
T4U medido = t:
cirugía de tiroides = f: hipotiroides primaria
cirugía de tiroides = t: negativo*
FTI > 64:
U
con tiroxina = t: negativo
con tiroxina = f: I I TSH medido = f: negativo
I I S H medido = t:
I cirugía de tiroides = t: negativo
cirugía de tiroides = f:
TT4 > 150: negativo
TT4 <= 150:
TT4 medida = f: hipotiroides primaria
TT4 medida = t: hipotiroides compensada
Figura 2-1. Árbol de decisión para condiciones de hipotiroides.
14
CAPITULO 2 DE LOS ARBOLES A LAS REGLAS
F = O :
I J = O : n o
J = l :
K = O : no
K = l : s i
F = l :
G = l : s i
G = O :
J = O : n o
J = l :
K = O : n o
K = l : s i
Figura 2-2. Arbol simple de decisión para F = G = 1 o J = K = 1
En cualquier árbol de decisión, la condición que debe ser satisfecha cuando
un caso es clasificado por una hoja puede ser encontrada rastreando todas las
salidas de las pruebas a lo largo de el camino de la raíz a la hoja. En el árbol de la
figura 2-2, la hoja más profunda YES es asociada con las salidas F = l , G=O, J=l I y
K= l ; cualquier caso que satisfaga estas condiciones será mapeado hacia la hoja
YES.
Podríamos de esta manera escribir “Si F= l y G=O y J= l y K=l entonces la
clase es YES’, Io cual de repente tiene la forma de la regla de producción oblicua.
De hecho, si el camino a cada hoja fuerá transformado en una regla de producción
de esta forma, la colección resultante de reglas podría clasificar casos exactamente
como el árbol lo hace. Como una consecuencia de su árbol origen, las partes “si” de
las reglas podrían ser mutuamente exclusivas y exhaustivas, así el orden de las
reglas podría no importar.
15
MANUAL TECNICO
Estamos haciendo el enfoque en reglas de producción con respecto a
algunas hojas, así podemos establecer una base más precisa para hablar acerca de
ellas. Una regla como la de arriba se escribirá:
Si F= l
G=O
J = l
K= 1
entonces clase YES
Con el entendimiento de que la condición de la regla anterior hecha arriba es
interpretada como una conjunción. Diremos que una regla cubre un caso si el caso
satisface las condiciones anteriores de la regla.
Generalizando reglas simples
Reescribiendo al árbol como una colección de reglas, una para cada hoja en
el árbol, podría no resultar en algo más simple que el árbol, ya que podría ser una
regla por cada hoja. Sin embargo, podemos ver que el antecedente de las reglas
individuales puede contener condiciones irrelevantes. En la regla de arriba, la
conclusión no es afectada por los valores de F y G. La regla puede ser
generalizada borrando esas condiciones superfluas sin afectar su exactitud, dejando
la regla más sencilla
Si J =I
K =I
entonces clase YES.
¿Cómo podemos decidir cuándo una condición puede ser borrada? Sea la regla R
es de la forma :
Si A entonces es clase C
y una regla más general R"
Si A " entonces es clase C,
16
CAPITULO 2 DE LOS ARBOLES A LAS REGLAS
donde A " es obtenida borrando una condición X de las condiciones A. La setial de
la importancia de la condición X debe ser encontrada en los casos preparados
usados para la construcción del árbol de decisión. Cada caso que satisface la
anterior A " pertenece o no pertenece a la clase designada C, y satisface o no
satisface a la condición X. El número de casos en cada uno de esos cuatro grupos
puede ser organizado dentro de una tabla eventual de 2 x 2 :
Clase C Otras clases
Satisface la condición X
E2 y2 No satisface la condición X
E1 Y1
I I I
Ya que estamos viendo sólo a los casos que satisfacen A" , aquéllos que
satisfacen la condición X también son cubiertos por la regla original R. Hay Y1+ El
de tales casos, El de ellos siendo agrupados por R ya que pertenecen a alguna otra
clase que C. Similarmente, aquéllos casos que satisfacen A " pero no a X pueden
ser cubiertos por la regla generalizada R " pero no por la regla original. Hay Y2 + E2
de ellos con E2 errores. Ya que R " también cubre todos los casos que satisface R ,
el número total de casos cubiertos por R " es Y, + El + Y2 + E2.
Mi primer experimento con reglas simplificadas usaba una prueba de
importancia en esta tabla eventual para decidir si la condición X deberá ser borrada.
CLASE CONJUNTO DE REGLAS
El proceso de generalización de reglas se repite para cada ruta en el árbol de
decisión sin simplificar. Las reglas derivadas de algunas rutas pueden tener un
índice de errror alto inaceptable o pueden duplicar reglas derivadas de otra rutas,
así el proceso usualmente produce menos reglas que el número de hojas en el
árbol.
17
MANUAL TECNICO
Una complicación causada por la generalización es que las reglas acaban
por ser mutuamente exclusivas y exhaustivas; serán casos que satisfacen las
condiciones de más de una regla o, si las reglas inexactas son descartadas, de
ninguna. Una regla de producción completa interpretada debe especificar cómo
estos casos serán clasificados. En la última situación, es convencional definir una
retirada o regla default que está en juego cuando ninguna otra regla cubre un caso.
Dediciendo que hacer en la anterior situación usualmente llamada resolución del
conflicto y adoptando el esquema de C4.5 es quizás lo más simple: las reglas son
ordenadas y la primer regla que cubre un caso es tomada como la operativa. En
consecuencia necesitamos algún método para establecer la prioridad de las reglas y
para decidir una clasificación por default.
En un trabajo anterior, desarrollé un esquema para clasificar todas las reglas
y para seleccionar un subconjunto de ellas, todas como una operación compuesta.
Aunque trabajó razonablemente bien, los conjuntos resultantes de reglas eran aún
difíciles de entender ( el orden de las reglas era importante, pero parecía arbitrario).
Supóngase que, del conjunto de todas las reglas anteriormente
desarrolladas, seleccionamos un subconjunto S de reglas para cubrir una clase
particular C. El desempeño de este subconjunto puede ser sumado por el número
de casos preparados cubiertos por S que no pertenecen a la clase C (los positivos
falsos), y el número de clase C de casos preparados que no son cubiertos por
ninguna regla en S (los negativos falsos). El valor del subconjunto S de reglas es
evaluado usando el Principio de Descripción de Longitud Mínima (MDL). Este
provee una base para compensar la exactitud de una teoría ( aquí, un subconjunto
de reglas ) , nuevamente esto es complejo.
El uso de el Principio MDL es muy simple : un Transmisor y un Receptor
ambos tienen identicas copias de un conjunto de casos preparados, pero la copia
del Transmisor también especifica la clase de cada caso mientras que en la copia
del Receptor falta toda la información de la clase. El Transmisor debe comunicar
esta información faltante a el Receptor transmitiendo una teoría de clasificación
18
CAPITULO 2 DE LOS ARBOLES A LAS REGLAS
junto con las exepciones de esta teoría. El Transmisor puede escoger la
complejidad de la teoría que envía ( una teoría relativamente simple con un número
importante de exepciones, o una teoría más completa con menos exepciones. El
Principio MDL formula que la mejor teoría derivable de los datos preparados
minimizará el número de bits requeridos para codificar el mensaje total consistente
en la teoría junto con sus exepciones asociadas.
La información que ha sido transmitida aquí es la identidad de los casos
preparados pertenecientes a la clase C, usando algún esquema de codificación
para la teoría (subconjunto S de reglas) y exepciones. El esquema usado por el
sistema es aproximado, ya que intenta encontrar un límite inferior en el número de
bits en alguna codificación en lugar de escoger una codificación particular. La idea
general puede ser resumida como sigue:
Codificar una regla, debemos especificar cada condición en su lado
izquierdo. El lado derecho no necesita ser codificado, ya que todas las reglas en el
subconjunto conciernen a la misma clase C. Hay una pequeña complicación: las
condiciones deben ser enviadas en algún orden, pero el orden no es importante ya
que las condiciones estan juntas. Si existen x condiciones en el lado izquierdo,
existen x! ordenes posibles que pueden ser enviados, todas ellas equivalentes
desde el punto de vista de especificación de la regla, Por Io tanto, los bits
requeridos para enviar algún orden en particular debe ser reducido por un “crédito”
de log2(x!).
Codificar un conjunto de reglas requiere la suma de los bits para codificar
cada regla, menos un crédito similar para la clasificación de la regla (ya que todas
las clasificaciones de reglas para una clase simple son equivalentes)
Las exepciones son codificadas indicando cual de los casos cubiertos por la
regla S son positivos falsos y cuales de aquellos no cubiertos son negativos falsos.
Si la regla cubre r de los n ca S pre rados, con fp po~[os fa)ys y fn negativos
falsos, el número de bits requ lL r os p 17 a codificar las exe ¡ones S
log2 r + log2 n-r.
19
MANUAL TECNICO
f P fn
El primer término son los bits necesarios para indicar los positivos falsos
entre los casos cubiertos por las reglas y el segundo término da una expresión
similar para identificar los negativos falsos entre los casos no cubiertos.
El valor de un subconjunto S particular es medido por la suma de la longitud
del código para reglas y exepciones ( la suma más pequeña, mejora la teoría
representada por S).
A menudo los esquemas de codificación tienden a sobreestimar el número de
bits requeridos para codificar una teoría relativa a conjuntos de exepciones. Esto
puede ser explicado en parte por el hecho que conjuntos de atributos son a veces
redundandes, as¡ que diferentes teorías pueden ser funcionalmente identicas.
Mientras que el papel de una teoría para una clase es identificar un subconjunto de
los casos preparados, diferentes conjuntos de reglas que denotan el mismo
subconjunto de casos son intercambiables, aunque ellos puedan tener diferentes
codificaciones. Siguiendo Quinlan y Rivers el sistema se compenda por este efecto
por el uso de una suma pesada
bits exeptuados + W * bits teoría.
Donde W es un factor menor que uno. Ahora, un valor apropiado de W
dependerá de la probabilidad de dos teoría describiendo la misma colección de
casos, las cuales a su vez dependerán sobre el grado de redundancia en los
atributos. C4.5 usa un valor por default de 0.5, el cual puede ser además reducido
por la R opción (Capítulo 9) cuando parece probable que los atributos tienen un
grado insólito de traslapo ( Afortunadamente, el algoritmo no parece ser
particularmente sensible a el valor de W).
La tarea, entonces, es encontrar un subconjunto S de reglas para la clase C
que minirnizen esta codificación total. Esto es similar a la tarea de regularización de
reglas discutida antes (encontrar un subconjunto de las condiciones que minimizan
el índice de error pesimista de la regla) pero, considerando que la ambiciosa
eliminación aproximada usada es razonablemente satisfactoria. En cambio, el
20
CAPITULO 2 DE LOS ARBOLES A LAS REGLAS
sistema considera todos los posibles subconjuntos de las reglas para una clase, si
no existen también muchos de ellos, y usa una simulación reforzada para encontrar
un buen subconjunto. Para el último, el sistema repetidamente selecciona una de
las reglas aleatoriamente y lo considera incluido en el subconjunto S ( si este no
está ), o borrado ( si este está). Esta acción produce un cambio AB en el total de
bits para codificar el subconjunto “más exepcional” y, si este cambio es benéfico,
esto es automáticamente aceptado. Si la acción incrementa el largo total de
codificación para que AB sea positivo, el cambio para S es aceptado con
probabilidad e- donde K es una especie de temperatura sintética. Para
gradualmente reducir K mientras los cambios son explorados, el sistema tiende a
converger a un conj de reglas con codificación cercana al mínimo.
La selección de subconjuntos de reglas es nuevamente ilustrado por el
dominio hipotiroides con reglas para la clase primaria hipotiroides. Para esta clase,
el árbol de decisión obtenido de 2,514 casos preparados dio tres reglas cuyos
números de identidad pasan a ser 4, 5, y 7. La tabla 2-1 resume el análisis de los
ocho posibles subconjuntos de estas reglas. El último renglón de la tabla puede ser
explicado como sigue:
El costo de la codificación para el conjunto de las tres reglas es la suma de los
costos de la codificación para las reglas individuales, menos el ordenamiento
credit. Las reglas individuales tienen costos de código de 17.1 ~ 19.8, y 15.7 bits
respectivamente y, ya que existen 3! formas de ordenarlas, el costo de la teoría
es de 17.1 + 19.8 + 15.7 - log2(6).
Existen cuatro casos falsos positivos de los 66 casos cubiertos por estas
reglas y dos falsos negativos de los restantes 2,448 casos, así el código exepción
requiere
4 2 bits
21
MANUAL TECNICO
Usando el valor por default W=0.5, el costo de la codificación total es
entonces 41 .O + 0.5 * 49.9.
22
CAPITULO 2 DE LOS ARBOLES A LAS REGLAS
CLASIFICANDO CLASES Y ESCOGIENDO UNA POR DEFECTO
Después de que un subconjunto de reglas para representar cada clase ha
sido definido, los restantes pasos solamente son para establecer un orden para las
clases y para seleccionar una clase estándar. Ambas operaciones son relativamente
simples.
Recordar que los subconjuntos de reglas seleccionados para cada clase
causarán usualmente errores falso positivos, ya que ellos cubrirán algunos casos
que no pertenecen a esta clase particular. Cuando se decide en un orden para las
clases, este parece sensible para diferir estas clases cuyo conjunto de reglas
cometen muchos errores falso positivos, los subconjuntos primitivos pueden
entonces haber (correctamente) cubierto alguno de estos casos antes de que ellos
sean clasificados. Los subconjuntos de clases son examinados y la clase cuyo
subconjunto de reglas tiene menos errores falso positivos llega a ser la primer clase.
23
MANUAL TECNICO
Los falso positivos en los restantes casos preparados son recalculados, la
siguiente clase seleccionada, y así.
Una selección razonable para la clase estándar podría ser aquel que aparece
más frecuentemente en el conjunto entrenador. Sin embargo, la clase estándar será
usada solamente cuando un caso no es cubierto por algunas reglas seleccionadas,
así estas reglas deben representar alguna parte determinada de esta. El sistema
simplemente escoge como la estándar la clase que contiene más casos preparados
no cubiertos por alguna regla, decidiendo vínculo en favor de la clase con mayor
fecuencia absoluta.
Después de que el orden de la clase y la clase estándar han sido
establecidas, el conjunto de reglas compuesto es un subconjunto de un proceso
final refinado. Si hay una o más reglas cuya omisión podría actualmente reducir el
número de errores clasificados en los casos preparados, la primera de tal regla es
descartada y el conjunto verificado nuevamente. Este paso es diseñado para
permitir un escrutinio final global de el conjunto de reglas como un todo ,en el
contexto del camino este será usado.
En nuestro ejemplo de hipotiroides, la situación después de que el conjunto
de reglas ha sido establecido para cada clase es resumido en la tabla 2-2. Las
reglas para hipotiroides compensada, sin positivos falsos, son colocadas primero,
seguidas del subconjunto de reglas para hipotiroides primaria, y finalmente las
reglas para la clase negativa. Hay 8 casos preparados de hipotiroides compensada
que no son cubiertos por alguna regla, más que el número de alguna otra clase, así
esta llega a ser la clase estándar. En el conjunto de reglas final (mostrado en la
figura 2-3), la exactitud predicha para cada regla aparece en corchete cuadrado.
Estas reglas representan una teoría más amigable que el árbol de decisión de la
figura 2-1, y aún las reglas son apenas tan exactas como el &bol: ambas dan sólo
ocho errores (0.06%) cuando se clasifican 1258 casos no vistos.
24
CAPITULO 2 DE LOS ARBOLES A LAS REGLAS
Tabla 2-2. Resumen de las clases por conjuntos de reglas, hipotiroides.
25
MANUAL TECNICO
Si tiroxine = f
cirugía de tiroides = f
TSH > 6
TT4 <= 150
FTI > 64
entonces clase hipotiroides compensada
Si cirugía de tiroides = f
TSH > 6
FTI <= 64
(98.9%)
entonces clase hipotiroides primaria (95.6%)
Si tiroxine = f
TT4 medido = f
TSH > 6
entonces clase hipotiroides primaria (45.3%)
Si TSH <= 6
entonces clase negativa (99.9%)
Si tiroxine = t
FTI > 64
entonces clase negativa (99.5%)
Si TSH medida = f
entonces clase negativa (99.5%)
Si TT4 > 150
entonces clase negativa(99.4Oh)
Si cirugía de tiroides = t
entonces clase negativa (92.7%)
Si ninguna de las arriba
entonces clase hipotiroides compensada
Figura 2.3. Reglas finales para el ejemplo de hitpotiroidez.
26
CAPITULO 3 PODANDO ARBOLES DE DECISION
PODANDO ARBOLES DE DECISIóN
El método de particionamiento recursivo de construcción de árboles de decisión
descrito en el capítulo 2 continuará para subdividir el conjunto de casos preparados hasta
que cada subconjunto en la partición contenga casos de una clase simple, o hasta que
ninguna prueba ofrezca alguna mejoría. El resultado es a menudo un árbol muy complejo
que "sobreajuste de datos" por inducir más estructuras de las que son justificadas por los
casos preparados.
Este efecto es prontamente visto en el ejemplo extremo de datos aleatorios en la
cual la clase de cada caso no tiene relación con sus valores de atributos. Construí una
base de datos artificial de este género con diez atributos, cada uno de los cuales tomaba
el valor de O o 1 con igual probabilidad. La clase fue también binaria, si con probabilidad
0.25 y no con probabilidad 0.75. Mil casos generados aleatoriamente fueron divididos en
un conjunto preparado de 500 y un conjunto prueba de 500. Para estos datos, la rutina
inicial de árbol de construcción de C4.5 produce un árbol sin sentido de 11 9 nodos que
tiene un porcentaje de error de más de 35% en los casos de prueba.
Este pequeño ejemplo ilustra el doble peligro que puede venir por ser demasiado
incauto en la aceptación de el árbol inicial: este es a menudo extremadamente complejo, y
puede tener actualmente un mayor porcentaje de error que un árbol más simple. Para los
anteriores datos aleatorios, un árbol compuesto de sólo las hojas no podría tener un
porcentaje de error esperado de 25% en casos no vistos, todavía el &bol elaborado es
notablemente inexacto.. . . .
25
MANUAL TECNICO
~ C U Á N D O SIMPLIFICAR?
Existen básicamente dos maneras en las cuales el método de particionamiento
recursivo puede ser modificado para producir árboles más simples: decidiendo no dividir
un conjunto de casos preparados en alguno más amplio, o eliminando retrospectivamente
alguna de las estructuras establecidas arriba con particionamiento recursivo.
La aproximación anterior, algunas veces llamada parando o prepodando, tiene la
atracción de que el tiempo no es desperdiciado reuniendo estructuras que no son usadas
en el árbol final simplificado. La aproximación típica es mirar la mejor manera de
fraccionamiento de un subconjunto y evaluar la división desde el punto de vista del
significado estadístico, ganancia de información, reducción de error o cualquiera. Si este
avalúo cae debajo de algún umbral, la división es rechazada y el árbol para el
subconjunto es justo la hoja más apropiada. Sin embargo, como Breiman y otros señalan,
tales reglas de parado no son sencillas de hacer bien - un umbral demasiado alto puede
concluir antes la división el beneficio de la subsecuente división llega a ser evidente,
mientras que un valor demasiado bajo resulta en una simplificación pequeña.
En un período, use un criterio de parada basado en la prueba X' de importancia
estadística. El resultado fue bastante satisfactorio en algunos dominios pero fue
desnivelado, de manera que abandone esta aproximación; C4.5, al igual que CART,
ahora seguimos el segundo camino. El proceso de divide y vencerás está dando rienda
libre y el árbol desbordado que es producido es entonces podado. El cálculo adicional
invertido en construir partes del árbol que es subsecuentemente descartado puede ser
substancial, pero este costo es desplazado contra el beneficio debido a una exploración
más completa de particiones posibles. El desarrollo y podado de árboles es más lento
pero más fiable.
Podar un árbol de decisión casi invariablemente causará a éste una mayor
clasificación errónea de los casos preparados. Consecuentemente, las hojas del arb01
podado no necesariamente contendrán casos de una clase simple, hemos encontrado un
fenómeno en el capítulo anterior. En lugar de una clase asociada con una hoja, allí
26
CAPITULO 3 PODANDO ARBOLES DE DECISION
nuevamente estará una distribución de clase especificada, para cada clase, la
probabilidad de que un caso preparado y la hoja pertenezcan a esta clase.
Esta modificación puede ligeramente afectar la determinación de la clase más
probable para un caso no visto.
Árbol de decisión original:
physician fee freeze = n;
adoption of the budget resolution = y: democrat (151)
adoption of the budget resolution = u: democrat (1)
adoption of the budget resolution = n:
education spending = n : democrat (6)
education spending = y 1 democrat (9)
education spending = u : republican (1)
physician fee freeze = y;
synfuels corporation cutback = n: republican (97/3)
synfuels corporation cutback = u: republican (4)
synfuels corporation cutback = y:
duty free exports = y: democrat (2)
duty free exports = u: republican (1)
duty free exports = n:
education spending = n: democrat (5/2)
education spending = y: republican (13/2)
education spending = u: democrat ( I )
physician fee freeze = u;
water project cost sharing = n: democrat (O)
water project cost sharing = y: democrat (4)
water project cost sharing = u:
mx missile = n: republican (O)
mx missile = y: democrat (3/1)
mx missile = u: republican (2)
27
MANUAL TECNICO
DESPUÉS DEL PODADO:
physician fee freeze = n: democrat (
physician fee freeze = y: republican
physician fee freeze = u;
1 68/2.6)
(1 2311 3.9)
mx missile = n: democrat (311 .I )
mx missile = y: democrat (412.2)
mx missile = u: republican (211)
Figura 3-1. Árbol de decisión antes y después del podado
ERROR BASADO EN EL PODADO
Los árboles de decisión son usualmente simplificados por eliminación de uno o
más árboles y reemplazando estos por hojas; como cuando construimos árboles, la clase
asociada con una hoja se encuentra por la examinación de los casos preparados
cubiertos por la hoja y escogiendo la clase más frecuente. Además C4.5 permite
reemplazar un subárbol por una de éstas ramas. Ambas operaciones son ilustradas en la
fig. 3-1 que muestra un árbol de decisión derivado de datos de votantes al congreso antes
y después del podado. (Para el árbol no podado, recordar que (N) o (N/E), apareciendo
después de la hoja indica que la hoja cubre N casos preparados, E erróneamente,
números similares para el árbol podado se explican a continuación). El subárbol
adoption of the budget resolution = y: democrat
adoption of the budget resolution = u: democrat
adoption of the budget resolution = n:
education spending = n : democrat
education spending = y : democrat
education spending = u : republican
ha sido reemplazado por la hoja demócrata, el subárbol
28
CAPITULO 3 PODANDO ARBOLES DE DECISION
synfuels corporation cutback = n: republican
synfuels corporation cutback = u: republican
synfuels corporation cutback = y:
duty free exports = y: democrat
duty free exports = u: republican
duty free exports = n:
education spending = n: democrat
education spending = y: republican
education spending = u: democrat
ha sido reemplazado por la hoja republicano, y el subárbol
water project cost sharing = n: democrat
water project cost sharing = y: democrat
water project cost sharing = u:
mx missile = n: republican
mx missile = y: democrat
mx missile = u: republican
ha sido reemplazado por el subárbol de su tercera rama.
Supóngase que fuerá posible predecir el porcentaje de error de un árbol y de sus
subárboles (incluyendo las hojas). Esto podría inmediatamente sugerir el siguiente
razonamiento simple de podado: comenzando desde el fondo del árbol y examinando
cada subárbol que no sea hoja. Si reemplazamos de este subárbol con una hoja, o con su
rama más frecuentemente usada, podríamos llegar a una predicción con menor porcentaje
de error, entonces podar el árbol es correcto, recordando que el porcentaje de error
estimado para todos los arboles que incluyen este serán afectados. Ya que el porcentaje
de error para el árbol completo decrece cuando el porcentaje de error de alguno de sus
subárboles es reducido, este proceso llevará a un árbol cuya predicción de porcentaje de
error es mínima con respecto a la forma aceptable de podado.
29
MANUAL TECNICO
¿Cómo podemos predecir este porcentaje de error?. Es claro que el porcentaje de
error en el conjunto preparado del cual el árbol fue construido (error de resubstitución, en
la terminología de Breiman y otros) no proporciona una estimación satisfactoria; en lo que
al conjunto preparado se refiere, el podado siempre incrementa el error. En el árbol de la
figura 3-1 , el primer árbol reemplazado separa 1 Republicano de 167 Demócratas (sin
errores en el conjunto entrenador), así podar este subárbol de la hoja demócrata causa a
uno de los casos preparados a ser mal clasificado. El segundo subárbol clasifica mal a 7
casos preparados cuando ordena 11 Demócratas y 112 Republicanos, pero esto aumenta
a 11 errores cuando el árbol es reemplazado por la hoja republicano.
Esta búsqueda como una manera de predecir porcentajes de error conduce
nuevamente a dos técnicas. La primera tecnica predice el porcentaje de error del árbol y
sus subárboles usando un nuevo conjunto de casos que es distinto del conjunto
preparado. Puesto que estos casos no fueron examinados al mismo tiempo que el árbol
fue construido, la estimacijn obtenida de ellos es claramente imparcial y, si existen
bastantes de ellos, fiable. Ejemplos de tales técnicas son:
Costo-Complejidad del podado, en el cual el porcentaje de error estimado de un árbol
es planeado como la suma pesada de su complejidad y su error en los casos
preparados, con los casos distintos usados principalmente para determinar un peso
apropiado.
Simplificado-Error del podado, el cual evalúa el porcentaje de error del árbol y sus
componentes directamente en el conjunto de casos separados.
El inconveniente asociado con esta familia de técnicas es simplemente que
algunos de los datos disponibles deben ser reservados para el conjunto separado, así el
árbol original debe ser construido de un conjunto entrenador más pequeño. Esto puede no
ser una desventaja cuando los datos son abundantes, pero puede conducir a arboles
inferiores cuando los datos son escasos. Una manera acerca de este problema es usar
una aproxlmación de validación-cruzada. En esencia, los casos disponibles son divididos
en C bloques de igual tamaño y, para cada bloque, un árbol es construido por casos en
30
CAPITULO 3 PODANDO ARBOLES DE DECISION
todos los otros bloques y probados por casos en el bloque “holdout”. Para valores
moderados de C, se supone que el árbol es construido para todos pero un bloque no
diferirá mucho del árbol construido para todos los datos. Por supuesto, C arboles deben
ser grandes en lugar de solamente uno. Ver Breiman (1984)
La aproximación aceptada en C4.5 pertenece a la segunda familia de técnicas que
usan solo el conjunto preparado del cual el árbol fue construido. La estimación
resubstituida original de porcentaje de error es ajustada para reflejar esta tendencia de la
estimación. En un trabajo anterior, desarrolle un método llamado podado pesimista,
inspirado por una corrección estadística, que efectivamente incrementó el número de
errores observados de cada hoja por 0.5. C4.5 ahora emplea una estimación mucho más
pesimista como sigue.
Cuando N casos preparados son cubiertos por una hoja, E de ellos
incorrectamente, el porcentaje de error de resubstitución para esta hoja es de E/N. Sin
embargo, podemos estimar esto como algo sencillo observando E “eventos” en N
ensayos. Si este conjunto de N casos preparados pudiera ser contemplado como un
ejemplo (el cual, por supuesto, no lo es), podríamos preguntar como este resultado nos
determina acerca de la probabilidad de un evento (error) por encima de la población
entera de casos cubiertos por esta hoja. La probabilidad de error no puede ser
determinada exactamente, pero tiene para ella misma una (posterior) distribución
probabilistica que es usualmente resumida por un par de limites de confianza. Para un
nivel de confianza dado CF, el límite superior de esta probabilidad puede ser encontrada
por el límite de confianza de una distribución binomial; así el límite superior se escribirá
UcF (E,N) . Entonces, C4.5 simplemente iguala el porcentaje de error predicho a la hoja
con este límite superior, basado en el argumento de que el árbol ha sido construido para
minimizar el porcentaje de error observado. Ahora, esta descripción viola las nociones
estadísticas de muestre0 y limites de confianza, así que el razonamiento debería tomarse
como un gran grano de sal. Como muchos heurísticos con cuestionables refuerzos, no
31
MANUAL TECNICO
obstante las estimaciones que estos producen parecen frecuentemente proporcionar
resultados aceptables.
Para simplificar la contabilidad, los errores estimados para las hojas y subárboles
son calculados asumiendo que ellos fueron usados para clasificar un conjunto de casos
no vistos del mismo tamaño que el conjunto preparado. Así que, una hoja cubre N casos
preparados con un porcentaje de error estimado de UCF(E,N) el cual podría aumentar para
una predicción de N * UcF(E,N) errores. Similarmente, el número de errores predichos
asociados con un (sub)árbol es solamente la suma de los errores predichos de estas
ramas.
EJEMPLO : DEMóCRATAS Y REPUBLICANOS.
Para ilustrar que está pasando, regresaremos a el ejemplo de la ilustración 3-1. El
subárbol
education spending = n : democrat (6)
education spending = y : democrat (9)
education spending = u : republican (1 )
no tiene errores asociados en el conjunto preparado. Para esta primera hoja, N=6, E=O, y
(usando un nivel de confianza por default del 25% dado por C4.5), UZ5% (0,6) = 0.206, así
que el número estimado de errores si esta hoja fue usada para clasificar 6 casos no vistos
es 6 x 0.206. Para las hojas restantes, UZ5% (0,9) = 0.143 y ( 0 , l ) = 0.750, asÍ que el
número de errores para este subárbol esta dado por
6 x 0.206 + 9 x O. 143 + 1 x 0.750 = 3.273
Si el subárbol fue reemplazado por la hoja demócrata, esta podría cubrir los
mismos 16 casos con un error, así los errores estimados correspondientes serán
16 X U25% (1:16) = 16 X 0.157 = 2.512
Puesto que el subárbol existente tiene un gran número de errores estimados, este
es podado para una hoja.
El subárbol anterior es como sigue:
32
CAPITULO 3 PODANDO ARBOLES DE DECISION
adoption of the budget resolution = y: democrat (1 51 )
adoption of the budget resolution = u: democrat (1 )
adoption of the budget resolution = n: democrat (16/1)
el número de errores estimados para este subárbol es
151 x UZ5% (0,151) + 1 x UZ5% (0 , l ) + 2.512 (de arriba)
el cual se convierte en 4.642. Si este subárbol fue reemplazado por la hoja demócrata, el
error estimado sería 168 x UZ5% (0,168) = 2.61 O. El porcentaje de error estimado para la
hoja nuevamente es menor que para el subárbol, así este subárbol es también podado
para una hoja.
ESTIMACIóN DE PORCENTAJES DE ERROR PARA ARBOLES
Los números (NIE) de las hojas del árbol podado en la figura 3-1 puede ahora ser
explicado como antes, N es el número de casos preparados cubiertos por la hoja. E es
precisamente el número de errores estimados de un conjunto de N casos no vistos que
fueron clasificados por el árbol.
La suma de errores estimados de las hojas, dividido por el número de casos en el
conjunto entrenador, proporciona una estimación inmediata del porcentaje de error del
árbol podado en casos no vistos. Para este árbol, la suma de los errores estimados de las
hojas es 20.8 para un conjunto entrenador de tamaño 300. Para esta estimación,
entonces, el árbol podado clasificará mal el 6.9% de casos no vistos.
El resumen de resultados sobre los casos preparados y un conjunto de casos
probados aparece en la figura 3-2. Para este conjunto de datos particular, el porcentaje
de error del árbol podado es mayor que para el de un árbol no podado para los datos
preparados, pero, como se esperaba, el árbol podado tiene un porcentaje de error menor
que el árbol original para casos no vistos. La estimación aquí del 6.9% queda fuera por
ser algo mayor que el porcentaje de error observado sobre casos no vistos que es del 3%.
Sobre diez maneras de validacion-cruzada, sin embargo, el promedio actual y 10s
porcentajes de error estimados sobre casos no vistos 5.3% y 5.6% respectivamente, son más estrechos,
33
MANUAL TECNICO
Evaluacion en datos entrenadore (300 casos):
Antes del Podado Después del Podado
Tamaño Errores Tamaño Errores Estimación
25 8(2.7%) 7 13(4.3%) (6.9%)
Evaluacion en datos de prueba (1 35 casos):
Antes del Podado Después del Podado
Tamaño Errores Tamaño Errores Estimación
25 7(5.2%) 7 4(3.0%) (6.9%)
Figura 3-4. Resultados de los votos del Congreso.
34
CAPITULO 4 IMPLEMENTACION DEL ALGORITMO ID3
IMPLEMENTACION DEL ALGORITMO ID3.
En el presente capitulo se Iistara el programa con el que se realizó la
implementación del algoritmo descrito en los capítulos anteriores, se incluye el programa
completo, así como una lista de las estructuras utilizadas para dicho fin y una breve
explicación del mismo.
Las estructuras utilizadas para la implementación del algoritmo descrito en capítulos
anteriores, fueron las siguientes:
ARRESUM typedef struct arresum{
float sum1 ; float sum2;
}SUMAS;
PAQUETE struct Paquete{ int num-atributos;
>; typedef struct Paquete PAQUETE;
int posicion;
PAQUETE1 struct Paquetel {
struct ListaSencilla int char
1; typedef struct Paquetel
struct PaqueteDecision{ float
*apuntador; posicion; Atributo[GO];
PAQUETEI;
PAQUETEDECISION
PorcientoError; struct ArbolDecision *DirCaso;
1; typedef struct PaqueteDecision PAQUETEDECISION;
35
MANUAL TECNICO
NODO struct Nodo{
char clase[60]; int frecuencia; struct Nodo*izq; struct Nodo*der;
typedef struct Nodo *NODO; 1;
I NODO I I NODO 1
ARBOL struct Arbol{
char atributo[60]; int frecuencia; int men-may; struct Lista *sig; struct Arbol *izq; struct Arbol *der;
1; typedef struct Arbol *ARBOL;
atributo sig der izq men-may frecuencia LISTA
ARBOL ARBOL
36
CAPITULO 4 IMPLEMENTACION DEL ALGORITMO ID3
LISTA struct Lista{
char clase[60]; float frecclase; struct Lista *sig;
I ; typedef struct Lista *LISTA;
clase NODO sig frecclase
LISTASENCILLA struct ListaSencilla{
char Salida[GO]; Int frecuencia; Int men-may; struct ListaSencilla *sublista;
>; typedef struct ListaSencilla "LISTASENCILLA;
salida LISTASENCILLA sublista men-may freccuencia
LISTASALIDA struct Listasalida{
char Atributo[GO]; int posición; float ganancia; struct Listasalida *sig; struct ListaSencilla *sublista;
I: typedef struct LlstaSalida *LISTASALIDA;
37
MANUAL TECNICO
Atributo posicion LISTASENCILLA
1 LISTASALIDA 1
ARBOLDECISI~N struct ArbolDecision{
char Valor[GO]; char Clase[GO]; struct ArbolDecision *sig; struct ArbolDecision "subraiz;
typedef struct ArbolDecision *ARBOLDECISION; 1;
Valor ARBOLDECISION Posicion Clase
I ARBOLDECISION I
Descripción del programa:
Inicialización de las estructuras a utilizar. 0 Abertura del archivo con los casos a procesar.
Cálculo del número de lecturas al archivo. Se procesa el archivo de la siguiente manera:
0 Lectura del encabezado del archivo, obteniendo de esto la lista de atributos presentes en los casos, estos atributos se guardaran en la variable CabAtributo la cual es de tipo LISTASALIDA.
0 Procesar el archivo atributo por atributo determinando los distintos valores de estos. exceptuando la última columna dando como resultado una lista de salidas por atributo la cual se guardara en la variable CabSalidas de tipo ARBOL. Para la última columna se formará una lista de clases la cual se almacenara en la varlable CabClase de tipo NODO.
0 Si las distintas salidas del atributo fueran números, se determinará un rango basado en el cálculo de la Entropía de éstos, de esta manera se generará el árbol
CAPITULO 4 IMPLEMENTACION DEL ALGORITMO ID3
ClasiSal de tipo ARBOL en cuya raíz se almacenará el número de casos menores o iguales a la Entropía y en el hijo derecho aquellos mayores que la misma. Cálculo del “info” en base a la estructura CabClase. Cálculo del “infox” ,”ganancia”, “splitinfox” y “razón de ganancia” por atributo . Seleccion de la máxima “razón de ganancia’’ tomando el atributo correspondiente a ésta como la raiz (subraiz) del árbol de decision, guardando dicho árbol en la variable RAlZ de tipo ARBOLDECISION. En la variable ListaVaIores de tipo LISTASENCILLA se almacenará la lista con las salidas del atributo seleccionado como raíz. Se recorrerá ListaValores de tal manera que se seleccionarán del archivo en turno aquellos casos casos cuya salida en ese atributo coincida con el nodo actual de esta lista, eliminando de los casos el atributo en cuestión, obteniendose así un archivo con los casos seleccionados. Ver figura sig.
7 1 outlook temp humidity wind!. class
m sunny 75 70 tnle play
overcast 81 75 false play
sunny 85 85 false !play
rain 68 80 false play
sunn?‘ 69 70 false play
rain 75 80 false play
overcast 72 90 false pia!.
rain 70 96 true play
sunny 80 90 true !play
d
7 1 overcast 64 65 true play
I outlook = rain I temp humidity windy class
68 80 false play
75 80 false play
70 96 truc pia!.
Con el archivo generado anteriormente se realiza una llamada recursiva clasificar todos los casos originales.
hasta
0 Se obtienen las reglas de produccion del árbol generado anteriormente escribiendo
0 El árbol generado anteriormente se somete a un algoritmo de podado que consiste en: estas en un archivo de texto llamado REGLASN.TXT.
0 Determinar el número de errores y aciertos producidos al clasificar cada caso. 0 Apartir de las hojas del árbol se calcula el porcentaje de error de cada una de
ellas (el porcentaje de error se iguala al límite superior del intervalo de confianza de una distribución binomial, con nivel de confianza por defautl del 25% para el algoritmo de clasificación ID3).
MANUAL TECNICO
0 Se realiza una comparación de los porcentajes de error antes y después del podado, definiendo que si el porcentaje de error después de podado es menor entoces se procede con el mismo en caso contrario no se realizan cambios.
Se obtienen las reglas de produccion del árbol podado generado anteriormente escribiendo estas en un archivo de texto llamado REGLASP.TXT. Consulte capítulo correspondiente.
40
CAPITULO 5 CODIGO FUENTE
CODIGO FUENTE #Include #Include #Include #Include #Include #Include #Include #Include #include
<stdio.h> <math. h> idlr . h> <conlo. h> <stdlib.h> <string.h> ifcntl. h> <ctype. h> <lo. h>
typedef struct arresumi float suml; float sum2;
1 SUMAS ; . . . . . . . . . . . . . . . . . . . . . . . . . . ARBOL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . struct Nodo[
char clase [ 601 ; / * Contlene el nombre de la clase * / lnt frecuencia; / * frecuencla de la clase * / struct Nodo *izq; struct Nodo *der;
1 ; typedef struct Nodo *NODO;
struct Arbol{ char atributo [ 601 ; / * Contiene el nombre del atributo * / Int frecuencia; / * frecuencia del atributo * / lnt menmay; struct Lista * s l g ; /*apuntador a la lista de sus clases*/ struct Arbol *Izq; struct Arboi *der;
1 ; typedef struct Arbol *ARBOL;
struct Lista( char clase [ 601 ; float frecclase; struct Lista * s i g ;
1 ; typedef struct Lista *LISTA;
/ * Contiene el nombre de la clase * / / * frecuencia de la clase * /
struct LlstaSencllla{ char Salida[GO]; / * Contiene el nombre de las salldas * / lnt frecuencia; / * de los atributos * / lnt men may; struct ListaSencIlla "sublista;
typedef struct LlstaSencilla *LISTASENCILLA; I ;
struct LlstaSallda( char Atributo[GO]; / * En la lista principal contlene el * /
int posiclon; / * En la lista pricipal contiene la * /
float ganancia; / * Contiene la razon de ganancia del * / struct LlstaSallda "sig; / * atrlbuto * / struct LlstaSencllla *subllsta;
/ * nombre del atributo * /
/*posiclon en la que se encuentra dentro del archivo * /
typedef struct LlstaSallda *LISTASALIDA; 1 ;
struct Paquete{ lnt num-atrlbutos; lnt poslclon;
~.
typedef struct Paquete PAQUETE; : I
43
MANUAL TECNICO
struct Paqueteclase( lnt frecuencla; char clase [ 601 ;
1 ; typedef struct Paqueteclase PAQUETECLASE; struct Paquetel(
struct ListaSencllla *apuntador; int char
1 ; typedef struct Paquete1 struct ArbolDecisioni
char char l n t int lnt struct ArbolDeclsion struct ArbolDeclsion
1 ;
poslcion; Atrlbuto [ 601 ;
PAQUETE1 ;
Valor[GO]; / * valor del atributo * / Clase[6O] ; / * clase * / Posiclon; / * poslciCn del atributo en el archlvo * / Errores; / * casos m a l clasificados * / Casos; / * n€mero de casos clasiflcados * / *s1g; "subralz;
typedef struct ArbolDeclslon *ARBOLDECISION; struct PaqueteDecisloni
float PorcientoError; struct ArbolDeclsion *DirCaso;
1 ; typedef struct PaqueteDecislon PAQUETEDECISION; Int num arch=O,Podarlhoja=O; float I l r n l t e = ~ . O E - Z O ;
SUMAS Fentropla(ARB0L SubRalz); vold claslflca-arbol(float entrop1,ARBOL arbolorlg,ARBOL **arbolfin); SUXAS SumEntropla (lnt frec, char atrib [ 601 ) ; lnt abre-archlvo(char nombre[]); vo id arbol-binario(f1oat entropi,ARBOL *orlgen,ARBOL *destino); float log2 (float x) ; float determina-rango(ARB0L CabSalldas,int tot-casos);
/ S - - - - - - - - - - - - - - - - - - - - - - - - D E C L A ~ C I O N DE FUNCIONES-----------------------*/
INICIALIZA L O S CAMPOS DE LA LISTA ORDENADA Y LA PONE A NULL * /
vold Iniclalizar(NOD0 *Cabeza){ (*Cabeza) =NULL; (*Cabeza) ->izq=NULL; (*Cabeza) ->der=NULL; ¡*Cabeza) ->frecuencia=l; strcpy ( (*Cabeza) ->clase, " " ) ;
/ veld InlclaLlsta(L1STASALIDA *Cabeza) i
(*Cabeza) =NULL; (*Cabeza)->sig=NULL; (*Cabeza)->sublista=NULL; ("Cabeza) ->poslcion=@; (*Cabeza)->[email protected]; strcpy ( ("Cabeza) ->Atributo, " ' I ) ;
1 , ,*----""---------"""""""""""""""""""""""""""" * / vold InlclaArbolDecislon(ARBOLDEC1SION *Cabeza){
1 *Cabeza) =NULL; 1 *Cabeza'! ->slg=NULL; '*Cabeza) ->subralz=NULL: strcpy ( í*Cabeza) - > V a l o r , " " i ; strcpy 1, (*Cabeza) ->Clase, ' I " ) ; I"Cabezaj->Poslclon = O; (*Cabeza) ->Errores = 0; (*Cabeza)->Casos = O;j
44
CAPITULO 5 CODIGO FUENTE
vold InlciArbLls(ARB0L *Cabeza) { ("Cabeza) =NULL; (*Cabeza) ->izq=NULL; (*Cabeza)->der=NULL; (*Cabeza) ->sig=NULL; (*Cabeza) ->frecuencia=l; (*Cabeza)->menmay=O; strcpy ( (*Cabeza) ->atributo, " ' I ) ;
1
/*""""""---"""""""----""""""""""-""-"""""""* / vo;d IniclaLlsSen(LISTASENC1LLA *Cabeza)(
(*Cabeza) =NULL; (*Cabeza)->subllsta=NULL; strcpy ( (*Cabeza) ->Sailda, " " ) ; (*Cabeza) ->frecuencia = O; (*Cabeza) ->menmay = O;
1
/,""""""""""""""""""""""""""""---"-"""""-* / NODO CreaNodo (char clase [ 601 ) [
struct Nodo "Nuevacabeza;
Nuevacabeza= (NOD0)malloc (sizeof (struct Nodo) j ; Nuevacabeza->frecuencia = 1; strcpy(NuevaCabeza->clase,clase); Nuevacabeza->lzq = NULL; NuevaCabeza->der = NULL; return (Nuevacabeza) ;
1 /*~"""""""~_~~"~""""""""""""~-""""--"---"-"""-* / ARBOLDECISION CreaRalz(char valor[60],char clase[60])(
struct ArbolDeclslon "Nuevacabeza;
NuevaCabeza=(ARBOLDECISION)malloc(sizeof(struct ArbolDecision)); Nuevacabeza->sig = NULL; Nuevacabeza->subraiz = NULL; strcpy(NuevaCabeza->Valor,valor) ; strcpy(NuevaCabeza->Clase, clase) ; Nuevacabeza->Poslclon = O; Nuevacabeza->Errores = O; Nuevacabeza->Casos = O; return (Nuevacabeza) ;
/~~~~""""""""""""------"""""""""---------"-------------"~ LISTASENCILLA CreaNodoSub(char sallda[60],int frecuencla,int menmay j(
/
struct Listasenellla *Nuevacabeza;
NuevaCabeza=(LISTASENCILLA)malloc(sizeof(struct LlstaSencilla)); strcpy(NuevaCabeza->Salida,sallda); Nuevacabeza->frecuencia = frecuencia; Nuevacabeza->men-may = men-may; Nuevacabeza->subllsta = NULL; return(NuevaCabeza);
/~ " " "~~~~~~~~~~"" " " " " " " " - - " " " " " " " "~-~" - " " " " - - - - - " " * LISTA CreaLlsta(char clase[60]) {
struct Llsta *Nuevacabeza;
NuevaCabeza=(LISTA)malloc(sizeof(struct Llsta)); Nuevacabeza->frecclase = 1; strcpy (Nuevacabeza->clase, clase) ; Nuevacabeza->slg = NULL; return (Nuevacabeza) ;
/
45
MANUAL TECNICO
LISTASALIDA CreaSalida(char Atrlbuto[GO]){ /*---"""""""""""---""""""""""----"-""""""""""-*/
struct LlstaSallda *Nuevacabeza;
NuevaCabeza=(LISTASALIDA)malloc(sizeof(struct ListaSallda)); Nuevacabeza->poslcion = O; Nuevacabeza->ganancia = 0.0; s t r c p y ( N u e v a C a b e z a - > A t r l b u t o , A t r l b u t o ) ; Nuevacabeza->slg = NULL; Nuevacabeza->sublista = NULL; return (Nuevacabeza) ; )
/ * / ARBOL CreaArbol (char atrlbuto [ 601 i { str-~ct Arbol *Nuevacabeza;
NuevaCabeza=(ARBGL)malloc(sizeof(struct Arbol)); Nuevacabeza->frecuencia = 1; Nuevacabeza->men may = o ; strcpy (Nuevacabeya->atributo, atributo) ; Nuevacabeza->lzq = NULL; Nuevacabeza->der = NULL; Nuevacabeza->sig = NULL; return (Nuevacabeza) ; 1
/*""""""""""""""""""""""""""------"-------------* volci LlberaLista(L1STA *SubLista){
/
lf ( (*SubLlsta) I = NULL ) [ LlberaLlsta(&(*SubLlsta)->sig); free (*SubLlsta) ; *SubLista=NULL; 1 )
/*--"""""""""""""-----"""""""""""""-""""""-* / veld LlberaArbol(ARB0L *SubRalz)[
If (*SubRalz !=NULL) [ LlberaArbol ( & (*SubRaiz) ->lzq) ; LlberaLlsta ( & (*SubRalz) - > s l g ) ; LlberaArbol ( & ("SubRaiz) ->der) ; free (*SubRalz) ; *SubRalz=NULL; ] ]
/ vola LlberaNodo(NGDG *SubRaiz){
If (*SubRalz !=NULL) [ LiberaNodo ( & (*SubRalz) ->lzq) ; LiberaNodo ( & (*SubRalz) ->der) ; free ("SubRaiz) ; *SubRaiz=NULL; ) )
*""""----""""""""-"""""""-""""""""""""""- * / v o l a LlberaListaSencllla(LISTASENC1LLA *SubLista){
If ( (*SubLista) ! = NULL ) { LiberaListaSencilla(&(*SubLlsta)->sublista); free (*SubLlsta) ; *SubLlsta=NULL; ) ]
/*--""----"""""----"""""""---""""--""""""""""-"" * /
46
CAPITULO 5 CODIGO FUENTE
veld InsertarInfo(NOD0 *CabezaTemp,NODO Nuevo) ( lnt dlferencla = O;
If (*CabezaTemp==NULL) *CabezaTemp = Nuevo;
else [ diferencia = s t rcmp((*CabezaTemp)->clase ,Nuevo->clase) ; lf (dlferencla < O) InsertarInfo ( & (*CabezaTemp) ->der, Nuevo
if(diferencia > O) InsertarInfo ( & (*CabezaTemp) ->izq, Nuevo
if (diferencia == O) ( ((*CabezaTernp)->frecuencia++); free(Nuev0); } ] 1
vold lnsertar (NODO *Cabeza, char clase [ 601 ) ( struct Nodo *Aux=NULL; Aux = CreaNodo(c1ase); InsertarInfo(Cabeza,Aux); }
"
vold InsertaLista(char clase[GO],LISTA *InlcLlsta)( /*~~~""~~""""~""""----"""""""""""""""""""-
if ( ! strcrnp ( (*InicLista) ->clase, clase) )
else ( (*InicLlsta)->frecclase++;
if ( (*InicLista)->slg!=NULL)
else InsertaLista (clase, & (*InlcLlsta) - > s i g ) ;
!*InlcLlsta)->slg=CreaLista(clase); ) 1
v o l d InsertaAtrlb(LISTASAL1DA *InlcLlsta,char atrlbuto[GO]) i lf ( '*lnlcLlstaj !=NULL)
else InsertaAtrib ( & (*InicLista) - > s i g , atrlbuto) ;
(*InlcLista) =Creasalida (atributoj ; ) /*~""""-~"""~~"""""""""--"""~"""~""-~"""~" vo ld InsertaMax(LISTASAL1DA *InicLista,float ganancia,lnt posiclon){ lnt l=l;
LISTASALIDA aux=*InicLlsta; while( (1 ! = posiclon) & & (aux ! = NULL) j {
aux=aux->sig; It+; 1
aux->ganancla=ganancla; aux-?poslc~on=poslclon; }
void InsInfoSalida(ARB0L *CabezaTernp,ARBOL Nuevo,char sallda[60])! lnt dlferencla = O; LISTA Aux=NULL;
If (*CabezaTemp==NULLj { *CabezaTernp = Nuevo;
(*CabezaTemp)->sig = CreaLista(sa1ida); ) else (
dlferencla = strcrnp((*CabezaTemp)->atrlbuto,Nuevo->atributo); ~f (dlferencla < O!
lf (dlferencla ? o )
If (dlferencla == 0 ) [
InsInfoSallda ( & (*CabezaTemp) ->der, Nuevo, sallda) ;
InsInfoSallda ( & f *CabezaTernp) -?lzq, Nuevo, sallda) ;
((*CabezaTemp)->frecuencla++j; Aux= (*CabezaTempi - > s ; g ; InsertaLlsta (sallda, &Aux) ; free(Nuev0); 1 )
- * /
" * /
* /
* /
* /
" * /
47
MANUAL TECNICO
/*"""-~~~~"""""""""""--"""""""""~""""""-"-~""- INSERTA EN LA LISTA LA INFORMFlCION CON LA AYUDA DE
LA FUNCION INSERTAINFO
vold lnssallda(ARB0L *Cabeza,char clase[60],char sallda[60]) { * /
struct Arbol *Aux=NULL;
PAQUETE lee-encabezado(char *buf,LISTASALIDA *CabAtributo) i 1nt 1=0,1 = o ; char atrlbuto [ 601 ='"I;
PAQUETE paquete;
paquete.num atr¡butos=O; whllei (bufT]] !='\r') & & (1<50) ) i
~f (buf [ I ] ! = I ' )
else { atrlbuto [ 11 = buf [ 7 ] ;
atributo[l]='\O'; InsertaAtrib(&(*CabAtributo),atributo); / * inserta en cola de atributos*/ paquete.num ~ atributos++: 1=-1; )
I + + ; I++; )
paquete. poslclon=] ; return (paquete) ; ]
/*~~""-~""""""""""""""""""""""""""""""""-* / * lmprlmlr funclon * / / * ~ ~ " - ~ ~ " " ~ ~ " " " - ~ ~ " " " - - - - - " " " - - - - " " " ~ " " " ~ " " " ~ " " " ~ ~ " " ~ " ~ float calculalnfo(int numerador,lnt denomlnador) {
/
/
f ioat divi=O, lnf o=O ;
dlvi = (numerador*l.O)/ (denominador*l.O); lnfo=info-dlvi*logZ(divi); return (lnf o) ; )
/*"-~~"-~~""-~~""""""""""""""""""""""~""""" / * lmprlmlr funclon * /
flcat Info(NOD0 SubRalz,lnt num-casos,float m f o ) {
* /
/
float l n fode r=O, ln fo lzq=O, In focab=0 ;
lf (SubRalz!=NULL) { ~nfo~zq=lnfo+InfoiSubRalz->lzq,num-casos,lnfo); lnfocab = calculalnfo(SubRalz->frecuencla,nuIn-casosI; L n f o d e r = l n f o + I n f o ( S u b R a i z > d e r , n u m c a s o s , l n f o ) ; return!lnfolzq+~nfoder+infocab); 1
return(lnfolzq+lnfoder+¡nfocab); } /*"~~""""~""""""--"""--""-"""""-~""-~""~""""-~"~ / * Imprimir funcion * / /"-~"""""""""""--""--""""""""-~~""""""""""""-* f-loat calculainfox (int denomlnador, LISTA SubLista) {
/
/
float dlvl=O,lnfo=O;
L f (SubLlsta==NULL; return ( O i ;
lnfo=calculalnfox(denomlnador,SubLlsta->slg); d~v~=~SubL~sta->frecclase*l.O;/~denom~nador*~.O); lnfo=lnfo-dlvl*logZ idlvl) ; return (Info) ; )
else {
I
CAPITULO 5 CODIGO FUENTE
/*~~"~-~~~~_~""""""""""""""""""""""--"---"""""~ / float Infox(ARB0L SubRaiz,int num-casos,float info){
float lnfoder=O,lnfoizq=O,infocab=O;
If ( SubRaiz ! =NULL) { infoizq=lnfo+Infox(SubRaiz->izq,num casos,info); lnfocab = ((SubRaiz->frecuencia*l.Ol/(num-casos*l.O) )*calculainfox(SubRalz
lnfoder=lnfo+Infox(SubRalz->der,num ~ casos,lnfo); return(lnfolzq+lnfoder+lnfocab); ]
>frecuencla,SubRalz->slg);
return(lnfolzq+lnfoder+lnfocab);] /*-----"""""""""""""""""-------------""-""""""----~ i-ioat SplltInfox(ARB0L SubRalz,lnt num-casos,float Info){
/
float lnfoder=O,infolzq=O,lnfocab=O;
If (SubRalz !=NULL) { infolzq=lnfo+SplitInfox(SubRaiz->izq,num casos,mfo); infocab = - (SubRaiz->frecuencia*l. O) / (nu&-casos*l. O) * l o g 2 ( (SubRaiz-
lnfoder=lnfo+SplitInfox(SubRaiz->der,num-casos,info); return(infoizq+lnfoder+infocab); ]
>frecuencia*l.O)/(num-casos*l.O) ) ;
return(lnfolzq+infoder+infocab);) /*-""""-------""-"""""""-------"""""""----""""""-""* LISTASALIDA Mezcla (LISTASALIDA p, LISTASALIDA q ) {
/
LISTASALIDA r=NULL,Mezcla=NULL;
lf ( ( p==NULL I 1 ( q==NULL) ) prlntf ("LISTAS VACIAS") ;
lf( p->ganancla <= q->ganancla) i r=p ; p=p->s1g;)
r=q; else {
q=q->s1g; 1 Mezcla=r; whlle ( ( p!=NULL) & & (q!=NULL)
If (p->ganancia<=q->ganancia) { r->slg=p; r=p ; p=p->s1g; )
r->slg=q; r=q; q=q->slg;)
else {
1 f (p==NULL)
else
return (Mezcla) ; )
r->slg=q;
r->sig=p;
/~""~~""~~""""~~"""""""-~""""""---"------------"----- void Divlde(LISTASAL1DA *CabLista,LISTASALIDA *Aux) {
* /
LISTASALIDA Auxl=NULL;
49
MANUAL TECNICO
/*"""_-"----""""""""""""""""""""""""""""----* / veld OrdenaLlsta(LISTASAL1DA *CabLlsta){ LISTASALIDA Aux=NULL;
If (*CabLista !=NULL) { ~f ( (*CabLista) - ? s i g ! =NULL) {
Dlvide (CabLlsta, &Aux) ; OrdenaLista(CabL1sta); OrdenaLista (&Aux) ; *CabLlsta=Mezcla(*CabLista,Aux); ] )
/ veld IniciallzaCabezas(NOD0 *CabClase,ARBOL *CabSalldas,ARBOL *ClaslSal,LISTASALIDA *CabAtributo,LISTASENCILLA *LlstaValores){
Inlcxallzar(&(*CabClase)); InlciaLlsta(&(*CabAtributo)); InlciArbLls ( & ("CabSalidas) ) ; InlclArbLls ( & (*ClasiSal) ) ; InlclaLlsSen(&(*LlstaValores));
1 /'--""""------------"""""""""""""""""""-"""""-* / veld SlDlglto(ARB0L *CabSalldas,ARBOL *ClasiSal,lnt numpcasos)[ char cadl[6O]="",cad2[60]=""; lnt pundec=O, slgno=O, l=O, tam=O; f-loat entropla=O, entropl=O;
1 f ( lsdiglt ( (*CabSalldas) ->atrlbuto[O] ) 1 1 ( (*CabSalldas) ->atrlbuto[Ol = = I . ' ) ) { entropla = determlna rango(*CabSalldas,num casos); / * calcula la entropia * / entropl = entropla; strcpy(cad2, ecvt (entropia, 10, &pundec, &signo) ) ; / * en pundec se guarda * / tam=strlen(cadZ) ; / * la poslclon del punto,en slgno se lndlca * / for(l=O;l<=pundec;lt+) / * sl ei nLmero es posltivo o negatlvo * /
cadl [pundec] = ' . ' ; for(l=pundectl;i<=tam;l++)
cad1 [tam] = ' \O ' ; (*ClasiSal) = CreaArbol(cadl);/* menor o igual a entropla * / (*ClaslSal)->frecuencia = O; (*ClaslSal)-?menmay = -1; (*ClasiSal)->der = CreaArbol(cadi);/* mayor a entropla * / (*ClasiSal)->der->frecuencia = O; (*ClaslSal)-?der->men-may = 1; (*ClaslSal)->lzq = NULL;
-
cad1 [ i] =cad2 [ i] ;
cadl [ I ] =cad2 [i-1] ;
arbol binarlo (entropl, & (*CabSalldas) , & (*ClaslSal) ) ; } else {
-
*ClaslSal = "CabSalldas; *CabSalidas = NULL; )
/ * ~ ~ ~ " " ~ ~ ~ " " " " ~ ~ " " " ~ " - - ~ ~ " " " ~ ~ " " " " - " " - - - - - " - - - - - - - - - - - - - * / * lmprlmlr funclon * /
veld Calcularazonganancla(ARB0L CabSalldas,LISTASALIDA *CabAtrlbuto,lnt num casos,lnt 1 , float lnfoj {
/
/
float lnfox,splltlnfox,ganancla: double razonqanancldx=O;
lnfox=infox (CabSalldas,num-casos, O) ; ganancla=-Lnfo-infox; s p i l t l n f o x = S p l l t I n f o x ( C a b S a l l d a s , n u m casos,O); ~f (splltlnfox == O) / * porque ¡a claslflcaclcn sobre este atrlbuto * /
else
InsertaMax(&(*CabAtributo),razongananclax,j); )
razongananclax = O; / * es amblgua * /
razongananclax=ganancia/splitinfox;
50
CAPITULO 5 CODIGO FUENTE
void Recorresublista(LISTASENC1LLA *Sublista,char atrlbuto[60],lnt frecuencia,lnt menmay) {
~f (*Subllsta!=NULL) Recorresubl~sta(&(*Sublista)->subllsta,atributo,frecuencia,men-may);
*Subllsta=CreaNodoSub(atrlbuto,frecuencla,men-may); ) else
/*-------"""""""--"""""""""""""""""""""""""-*/ void InsertaSublista(char atrlbuto[60],lnt frecuencla,lnt men-may,LISTASALIDA *CabAtrlbuto, lnt 1 ) {
LISTASALIDA aux=NULL;
aux = *CabAtrlbuto; while ( ( aux->pos1clon!=]) & & (aux!=NULL))
aux = aux->slg; ~f(aux->poslcion==~i
R e c o r r e s u b l ~ s t a ( & a u x - > s u b l l s t a , a t r ~ b u t o , f r e c u e n c i a , m e n - m a y ) ; ) /
iilt lee-atributos(char *buf,LISTASENCILLA *ListaAtrlb){ lnt 1=0 , j=O,poslclon=O; char atributo [ 601 ="" ;
while( (buf[j] !='\r') & & (j<50) 1 { lf (buf [ I ] ! = ' ' )
else { atrlbuto [ I] = buf [ j I ;
atributo [ 11 = ' \O ' ; posiclont+;
1=-1; ] I + + ; 1 + t ; ]
Recorresubl~sta(&(*ListaAt~~b),atributo,pos~cion,O);
return (O) ; ] /
veld EscArcProd(F1LE *fp,ARBOLDECISION RAIZ,ARBOLDECISION AuxSub,char cadena[200]){ ARBOLDECISION AuxRaiz=RAIZ; lnt tam; char espaclo [O] =" ";
whlle (AuxRalz !=NULL) [ If ( ( lsdlgit (AuxRaiz->Valor [O] ) ) 1 1 (AuxRaiz->Valor [O] == ' . ' ) ) {
If (AuxRaiz->sig!=NULLj
else strcat (cadena, "<="j ;
strcat (cadena, " > " ) ; ] strcat(cadena,AuxRaiz->Valor); strcat (cadena, espacloj ; lf(AuxRalz->subralz==NULL)
if ( ! strcmp (AuxRalz->Clase, " ' I ) ) / * no claslflcado * /
else ( / * ya claslflcado * / AuxRalz = AuxRalz->slg;
strcat(cadena,AuxRaiz->Clase); fprintf (fp, " % S ",cadena) ; lf ( ( lsdigit (AuxRalz->Valor [O] ) ) 1 1 (AuxRalz->Valor [O] == ' . ' ) ) {
if (AuxRaiz->sig!=NULL)
else tam=strlen(cadena) - strlen(AuxRa1z->Valor) - strlen(AuxRai2->Clase) - 3;
tam=strlen(cadena) - strlen (AuxRalz->Valor) ~~ strlen(RuxRalz->Clase) - 2 ; ] else
cadenaítaml='\O'; tam=strlen(cadena) - strlen(AuxRalz->Valor) - strlen(AuxRa1z->Clase) - 1;
fprlntf (fp. "\n"' : I . AuxRalz = AuxRalz->slg;]
51
MANUAL TECNICO
else ~f(AuxRaiz->subralz ! = NULL) {
AuxSub=AuxRalz; AuxRaiz=AuxRaiz->subraiz; EscArcProd(fp,AuxRalz,AuxSub, cadena) ; tam=strlen(cadena) - strlen (AuxRalz->Valor) - 1; cadena[tam]='\O'; lf ( ( isdlgit (AuxSub->Valor [ O] ) ) 1 I (AuxSub->Valor [ O] == ' . ' ) ) {
if(AuxSub->sig!=NULL) tam=strlen(cadena) - strlen (AuxSub->Valor) - 3;
tam=strlen(cadena) - strlen(AuxSub->Valor) -. 2; 1 else
else tam=strlen (cadena) - strlen(AuxSub->Valor) - 1.; cadena [tam] = ' \O ' ; AuxRaiz=AuxSub->sig; ) / * f l n if * / } / * fin while * /
I /*"-------""""""""--""""""""""""""""""""""""- * / vold EscTltulos (FILE *fp, char nombre [13] j {
fprlntf(fp," REGLAS DE PRODUCCION OBTENIDAS APARTIR DEL ARBOL DE DECISION
fprlntf (fp, "\n") ; tprlntf (fp, " DEL ANALISIS DEL ARCHIVO ' : ' S , \n",nombre) ; fprlntf (fp, "\n") ; fprlntf (fp, "\n") ; ]
GENERADO\n" ) ;
/*~----------""""--"""""--""""""""-""""---"""""""-* / veld EscRegProd(ARBOLDECISI0N Ralz,char nombre[l3]){
FILE *fp; char cadena [2OO] ="" ; ARBOLDECISION AuxSub=NULL;
lf ( ( fp=fopen(nombre, "w+") ) == NULL ) { prlntf("N0 SE PUEDE ABRIR EL ARCHIVO PARA GENERAR LAS REGLAS DE PRODUCCION"); exlt (1) ; 1
EscTltulos (fp,nombre) ; EscArcProd(fp,Ralz,AuxSub, cadenaj ; fciose ifp) ; 1
else {
1
vold CreaSubllsta(ARB0L CabSalldas,LISTASALIDA *CabAtributo,lnt I ) { ~f (CabSalidas ! = NULL) {
CreaSubllsta(CabSalldas->lzq,&(*CabAtributo),]); InsertaSubllsta(CabSalldas->atrlbuto,CabSalidas->frecuencia,CabSall~as-
>menmay, & ("CabAtrlbuto) , j ) ;
I /"---------"--------""""""""""""""""""-------------"""* / PAQUETEl Irflnllsta(LISTASAL1DA CabAtributo){
CreaSublista(CabSa1idas->der,&(*CabAtributo),j); }
PAQUETE1 paquete; LISTASENCILLA AUX=NULL,LlstaSal=NULL;
while(CabAtribut0->slg!=NULL)
AUX = CabAtrlbuto->sublista; ir!iclai~sSen (&LlstaSal: ; whlle ;AUX !=NULL) {
CabAtrlbuto=CabAtributo->slg;
Recorresubllsta(&L~staSal,AUX->Sal~da,AUX->frecuencla,AUX->men-~mayj ; AUX= AUX->subilsta;i
paquete.poslclon=CabAtrlbuto->poslclon; paquete.apuntador=LlstaSal; strepy(paquete.Atrlbuto,CabAtr1buto->Atr1buto); r e t u r n (paquete) ;
52
CAPITULO 5 CODIGO FUENTE
* / void escrlbearchlvo (char renglon [5O], lnt pa) {
lnt tam=@;
tamzstrlen (renglon) ; lseek (pa, O, 2) ; If (wrlte (pa, renglon, tam) !=tam)
printf ("Error de escritura") ;
liit CreaAbreArc (char nombre [13] j [ lnt pa;
~f ( (pa=-creat (nombre, O) ) ==-1) { prlntf ("NO SE PUEDE CREAR EL ARCHIVO (-CREAT) " ) ;
return (I) ; ]
- close (pa) ; If ( (pa=open(nombre, O-WRONLY, O) ) ==-1) {
prlntf ("NO SE PUEDE ABRIR EL ARCHIVO") ; exlt(1); )
return (pa) ;
I
v o l d EscribeEncabezado(1nt posicion,char buffer[50],lnt pb){ lnt num esp=l, 7 =O, posenca=0; char auxsallda [ G O ] = ' I T ' ;
whlle ( [buffer[posenca] !='\r')&&(buffer[posenca] !='\n')&&(posenca<50)&&(buffer[posenca] !='\xO' / ) i
if (buffer[posenca]==' ' )
lf (num esp==poslclon) { num-esp++;
if (Fosiclon ! =I) posenca+t ;
whlle (buffer [posenca] ! = I ' j posenca++;
~f(posicion == I ) { posenca++; num-esp++; ) }/*fin de If espaclo=poslclon*/
else ( auxsalida [ J ] =buffer [posenca] ; I++; posenca++; ]/*fin else*/ ]/*fin del while de retorno de carro*/
escrlbearchivo(auxsallda,pbj; escrlbearchivo ("\n", pb) ; }
PAQUETECLASE CornparaFrecClase(1nt primerafrec,NODO CabClase,char prlrneraclase[GO]j { PAQUETECLASE paquete;
if(CabC1ase->frecuencla>prlmerafrec){ paquete.frecuencla = CabClase->frecuencia; strcpy(paquete.clase,CabClase->clase); return (paquete) ; I
paquete.frecuencla = prlmerafrec; strcpy(paquete.clase,prlmeraclase); return(paquete) ; 1 j
else [
* / PAQUETECLASE IniciaPaqClase(voidj {
PAQUETECLASE paquete;
paquete.frecuencla=O; strcpy (paquete. clase, " " ) ; return (paquete j ; ,
53
CAPITULO 5 CODIGO FUENTE
/ *_~" " " " " " "~_~"____________________"" " " " " " "~~~~~~* / veld escribearchivo(char renglon[50],int pa){
lnt tam=0;
tam=strlen(renglon); lseek (pa, O, 2) ; if (wrlte (pa, renglon, tam) !=tam)
) /*"""""""""""""""""""""""""""""""""""""* / lnt CreaAbreArc (char nombre [ 131 ) {
printf ("Error de escritura") ;
lnt pa;
if ( (pa=-creat (nombre, O) ) ==-1) { printf ("NO SE PUEDE CREAR EL ARCHIVO (-CREAT) " ) ;
return (1) ; 1 - close (pa) ; If ( (pa=open (nombre, O-WRONLY, O) ) ==-1) {
printf ("NO SE PUEDE ABRIR EL ARCHIVO") ; exlt(1); )
1 /*~~""""""""""""""~""""""""""""----~~""--------~*
return (pa) ;
/ void EscribeEncabezado(int posicion,char buffer[50l,int pb) {
lnt num esp=l,j=O,posenca=O; char auxsalida [ 601 ="" ;
while ( (buffer[posenca] !='\r')&&(buffer[posenca] !='\n')&&(posenca<5O)&&(buffer[posenca] !='\xO' 1 ) i
if (buffer [posenca] = = I ' )
if (num esp==posicion) { num-esp++;
1f (poslclon! =I) posenca++;
while (buffer[posenca] ! = I ' ) posenca++;
If (poslclon == 1) { posenca++; num-esp++; ) )/*fin de If espaclo=posicion*/
else { auxsalida [ 1 ] =buffer [posenca] ; I + + ; posencatt; )/*fm else*/ }/*fin del while de retorno de carro*/
escrlbearchivo(auxsallda,pb); escrlbearchivo ("\n", pb) ; )
/*""""-~""""~"""-"""""""""""""""""""""""" PAQUETECLASE ComparaFrecClaseiint prlmerafrec,NODO CabClase,char primeraclase[60]) { PAQUETECLASE paquete;
* /
if(CabC1ase->frecuencia>primerafrec){ paquete.frecuencia = CabClase->frecuencia; strcpy(paquete.clase,CabClase->clase); return (paquete) ; )
paquete.frecuencia = primerafrec; strcpy(paquete.clase,primeraclase); return!paquetej;] ]
else {
/*""~"""""~"""""-""--"""""""""""""""-""""-~"* PAQUETECLASE InlclaPaqClase (vold) (
/
PAQUETECLASE paquete;
paquete.frecuencla=O; strcpy(paquete.clase, " " ) ; return (paquete) ;
53
MANUAL TECNICO
/*---"""""--"""""""""""""""""""""""""""""- * / PAQUETECLASE clasemasPfrecuente(N0DO CabClase,int primerafrec,char primeraclase[hO])(
PAQUETECLASE paqizq,paqraiz,paqder;
paqizq=InlclaPaqClase(); paqralz=In:claPaqClase(); paqder=InlciaPaqClase();
~f (CabClase !=NULL) { paqlzq = clasemas-frecuente(CabClase->izq,pr~merafrec,pr~meraclase); paqralz = ComparaFrecClase(paqizq.frecuencia,CabClase,paqizq.clase); paqder = clase~mas_frecuente(CabClase->der,paqra:z.frecuencia,paqraiz.clase);
I else (
paqder.frecuenc1a = prlmerafrec; strcpy(paqder.clase,prlmeraclase);
1
return (paqder) ;
vold CreaSubArch(int pa,lnt pb,long int tamani0,LISTASENCILLA ListaValores,int resto, ~ n t po~:clon) { lnt num esp=l,posenca=0,~=O,7=O,veces=O,band=O,band=O,frecuenc~a=O,alto = O , termino = O; char bu?fer[5O]="", auxbuf [60]="",auxsalida[60]=""; PAQUETE pnumatrlb; LISTASALIDA CabAuxlllar;
/*---------------"""""""""""""-""-"""""""""""""-*/
alto = tamanlo/50; InlciaLista(&CabAuxlliar); l s e e k (pa, O, O) ; - read(pa, buffer, 50) ; buffer[50]='\0'; pnumatrib = lee-encabezado(buffer,&CabAuxillar); EscribeEncabezado(posiclon,buffer,pb); posenca=pnumatrib.poslclon+Z; / * por retorno de carro y salto de llnea * / for(veces=l;veces<=alto+l;veces++){ / * ntmero de lecturas * /
while !posenca<50 i { li- (veces==(alto+l) ) & & (posenca>=resto) )
else ( posenca = 50;
while( (buffer[posenca] !='\r')&&(buffer[posenca] !='\n')&&(posenca<50)&&(buffer[pos enca] !='\xO')) (
If ( (veces== (alto+l) ) & & (posenca>=resto) )
else { posenca = 50;
~f (buffer [posenca] = = I ' ) ( termlno = O; num-esp++;) lf (num esp==poslclon) [
if (nüm-esp ! = I ) posenca++;
whlle ( (buffer [posenca] ! = I ' ) & & (posencai50) ) { termlno = O; auxbuf[l]=buffer[posenca]; / * guarda el valor a comparar * / it+;
posenca++; )/*fin de whlle de distlnto de espacio*/ lf (posenca == 50)
termlno = 1; If !posenca<=50) (
auxbuf [1]='\0'; if (lsdlglt (auxbuf [O] ) 1 I (auxbuf [O]=='. ' ) ) (
lf!LlstaValores->men may==-1) { / * menor o igual * / If ( atof (auxbuf) <=atof (Listavalores->Salida) )
CAPITULO 5 CODIGO FUENTE
band = 1; } else / * mayor * /
If ( atof (auxbuf) >atof (Listavalores->Salida) )
else band = 1; )
if(!strcmp(auxbuf,ListaValores->Salida)) band= 1 ; posenca++; lf (num esp!=l)
posenca"; num-esp++; ] )
~f ( (termlno == 1) & & (buffer[posencal ! = ' I ) ) {
while( (buffer[posenca] ! = I ' j & & (posenca<50) ) {
-
else {
termmo = O;
auxbuf[l]=buffer[posenca]; /*guarda el valor a comparar*/ I++;
posenca++; ) if (posenca == 50)
termlno = 1; else (
auxbuf[i]='\O'; if (isdigit (auxbuf [O] ) I I (auxbuf [O] == ' . ' ) ) {
if(ListaVa1ores->men may==-1) { / * menor o igual * / if( atof(auxbuf)<=atof(ListaValores->Salida) )
band = 1; } else / * mayor * /
If ( atof (auxbuf) >atof (LlstaValores~>Sallda) )
else band = 1; )
If ( ! strcmp (auxbuf, LlstaValores->Sallda) )
If (posenca<50) { band=l ; ] )
If( (]==O)&& (buffer[posenca]==' ' j ) posenca++; auxsalida[ J ] =buffer[posenca] ; j ++; posencatt;}
)/*fin if num esp == posiclonk/ ) }/*fin del whlle de retorno de carro*/
if (posencai50) { If (band==l j {
auxsalida[~]='\O'; frecuencia++; If( frecuencla <= LlstaValores->frecuencia)
If( frecuencia < Llstavalores->frecuencia)
else
strcpy(auxsalida, " ' I ) ; posenca=posenca+2; band=O ;
i=O ; num - esp=l;)
strcpy (auxsallda, " " ) ;
If (terrnlno==O) 1=0 ;
poseneat+; num-esp=l; I / * fln de lf band==l * /
escrlbearchlvo(auxsallda,pb);
escrlbearchlvo ("\n",pb) ;
escrlbearchlvo ( " ' I , pb) ;
j = O .
else {
7 = o ;
I / * fln de posenca < 50 * / else [ / * posenca >= 50 * /
If (band==l) {
MANUAL TECNICO
lf (resto>O) { lf (alto==O) {
auxsalida [ j ] = ' \O ' ; frecuencia++;
lf( frecuencla <= Listavalores->frecuencia) escrlbearchivo(auxsallda,pb);
if( frecuencia < Llstavalores->frecuencia) escribearchlvo ( "\n" , pb) ;
escribearchivo ( I ' ' I , pb) ; else
strcpy (auxsalida, " " ) ; posenca=posenca+2; band=O; 7 =o; 1=0;
num esp=l; ] else {
-
if (veces == alto ) {
- read (pa, buffer, resto) ; buffer[resto]='\O'; 1
- read(pa,buffer,50); else
posenca=O;
If (buffer[posenca]=='\n') { auxsallda[j]='\O'; frecuencia++; lf( frecuencia <= Listavalores->frecuencia)
lf( frecuencia < LlstaValores->frecuencia)
else
strcpy (auxsallda, " " ) ; posenca=posenca+2; band=O ; 7 =o; 1=o; num esp=l; ]
veces++- 1 1
escrlbearchlvo(auxsalida,pb);
escrlbearchlvo ("\n", pb) ;
escrlbearchivo ( " ' I , pb) ;
else{ / * else resto == O * /
if (veces == alto ) [ if (veces <= altotlj [
- read (pa, buffer, resto) ; buffer[resto]='\O'; }
~ read(pa,buffer,50); else
posenca=O; I If (buffer [posenca] = = I \n' j {
auxsalida[j]='\O';
frecuencia++; if( frecuencia <= Listavalores->frecuencia)
If( frecuencia < Listavalores->frecuencia)
eise
strcpy (auxsallda, ' I " : ; posenca=posenca+2; band=O ; j = O ; l=o ; num esp=l; 1 / * fin else resto > 0 * / veces++; 1
/ * modif * /
escrlbearchivo(auxsalida,pb);
escrlbearchlvo("\n",pb) ;
escrlbearchlvo ( " " , pb) ;
56
CAPITULO 5 CODIGO FUENTE
] / * fin If band == 1 * / } / * fin else posenca < 50 * / 1 /*fin while posenca<=50*/
I if (veces == alto ) {
read(pa, buffer, resto) ; buffer[resto]='\~'; 1
- read(pa, buffer, 50) ;
else
posenca=O; ] /*fin del for veces * /
~ c l o s e (pb) ; LlberaLlstaSalida(&CabAuxlllar);
I /*~"""~~~"""~""""""""""""""""""-~""""""~~"-* / lnt lee-archlvo(char nombre[l3],ARBOLDECISION *RAIZ,ARBOLDECISION RAIZTEM,lnt vez) { long lnt tamanlo=O; ARBOLDECISION SUBRAIZ=NULL; NODO CabClase; ARBOL CabSalidas,ClasiSal; LISTASALIDA CabAtrlbuto; LISTASENCILLA LlstaValores; PAQUETE pnurnatrlb; PAQUETE1 LlstaValoresStr; PAQUETECLASE paqueteclase; char buffer [ 5 0 ] = I " ' ,
auxbuf [ 601 =" " , auxsallda [ 601 ="" , nomarch2 [ 131 ="", retorno [ O] = I " ' , cadparch[ 61 ="" ; lnt l=O, num casos=O, veces, j =O, num esp=l, p=O, posenca=O, resto=O, poslcion=O; lnt pa,pb,primerafrec=O; /*manejadores de archivo*/ float info=O;
pa=abre archlvo (nombre) ; InlclaArbolDecision(&SUBRAIZ); inlclallzaCabezas(&CabClase,&CabSalidas,&ClasiSal,&CabAtributo,&LlstaValores); tamanlo = fllelength(pa) -1; resto = tamanlo d 50;
~ read(pa, buffer, 50) ; buffer[50]='\0'; pnumatrib = lee-encabezado(buffer,&CabAtributo); p=pnumatrlb.posiclon+2; / * por retorno de carro y salto de llnea * / posenca=p;
for(l=l;~<=pnumatrlb.numatrlbutos;l++)( / * ntmero de atributos * / num esp=l; forTveces=l;veces<=(tamanio/50)+l;veces++) / * nfmero de lecturas * / while( ( buffer[p] !='\O') & & ( p<50 ) ) { / * mlentras tenga algo en el arreglo * /
If ( (veces== (tamanio/50+1) ) & & (p>=resto) ) {
else { lf [ (buffer[p] ! = I ')&&(buffer[p] !='\r')&&[buffer[p] '='\n')&&(
p=5O; 1
( , n u r n _ e s p = = ~ ) I 1 (num esp==pnumatrlb.num atrlbutos+l) ) ) { auxbuf fi] = buffer[p] ; l++; j
~f(buffer[p] == ' ' 1 {/*se ha encontrado un espacio o sea otra salida * / e l s e
auxbuf[l]='\O'; / * de un atrlbuto * / If (num esp==~ j
nilm ~ esp++; i=O; ) strcpy (auxsalida, auxbuf) ;
else lf(buffer[pl=='\r') {/*se ha llegado al final de una linea o sea de un*/
/ * caso y se analizara el slguiente * / auxbuf [l]='\O'; If ( (strcmp[auxbuf,"") )&&(strcmp(auxsalida,"")) ) {
If ( 7 = = l ) / * solo para el prlmer atrlbuto reallza el arbol. de c l a s e s * /
Insertar [ &CabClase, auxbuf) ; /*construye rbol de clases*/
57
MANUAL TECNICO
inssa1:da (&CabSalidas, auxbuf, auxsalida) ; /*construye rbol de
strcpy (auxbuf, " ' I ) ; strcpy(auxsalida, " " ) ; :=O; num casos++;]/*fin de strcmp*/
salldas para cada atributo*/
num-esp=l; E++;) /*f:n de buffer[p]=='\r' * / p++;
I /*fin while buffer[p]!='\O' . . . * /
strcpy (buffer, " ' I ) ; ifiveces == (tarnan:o/50) ) { / * solo lee el resto, es la t1t:ma lectura * /
read(pa,buffer, resto) ; buffer[resto~='\~';
~ read(pa,buffer,50); else / * realiza lecturas de tamano 50 * /
p=O ; )/*f:n for veces numero de lecturas*/ auxbuf [i] = ' \O' ; if ( (strcmp(auxbuf,"") )&&(strcmp(auxsalida,"")) ) (
lf ( j = = l ) / * solo para el primer atributo realiza el arbol de clases * /
insertar(&CabClase,auxbuf); /*construye rbol de clases*/ :nssal:da(&CabSal:das,auxbuf,auxsalida); /*construye rbol de salldas para cada
l=O; num casos++; 1 atributo*/
- 1 : (J==lj
~ f ( (CabClase->izq==NULL) &&(CabClase->der==NULL) ) { / * s1 e l arbol de clases solo contlene una clase * /
strcpy(RA1ZTEM->Clase,CabClase->clase); ~ close (pa) ; :f(CabSal:das ! = NULL) LiberaArbol(&CabSalidas); If (CabClase ! = NULL) LiberaNodo(&CabClase);
return (O) ; ]
lf(CabAtr1buto->sig==NULL){
lf(CabAtributo ! = NULL) LlberaListaSalida(&CabAtributo);
else {
pr:rnerafrec=CabClase->frecuencia; paqueteclase = clase " mas frecuente(CabClase,prlmerafrec,CabClase->clase); strcpy(RA1ZTEM->Clase,paqueteclase.clase); - c l o s e (pa) ; lf(CabSa1idas ! = NULL) LiberaArboli&CabSalidas); :f (CabClase ! = NULL) LiberaNodo(&CabClase); :f(CabAtrlbuto ! = NULL) LiberaL:staSallda(&CabAtrlbutoj; return (O j ; j ]
:f ( j = = 1 ) / * calcula e l lnfo solo una vez cuando se esta analizando el pr:mer strlbuto * /
inf o=Inf o ( CabClase, num-casos, O j ; S ~ D l g ~ t o ( & C a b S a l ~ d a s , & C l a s i S a l , n u m _ c a s o s ) ; Calcularazongananc~a(ClasiSal,&CabAtributo,num-casos,j,info); Iseek(pa,O,O); / * posiciona el apuntador al in1c:o del archivo * /
buffer[501='\0'; p=posenca; num casos=O; CreaSubl:sta(C¡aslSal,&CabAtrlbuto,j); :f (CabSa1:das ! = NULL) LlberaArbol (&CabSalldas) ; L f (C1as:Sal ! = NULL) L:beraArboli&ClaslSal);
read(pa,buffer,50); / * vuelve a leer e l archlvo en un buffer de tamauo 50 * /
i /+f-:n for 2 numero de atributos*/ ? f KabClase I = NULL) LlberaNodo(&CabClase!; OrdenaLlsta (&CabAtrlbuto) ; I,1 s~aValoresStr=Irflnllsta (CabAtrlbuto) ; LlsfaValores=LlstaValoresStr.apuntador: poslclon=LlstaValoresStr.pos~clon; If (vez==O)
else { RAIZTEM = CreaRalz (LlstaValoresStr.Atr:buto, " " ) ;
58
CAPITULO 5 CODIGO FUENTE
p?-q~zTEM->subralz = CreaRaiz(ListaValoresStr.Atribut0,""); PAIZTEM = RAIZTEM->subralz;)
SUBRAIZ = RAIZTEM; if(CabAtrlbut0 ! = NULL) LiberaLlstaSallda(&CabAtributo); whlle(ListaValores!=NULL) {
num arch++; strcpy(nomarch2,"a"); 1toa (num-arch, cad-arch, 10) ; strcat(nomarch2,cad-arch); strcat (nomarch2, " . xxx") ; pb=CreaAbreArc (nomarch2) ; RAIZTEM->slg = CreaRaiz (LlstaValores->Salida, " ' I ) ; RAIZTEM=RAIZTEM->slg;
CreaSubArch(pa,pb, tamanio,LlstaValores, resto,posicion) ; pb=abre_archlvoinomarch2); lseek (pb, fllelength(pb) -2, O) ; - read (pb, retorno, I ) ; lf (retorno[O]=='\r')
lseek (pb, filelength(pb) -2, O) ; write (pb, "\xlA", 1) ; close (pb) ;
lee-archivo (nomarch2, & (*RAIZ) ,RAIZTEM, 1) ; ~1sta~alores=L1staValores->sublista;
I /*fin whlle LlstaValores"/
- close (pa) ; * W I Z = SUBRAIZ;
1f (CabSalldas ! = NULL) LlberaArbol (&CabSalldas) ; ~f (ClaslSal ! = NULL) LlberaArbol (&ClaslSal) ; If (CabClase ! = NULL) LlberaNodo(&CabClase); lf (CabAtrlbuto ! = NULL) LlberaListaSalida (&CabAtrlbuto) ; ~f(LlstaValores ! = NULL) LlberaLlstaSencilla(&LlstaValores); return (O 1 ; ]/*fin funclon*/ / * ~ ~ ~ ~ " " " ~ ~ ~ ~ ~ ~ ~ ~ " " " " " ~ " " " " " " ~ ~ " " " " " " - - ~ " " " " - " " " - * .~nt abre-archlvo(char nom-arch[l3]) {
/
lnt pa; If ( (pa=open (nom-arch, O-RDONLY, O ) ) ==-1) {
prlntf ("NO SE PUEDE ABRIR EL ARCHIVO") ; exlt (I); 1
return (pa) ; ) /*~~-""----""""--"""""--""""--"""""-"""----""""""" lnt. Busca-poslclon(char Valor[GO],LISTASENCILLA ListaAtrlb) (
* /
l n t poslcion=O,bandera=O; while( (ListaAtrib!=NULL) & & (bandera==O) ) {
lf ( ! strcmp (Valor, LlstaAtrlb->Sallda) ) { poslclon = ListaAtrlb->frecuencia; bandera = 1; ]
LlstaAtrib = ListaAtrlb->subllsta;] return (posiclon) ; 1
/*--""--"""-""""---""""-""""""""""""""""""""""* / lnt poner-poslclon(ARBOLDEC1SION *RAIZ,LISTASENCILLA ListaAtrib){
ARBOLDECISION TempoRalz,AuxRaiz;
TempoRaiz = *RAIZ; lf (TempoRalz ! = NULL) (
l€ ( ! strcmp(TempoRa1z->Clase, " " ) & & (TempoRalz->subraiz==NULLj )
RuxKalz = TempoRalz->slg; whll e ( AuxRal z =NULL j {
TempoKalz->Poslc>on = Busca-poslclon(TempoRalz->Valor,LlstaAtrlb);
lf ( ! strcmp íAuxRalz->Clase, "" j & & (AuxRalz->subralz==NULL) )
rf( AuxRalz->subralz!=NULL)
AuxRalz AuxRalz->slg;)]
AuxKalz->Posiclon = Busca ~ poslclon(AuxRalz->Valor,LlstaAtr-b);
poner poslclon(&AuxRalz->subralz,LlstaAtrlb);
return(0);)
59
MANUAL TECNICO
/*""""""""""~--""~""""""""""""""""""-"""-""*/ char *Busca-Clase(LISTASENCILLA Iniciocaso) {
whlle(InlcloCaso->subllsta!=NULL) / * * /
return(InlcloCaso->Sallda); InlcloCaso=InlcloCaso->subllsta;
~ n t determina-clase(ARB0LDECISION *RAIZ,LISTASENCILLA *InicloCaso) i nKBOLDECISION TempoRalz=NULL,TempoSalida=NULL; LISTASENCILLA TempoCaso=NULL; lnt Poslclon=O,bandera=O; char Salida [ 601 ="" , ClaseArbol [ 601 = I " ' , Clasecaso [ 601 ="";
TempoRalz = *RAIZ; whl ie ( ! strcmp (TempoRalz->Clase, " " ) & & (TempoRaiz->slg ! = NULL) ) {
I'os1clon = TempoRaiz->Poslclon; 'CempoCaso = *InlcloCaso; while( (TempoCaso ! = NULL) & & (TempoCaso->frecuencia ! = Poslclon) )
TempoCaso = TempoCaso->sublista;
strcpy(Sallda,TempoCaso->Salida); TempoSalida = TempoRalz->sig; while( (TempoSallda!=NULL) & & (bandera == O) ) {
lf( (TempoCaso ! = NULL) & & (TempoCaso->frecuencia == Poslcion) ) {
if ( (Isdigit (TempoSalida->Valor[O] ) ) I I (TempoSalida->Valor[Ol = = l . ' /*If 2*/
if ( atof (Salida) <= atof (TempoSallda->Valor ) ) if(TempoSal1da->subraiz==NULL){
else { TempoRaiz=TempoSalida; bandera=l;l
TempoRaiz=TempoSalida->subraiz; bandera=l;) else {
TempoSallda=TempoSallda->sig; lf(TempoSa1ida->subraiz==NULL){
else { TempoRalz=TempoSalida; bandera=l;]
TempoRalz=TempoSalida->subraiz; bandera=l;)) else
lf( !strcmp(TempoSalida->Valor,Sallda) ) if(TempoSa1ida->subraiz==NULL) (
else { TempoRaiz=TempoSallda; banderazl;]
TempoRalz=TempoSalida->subralz; bandera=l;] TempoSalida = TempoSalida->slg;) bandera=O;]]
strcpy (ClaseArbol, " ' I ) ; lf ( (TempoRaiz->slg==NULL) & & (strcmp (TempoRaiz->Clase, " " ) ) )
l f ( (TempoRalz->subralz==NULL) & & (strcmp (TempoRalz->Clase, " " ) )
l f ( strcmp (ClaseArbol, " " ) ) [
strcpy (ClaseArbol, TempoRaiz->Clase) ;
strcpy(ClaseArbol,TempoRalz->Clase);
strcpy(ClaseCaso,Busca_Clase(*InlcloCaso) 1 ; ~f(!strcmp(ClaseArbol,ClaseCaso))
TempoRalz->Casos = TempoRaiz->Casos + 1; else
TempoRalz->Errores = TempoRaiz->Errores + l;] return (O) ; I
60
CAPITULO 5 CODIGO FUENTE
lnt determina-error(ARBOLDECISI0N *RAIZ,char nom-arch[l3]) ( lnt pa, resto=O,p=O,num esp,veces=O, i=O; long lnt tamanio=O; char buffer 1501 ="", auxbuf [ 601 ; PAQUETE pnumatrib; LISTASENCILLA InicioCaso=NULL; LISTASALIDA CabAtrlbuto;
-
InlclaLlsta(&CabAtrlbuto); pa=abre-archlvo(nom-arch); tamanlo = filelength(pa)-1; resto = tamanio % 50;
buffer [50] ='\O' ; pnumatrlb = lee-encabezado(buffer,&CabAtributo); p=pnumatrlb.posiciontZ; / * por retorno de carro y salto de linea * / num-esp=l; for(veces=l;veces<=(tamanio/5O)tl;vecestt)( / * n€mero de lecturas * /
- read(pa, buffer, 50) ;
while( ( buffer[p]!='\O') & & ( p<50 ) ) ( / * mlentras tenga algo en el arreglo * / if ( (buffer[p] ! = I ' ) & & (buffer[p] !='\r') & & (buffer[p] !='\n') ) {
else auxbuf [1] = buffer[p]; i+t; }
lf( (buffer[p] == ' ' ) 1 I (buffer[p] == '\r') ) { / * se ha encontrado un espaclo o sea otra sallda de un atrlbuto o se termino un caso*/
auxbuf [i] = ' \O' ; Recorresublista(&InicioCaso,auxbuf,num-esp,O); / * inserta al final * / num esp++; i=O; strcpy (auxbuf, " " ) ; lf ibuffer[p] == '\r') {
determina-clase ( & (*RAIZ) , &Iniciocaso) ; LiberaListaSencilla(&InicioCaso);
num-esp = 1; ] ) p++; 1 /*fin while buffer[p]!='\O' . . . * /
strcpy (buffer, " " ) ; lf(veces == (tamanlo/50) ) ( / * solo lee el resto, es la fltlma lectura * /
read(pa, buffer, resto) ; buffer [resto] = ' \O' ; ] el s e / * reallza lecturas de tamano 50 * /
read(pa,buffer,50); p=O; l/*fln for veces numero de lecturas*/
-
If ( strcmp (auxbuf, " ' I ) ) { auxbuf[l]='\O'; Recorresubllsta (&InlcloCaso, auxbuf ,num-esp, O) ; / * inserta al final * / determina-clase ( & (*RAIz), &InlcloCaso) ; LlberaListaSencilla(&Inlclocaso); num esp++; l=O; strcpy(auxbuf, " " ) ; ]
return (O) ; -
/*~~""~"""~""""--"""~"""""""""""-~"""-""---"-----* lnt claslflca(char nom-arch[l3] ,ARBOLDECISION *RAIZ) (
/
lnt pa; char buffer [50]=""; LISTASENCILLA ListaAtrib;
pa=abre-archlvo(nom-arch); InlclaLlsSen(&ListaAtrlb);
/ * crea lista con atributos y posiclones * / lee atrlbutos(buffer,&LlstaAtrlb); / * graba poslclones en el rbol de declslcn * / poner~poslcloni&(*RAIZi ,LlstaAtrib); close (pa) ; / * determlna el n€mero de errores y aclertos en la claslficaclCn y los
determina-error ( & (*RAIZ) ,nom-arch) ; returni0) ; )
- read (pa, buffer, 50) ;
guarda en el rbol de decisiCn * /
/*~~"""~"-~""""""""""""""""""""""""""""""- * /
MANUAL TECNICO
void Podarl(ARBOLDECIS1ON *TempoRaiz, int Casos, lnt Errores){ ARBOLDECISION Llbre=NULL;
Llbre = (*TempoRalz) ->s ig ; (*TempoRaiz)->Casos = Casos; (*TempoRaiz)->Errores = Errores; c*TempoRalz)->subraiz = Libre->subralz; ("TempoRalz) - > s l g = Llbre->slg; free (ilbre) ;
i
v o l d Podar2(ARBOLDECISION "TempoRaiz, 1nt Casos, lnt Errores){ ARBOLDECISION Llbre=NULL;
Llbre = ("TempoRalz) - > s l g ; ("TempoRaiz) ->Casos = Casos; (*TempoRaiz)->Errores = Errores; (*TempoRaiz)->Position = Libre->Position; (*TempoRaiz)->subraiz = Libre->subraiz; (*TempoRaiz) ->si9 = Libre->sig; strcpy((*TempoRaiz)->Clase,Libre->Clase); free (Libre) ;
/ float U21 (lnt Errores, 1nt Casos) {
float porcenta~e = O,sumando=O,sumandoraiz=O;
sumandoralz = Errores*(l-Errores/Casos); sumando = 1.15*sqrt( sumandoraiz + 0.330625 ) ;
porcenta~e =(Errores + 0.66125 + sumando)/(Casos + 1.3225);
return (porcenta] e) ; I /*"""~~""""""""----"""""""-~~""""""""~""""""~"* / PAQUETEDECISION Inicia-paquete(void)( PAQUETEDECISION paquete;
paquete.Porc1entoError = O; paquete.DlrCaso = NULL; return (paquete) ;
1
/*""~~~"""~~""""""""---""""~~~""""""~""""--~"-----~* PAQUETEDECISION podar arbol(ARBOLDECISI0N *RAIZ,int profundidad){ PAQUETEDECISION ~2,paGuete; ARBOLDECISION TempoRalz=NULL,AuxRaiz=NULL; lnt Casos=O,Errores=O; float Porc~entoEl=O,PorcientoE2=0,PorcientoPodado=O,Porc~entoSinPodar=O;
P2 = lnlcla paquete ( ) ; paquete = lnicla-paquete(); TempoRalz = *RAIZ; lf(TempoRaiz->subraiz!=NULL){
/
~
podar arbol(&TempoRalz->subralz,O); / * recursividad * / lf ( (Podar?¡ho]a==l) & & (TernpoRaiz->Poslclon==O) & & (TempoRalz-
>subralz '=NULL) & & ( ! strcmp (TempoRaiz->Clase, " " ) ) ) { Podarlho~a=O; AuxRalz=TempoRalz->subralz->slg; strcpy!TempoRalz->Clase,AuxRalz->Clase);
TempoRa;z->Casos=AuxRalz->Casos; TempoRalz->Errores=AuxRalz->Errores;
TempoRalz->subralz=AuxRaiz->subralz; free (AuxRalz) ; AuxRalz=TempoRalz->subralz; free (AuxRalz i ; }
podar-arbol(&TempoRaiz->slg,profundldad+l); / * recursivldad * / ) ] If (TempoRalz->slg'=NULL) {
else
CAPITULO 5 CODIGO FUENTE
~f(TernpoRaiz->sig!=NULL) {
else { / * Casos mal claslficados, total de casos cubiertos * / p2 = podar_arbol (&TempoRaIz->s ig ,profundidad+l ) ; / * recurslvldad * /
paquete.~orciento~rror = U25(TempoRaiz->Errores,TempoRaiz->Casos+TempoRaiz-
paquete.DirCaso = TempoRaiz; return (paquete) ; I
PorcientoEl = ~25(TempoRaiz->Errores,TempoRaiz->Casos+TempoRaiz->ErroreS) ,' 1f(~empoRalz->Casos>=PZ.DirCaso->Casos){ / * TempoRalz Clasifica m S Casos
>Errores) ;
lf (strcmp (TempoRaiz->Clase, " " ) & & (TempoRaiz->subraiz==NULL) )
correctamente que P2 * /
>Errores; / * total de casos cublertos * / Casos = ~empoRalz->Casos + TempoRaiz->Errores + P2.DlrCaso->Cas05 + P2.DlrCaso-
if(!strcmp(TempoRaiz->clase,~~.DirCaso->Clase)) / * son iguales * / Errores = TempoRaiz->Errores + P2.DirCaso->Errores;
else / * son diferentes * / Errores = TempoRaiz->Errores + P2.DirCaso->Casos + P2.DlrCaso-
>Errores; PorclentoE2 = U25(Errores,Casos); porclentopodado = Casos * PorcientoE2; / * hojas ya podadas * / PorcientoSlnPodar = (TempoRalz->Casos+TempoRalz->Errores) * POrCientoEl
if(porc1entoPodado < PorcientoSinPodar ) { / * se recomienda podar * / +(P2.DirCaso->Casos+P2.DirCaso->Errores) * P2.PorcientoError;
Podarl(&TempoRa~z,TempoRaiz->Casos+P~.DirCaso->~:a~os,Errores) ;
paquete.PorclentoError = PorclentoE2; paquete.DlrCaso = TempoRalz; If ( (profundldad==l) & & (TempoRaiz->slg==NULL) )
return (paquete) ; 1
paquete.PorcientoError x PorclentoEl; paquete.DirCaso = TempoRaiz; return (paquete) ; ) 1
Podarlho]a=l;
else { / * sin podar * /
else ( / * P2 clasifica m S casos correctamente que TempoRaiz * / Casos = TempoRalz->Casos + TempoRaiz->Errores + P2.DlrCaso->Casos + P2.DirCaso-
1f(!strcmp(TempoRaiz->Clase,P2.DirCaso->Clase)) / * son iguales * /
else / * son dlferentes, se debe verificar cuantas clases son * /
PorclentoE2 = U25(Errores,Casos); / * los errores correctamente * /
>Errores; / * total de casos cubiertos * /
Errores = TempoRalz->Errores + P2.DirCaso->Errores;
Errores = P2.DlrCaso->Errores + TempoRaiz->Casos + TempoRaiz->Errores;
PorcientoPodado = Casos * PorclentoE2; / * holas ya podadas * / PorcientoSlnPodar = (TempoRaiz->Casos+TempoRalz->Errores) * PorclentoEl
+(P2.DlrCaso->Casos+PZ.DirCaso->Errores) * P2.PorclentoError; lf(PorcientoPodado < PorcientoSinPodar ) {
Podar2(&TempoRaiz,TempoRaiz->Casos+PZ.DirCaso->Casos,Errores); paquete.PorclentoError = PorclentoE2;
paquete.DlrCaso = TempoRalz; if((profundldad==l)&&(TempoRalz->sig==NULL))
return (paquete) ; ]
paquete.PorcientoError = PorclentoEl; paquete.DlrCaso = TempoRalz; return (paquete) ; J 1 )
Podarlho]a=l;
else{ / * sln podar * /
else return (paquete) ;
I / * - vold BorrarTemporales(vo1d: {
* /
system("de1 * . xxx") ;
63
MANUAL TECNICO
/ void lee-datos(char nomparch[13])[ ARBOLDECISION RAIZ=NULL, RAIZTEM=NULL;
1n:claArbolDeclslon (&RAIZ) ; In i c l aArbo lDec i s ion (&RAIZTEM); lee-archlvo (nom-arch, &RAIZ, RAIZTEM, O) ; EscRegProd(RAIZ,"reglasn.txt");/* escrlbe las reglas de producciCn a un archivo * / claslflca (nom-arch, &RAIZ) ; / * clasifica casos no vistos * / podar-arbol ( &RAI Z , O) ; / * realiza el podado del arbol * / EscRegProd(RAIZ,"reglasp.txt");/* escribe las reglas de producciCn a un archivo * / BorrarTemporales ( ) ; exlt (1) ;
I . . . . . . . . . . . . . . . . . . . . . . . . . . FUNCIONES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
float l og2 (float x) { lf ( x < Ilmite) return (O ) ; else return (log (x) ) ;
!
SUMAS SumEntropia (int frec, char atrib [ 6 0 ] ) ( /*regresa un arreglo de float's*/ /*~~~~""""~"""-~"""""""""""""~""""-~""""""~-"* /
double numatrlb=O; SUMAS arresum;
arresum.sum1 = O; arresum.sum2 = O;
numatrlb = atof (atrib) ; arresum.sum2 = arresum.sum2 + (numatr1b)"frec; return (arresumj ;
/*~~~"""""""~"""""""~"""""""""""""~~""""""-*/ float determlnaprango(ARBOL CabSalidas,int tot-casos) ( SUMAS arrentrop; float entropia70;
lf (tot casos<=l)
else ( return(l.OE+37);
arrentrop = Fentropla(CabSa1idas); entropia = (arrentrop.sum2*1.0)/(tot-casos*l.O); return (entropla) ; 1
I /*~~~~~~~~~~~~~-~""-""""""""""-----""""""""""""""~-~-*/ SUMAS Fentropla(ARB0L SubRalz)( /*regresa arreglo de float*/
SUMAS lnfoder, infolzq, Infocab;
xnfoder.suml=O; lnfolzq.suml=O; :nf ocab . suml=0 ; lnfoder.sum2=0; infolzq.sum2=0; lnfocab.sum2=0;
lf (SubRalz !=NULL) ( lnfolzq = Fentropla!SubRalz->lzq); lnfocab = SumEntropla(SubRalz->frecuencla,SubRalz~>atrlbuto): lnfoder = Fentropla(SubRalz->der); ~nfo~zq.suml=~nfo~zq.suml+~nfoder.suml+~nfocab.sum~; ~nfo~zq.sum2=~nfo~zq.sum2+~nfoder.sum2+~nfocab.sum2; return(lnfo1zq) ; j
returniinfoizq) ; else
I /*~~~~"""~~~~~~~~""""""""""""""""""""""""""""* /
CAPITULO 5 CODIGO FUENTE
v o l d llsta-destlno(ARBOL *nodo,LISTA origen)( char clase [ 601 ; LISTA aux;
whlle ( orlgen!=NULL) { strcpy (clase, orlgen->clase) ; ~f ( (*nodo) ->slg==NULL) (
(*nodo)->sig=CreaLlsta(clase); aux = (*nodo) - > s l g ; aux->frecclase=origen->frecclase; /*(*nodo)->frecuencla=origen->frecclase;*/ ] / * mucho o10 aqui se encuentra el
error * / else {
orlgen = origen->sig; 1 InsertaLista (clase, & (*nodo) - > s l g ) ; I
i
/*--""_-""-"""""""-"""-""--"""""--""~-""---"""-* / veld arbol-binarlo(f1oat entropi,ARBOL *origen,ARBOL *destino)(
if(*orlgen!=NULL) { arbol-blnario (entropi, & (*origen) ->izq, & (*destino) ) ;
if (atof ( (*origen) ->atributo) <= entropi) { (*destino)->frecuencia = (*destino)->frecuenc~a + (*origen)->frecuencia; llsta-destino(&(*destino),(*origen)->sig); ] / * funcion para llsta * /
(*destino)->der->frecuencia = (*destlno)->der->frecuencia + (*origen)-
llsta-destino(&(*destino)->der,(*orlgen)->sig);] / * funclon para lista * /
else {
>frecuencia;
arbol-blnario (entropl, & (*origen) ->der, & (*destino) ) ; LlberaArbol ( & (*origen) ) ; }
. . . . . . . . . . . . . . . . . . . . . . . . . . PRINCIPAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . / void maln (lnt argv, char *argc [ I )
clrscr ( ) ; gotOxy(20, 9 ) ; prlntf ("PROCESANDO ARCHIVO, ESPERE UN MOMENTO.. . " ) ; lee-datos (argc [ I ] ) ;
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . : I
65
Top Related