Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Algoritmos Genéticos Aplicados A Caracterizacion de Documentos
Algoritmos Genéticos Aplicados A Caracterizacion de Documentos
TESISTA: Sr. Eugenio YOLIS DIRECTOR: Prof. Dr. Ramn GARCIA-MARTINEZ Laboratorio de Sistemas Inteligentes ABRIL 2003
ABRIL 2003
Resumen
La categorizacin automtica de documentos ha estado recibiendo creciente atencin debido al incremento en la cantidad de informacin disponible en forma electrnica y a la necesidad cada vez mayor de encontrar la informacin buscada en un tiempo mnimo. Si bien existen numerosos algoritmos para categorizar documentos, todos ellos evaluan un subconjunto pequeo del espacio de posibles soluciones. Estea tesis presenta un algoritmo gentico adaptado al problema de categorizacin de documentos. El algoritmo propuesto introduce 5 nuevos operadores, diseados especficamente para la resolucin del problema de categorizacin. Los resultados obtenidos demuestran que el algoritmo gentico logra explorar el espacio de bsqueda ms amplia y eficientemente que los algoritmos previos tomados como referencia.
Abstract
Automatic document clustering has been receiving increasing attention due to the growing amount of information available in digital formats, and the importance of finding the information required faster every day. Even though several clustering algorithms have been developed, all of them evaluate just a small part of the solution space. This paper presents an adaption of a genetic algorithm to the document clustering problem. This new algoritm introduces 5 new operators, designed specifically for the problem being solved. The obtained results show that the genetic algorithm achieves a wider and more efficient exploration of the solution space than the previously developed algoritms that were taken as reference.
Keywords: Computation
Automatic
Document
Clustering,
Genetic
Algorithms,
Evolutionary
Indice
CAPTULO 1 ...............................................................................................................................................................7 INTRODUCCIN ......................................................................................................................................................7 1.1 CATEGORIZACIN AUTOMTICA DE DOCUMENTOS...................................................................................... 8 1.1.1 La Hiptesis del Agrupamiento.............................................................................................................8 1.1.2 Aplicaciones..............................................................................................................................................9 1.2 NATURALEZA COMBINATORIA DEL PROBLEMA DE CATEGORIZACIN..................................................... 10 1.3 A LGORITMOS GENTICOS............................................................................................................................... 11 1.4 OBJETIVO DE LA TESIS .................................................................................................................................... 11 1.5 ESTRUCTURA DE LA TESIS .............................................................................................................................. 12 CAPTULO 2 .............................................................................................................................................................15 ESTADO DEL ARTE..............................................................................................................................................15 2.1 CATEGORIZACIN DE OBJETOS...................................................................................................................... 16 2.2 REPRESENTACIN VECTORIAL....................................................................................................................... 16 2.2.1 Definicin del centroide de un grupo ............................................................................................17 2.2.2 Reduccin de la dimensionalidad del espacio de trminos............................................................18
2.2.2.1 Reduccin de palabras a su raz ......................................................................................................... 18 2.2.2.2 Remocin de trminos poco discriminantes ...................................................................................... 19
2.3 M EDIDAS DE SEMEJANZA ............................................................................................................................... 20 2.4 M TODOS PARA CATEGORIZAR DOCUMENTOS............................................................................................ 23 2.5 M TODOS DE CATEGORIZACIN INTRNSECOS............................................................................................ 24 2.5.1 Mtodos Jerrquicos.............................................................................................................................24
2.5.1.1 Enlace simple (single link) ............................................................................................................. 27 2.5.1.2 Enlace completo (complete link).................................................................................................... 28 2.5.1.3 Enlace promedio (average link)...................................................................................................... 28 2.5.1.4 Mtodo de Ward................................................................................................................................. 29 2.5.1.5 Resumen de caractersticas ................................................................................................................ 29
2.6 EL ALGORITMO BISECTING K-M EANS...................................................................................................... 38 2.6.1 Algoritmo Bisecting K-Means con refinamiento..........................................................................39
Eugenio Yolis
INDICE
2.7 INTRODUCCIN A LOS A LGORITMOS GENTICOS....................................................................................... 39 2.7.1 Representacin.......................................................................................................................................42 2.7.2 Generacin de la poblacin inicial.....................................................................................................44 2.7.3 Funcin de adaptacin..........................................................................................................................44 2.7.4 Seleccin..................................................................................................................................................45
2.7.4.1 Seleccin basada en el ranking.......................................................................................................... 45 2.7.4.2 Seleccin por ruleta............................................................................................................................ 46 2.7.4.3 Seleccin por torneo........................................................................................................................... 47
2.7.5 Reproduccin..........................................................................................................................................48
2.7.5.1 Cruza monopunto............................................................................................................................... 49 2.7.5.2 Cruza multipunto................................................................................................................................ 49 2.7.5.3 Cruza uniforme .................................................................................................................................. 50
CAPTULO 3 .............................................................................................................................................................55 DESCRIPCIN DEL PROBLEMA ...................................................................................................................55 3.1 LA BSQUEDA EN EL ESP ACIO DE SOLUCIONES........................................................................................... 55 3.1.1 Problemas de los algoritmos actuales................................................................................................55 3.2 UTILIZACIN DE ALGORITMOS GENTICOS.................................................................................................. 57 3.2.1 Representacin y operadores de cruza...............................................................................................58 3.2.2 Uso del conocimiento del dominio......................................................................................................58 CAPTULO 4 .............................................................................................................................................................61 SOLUCIN PROPUESTA ....................................................................................................................................61 4.1 A DAPTACIONES EXISTENTES.......................................................................................................................... 61 4.1.1 Representacin.......................................................................................................................................61
4.1.1.1 Numeracin de grupo......................................................................................................................... 61 4.1.1.2 Representacin por matriz ................................................................................................................. 62 4.1.1.3 Permutacin con separadores ............................................................................................................. 62 4.1.1.4 Permutacines con bsquedas locales................................................................................................ 63
INDICE
Eugenio Yolis
4.1.6 Mutacin..................................................................................................................................................67 4.2 A LGORITMO PROPUESTO................................................................................................................................ 67 4.2.1 Representacin.......................................................................................................................................67 4.2.2 Estructura del cromosoma....................................................................................................................68 4.2.3 Generacion de la poblacin inicial.....................................................................................................68 4.2.4 Funcion de adaptacin..........................................................................................................................69 4.2.5 Seleccion..................................................................................................................................................69 4.2.6 Cruza ........................................................................................................................................................70
4.2.6.1 Cruza Pasa Grupo............................................................................................................................... 70 4.2.6.2 Anlisis del operador Cruza Pasa Grupo........................................................................................... 72
4.2.7 Mutacin..................................................................................................................................................73
4.2.7.1 Mutacin RefinarKM......................................................................................................................... 73 4.2.7.2 Mutacin Refinar Selectivo ............................................................................................................... 74 4.2.7.3 Mutacin Join..................................................................................................................................... 74 4.2.7.4 Mutacin Split.................................................................................................................................... 75
4.2.8 Insercin de los hijos en la poblacin................................................................................................75 4.2.9 Tamao de la poblacin........................................................................................................................76 4.2.10 Criterio de terminacin.......................................................................................................................76 4.2.11 Algoritmo Gentico con refinamiento.........................................................................................77 CAPTULO 5 .............................................................................................................................................................79 PRUEBA EXPERIMENTAL................................................................................................................................79 5.1 CONJUNTO DE DATOS UTILIZADO .................................................................................................................. 79 5.2 VARIABLES A OBSERVAR ................................................................................................................................ 81 5.2.1 Variables independientes......................................................................................................................81 5.2.2 Variables dependientes.........................................................................................................................82
5.2.2.1 Similitud promedio ............................................................................................................................ 82 5.2.2.2 Entropa.............................................................................................................................................. 83 5.2.2.3 Cantidad de operaciones .................................................................................................................... 85
5.3.2 Parmetros utilizados por el algoritmo gentico.............................................................................88 5.4 RESULTADOS.................................................................................................................................................... 89 5.4.1 Experimentos variando la cantidad de grupos.................................................................................89
Eugenio Yolis
INDICE
5.4.2 Experimentos variando la cantidad de documentos........................................................................93 5.5 A NLISIS DE LOS RESULTADOS...................................................................................................................... 96 CAPTULO 6 .............................................................................................................................................................97 CONCLUSIONES ....................................................................................................................................................97 RESPUESTA A LAS CUEST IONES PLANTEADAS.................................................................................................... 97 REFERENCIAS ..................................................................................................................................................... 101 APNDICE 1 .......................................................................................................................................................... 109 DETERMINACIN DE PARMETROS PARA EL ALGORITMO ................................................... 109 A1.1 PARMETROS A DETERMINAR .................................................................................................................. 109 A1.1.1 generacionesMximo....................................................................................................................... 109 A1.1.2 poblacionTamao............................................................................................................................. 109 A1.1.3 torneoTamao................................................................................................................................... 109 A1.1.4 torneoProbMejor.............................................................................................................................. 110 A1.1.5 cruzaPasaGrupoProbMejor........................................................................................................... 110 A1.1.6 mutacionRefinarKMProb................................................................................................................ 110 A1.1.7 mutacionRefinarSelectivoProb...................................................................................................... 110 A1.2 M ETODOLOGA UTILIZADA ....................................................................................................................... 110 A1.3 RESULTADOS............................................................................................................................................... 112 A1.3.1 generacionesMximo....................................................................................................................... 112 A1.3.2 poblacionTamao............................................................................................................................. 113 A1.3.3 torneoTamao................................................................................................................................... 115 A1.3.4 torneoProbMejor.............................................................................................................................. 116 A1.3.5 cruzaPasaGrupoProbMejor........................................................................................................... 117 A1.3.6 mutacionRefinarKMProb................................................................................................................ 118 A1.3.7 mutacionRefinarSelectivoProb...................................................................................................... 119 APNDICE 2 .......................................................................................................................................................... 121 ANLISIS ESTADSTICO DE LOS RESULTADOS................................................................................ 121 A2.1 PRUEBA DE HIPTESIS ESTADSTICAS...................................................................................................... 121 A2.2 EL TEST DE WILCOXON PARA LA COMPARACIN DE MEDIAS DE MUESTRAS APAREADAS .............. 123 A2.2.1 Introduccin...................................................................................................................................... 123 A2.2.2 Descripcin del test.......................................................................................................................... 123 A2.3 A PLICACIN DEL TEST A LOS RESULTADOS............................................................................................ 125 A2.3.1 Similitud promedio........................................................................................................................... 126
A2.3.1.1 Bisecting K-Means con refinamiento contra Gentico .......................................................... 126
INDICE
Eugenio Yolis
A2.3.1.2 Bisecting K-Means con refinamiento contra Gentico con refinamiento.............................. 126
APNDICE 3 .......................................................................................................................................................... 129 MANUAL DE USO............................................................................................................................................... 129 A3.1 ESQUEMA DE PROCESAMIENTO ................................................................................................................ 130 A3.2 ESTRUCTURA DE DIRECTORIOS DEL CD.................................................................................................. 132 A3.3 CONFIGURACIN DEL ORI GEN DE DATOS ODBC................................................................................... 133 A3.3.1 Copiar el archivo MDB................................................................................................................... 133 A3.3.2 Agregar el origen de datos ODBC ................................................................................................ 133 A3.4 FORMATO DE LOS ARCHIVOS DE DATOS.................................................................................................. 136 A3.5 PROGRAMA A RMAR DATASETS............................................................................................................ 137 A3.6 PROGRAMA AGD OC CLUS..................................................................................................................... 139 A3.6.1 Copia del programa al disco local................................................................................................ 139 A3.6.2 Utilizacin del programa ................................................................................................................ 139 A3.7 PROGRAMA EVALUAR A GRUPAMIENTOS ........................................................................................... 141 APNDICE 4 .......................................................................................................................................................... 143 PROGRAMACIN DE LOS ALGORITMOS ............................................................................................. 143 A4.1 DESCRIPCIN DE LOS MDULOS............................................................................................................... 143 A4.1.1 Mdulo ArchivosTexto................................................................................................................ 143 A4.1.2 Mdulo VecArchivos................................................................................................................... 144 A4.1.3 Mdulo Agrupamiento................................................................................................................ 144 A4.1.4 Mdulo K-Means......................................................................................................................... 145 A4.1.5 Mdulo Gentico......................................................................................................................... 145 A4.1.6 Mdulo Principal......................................................................................................................... 146 A4.2 CDIGO FUENTE.......................................................................................................................................... 147 A4.2.1 ArchivosTexto.h ................................................................................................................................ 147 A4.2.2 ArchivosTexto.cpp............................................................................................................................ 148 A4.2.3 VecArchivos.h ................................................................................................................................... 154 A4.2.4 VecArchivos.cpp............................................................................................................................... 156 A4.2.5 ClsAgrupamiento.h........................................................................................................................... 164 A4.2.6 ClsAgrupamiento.cpp...................................................................................................................... 165 A4.2.7 ClsAgrupImprime.h .......................................................................................................................... 171
Eugenio Yolis
INDICE
A4.2.8 ClsAgrupImprime.cpp...................................................................................................................... 172 A4.2.9 ClsKMeans.h ..................................................................................................................................... 175 A4.2.10 ClsKMeans.cpp............................................................................................................................... 177 A4.2.11 ClsGenetico.h.................................................................................................................................. 196 A4.2.12 ClsGenetico.cpp.............................................................................................................................. 199 A4.2.13 Def.h ................................................................................................................................................. 225 A4.2.14 Sis.h................................................................................................................................................... 227 A4.2.15 SisDos.h ........................................................................................................................................... 228 A4.2.16 SisDos.cpp....................................................................................................................................... 229 A4.2.17 Ppal.cpp........................................................................................................................................... 232
INDICE
Eugenio Yolis
Captulo 1 Introduccin
La Categorizacin de Documentos (Document Clustering) puede definirse como la tarea de separar documentos en grupos. El criterio de agrupamiento se basa en las similitudes existentes entre ellos [Kaufmann et al., 1990]. En la bibliografa consultada, los trminos clasificacin (classification), y categorizacin o agrupamiento
(categorization clustering), son utilizados con distinto significado [Lewis, 1991; Yang, 1997; Maarek et. al., 2000; Clerking et. al., 2001]. El concepto de clasificacin de documentos refiere al problema de encontrar para cada documento la clase a la que pertenece, asumiendo que las clases estn predefinidas y que se tienen documentos preclasificados para utilizar como ejemplos. En la presente tesis, se estudia la categorizacin o agrupamiento de documentos, entendindose por sto el proceso de encontrar grupos dentro de una coleccin de documentos basndose en las similitudes existentes entre ellos, sin un conocimiento a priori de sus caractersticas. Un criterio de agrupamiento utilizado es dividir los documentos en una jerarqua de temas. Un ejemplo de esto ltimo son las categoras que presenta el buscador Yahoo [Rger et. al., 2000]. Un documento en particular se podra encontrar, por ejemplo, dentro de Tecnologa ? Informtica ? Internet ? Buscadores. El problema que presenta esta tcnica es la dificultad de encontrar la categora que mejor describa a un documento [Hearst et. al., 1996]. Los documentos no tratan un slo tema, y aunque lo hicieran, el enfoque con el que el tema es tratado puede hacer que el documento encuadre en otra categora. Esto hace que la categorizacin de documentos sea una tarea compleja y subjetiva, ya que dos personas podran asignar el mismo documento a categoras diferentes, cada una aplicando un criterio vlido [Macskassy et.al., 2001]. Las siguientes secciones de este captulo dan una introduccin al contenido, objetivo y estructura de esta tesis. La seccin 1.1 presenta el problema de la categorizacin automtica de documentos, describiendo su utilidad y las causas que han despertado el inters por resolverlo. En la seccin 1.2 se muestra la imposibilidad de encontrar la solucin al problema de categorizacin automtica mediante una bsqueda exhaustiva, lo que ha llevado a la creacin de algoritmos que encuentran soluciones
Eugenio Yolis
CAPITULO 1 - INTRODUCCION
aproximadas al problema. La seccin 1.3 describe en forma breve qu son los algoritmos genticos, y por qu se cree que pueden aplicarse al problema en estudio. La seccin 1.4 presenta el objetivo de la tesis, y la seccin 1.5, la forma en la que se estructura su contenido en los captulos que la componen.
CAPITULO 1 - INTRODUCCION
Eugenio Yolis
eficacia se basa en la relevancia de los resultados encontrados [Raghavan et. al., 1989]; en el ejemplo del prrafo anterior, una bsqueda eficaz debera retornar todos los documentos que trataran sobre la bsqueda de informacin en internet, an si la palabra buscador no estuviera en el contenido de los mismos. En el contexto del recupero de informacin, Van Rijsbergen [Van Rijsbergen, 1979] formula la denominada Hiptesis del Agrupamiento (en ingls, Cluster Hypothesis); bsicamente, la hiptesis del agrupamiento sostiene que los documentos fuertemente asociados tienden a ser relevantes para la misma consulta, lo cual ha sido verificado experimentalmente [Cutting et. al., 1992; Schtze et. al.,1997; Zamir et. al., 1999]; basndose en dicha hiptesis, la categorizacin automtica tiene en cuenta el contenido de los documentos para agruparlos, ya que documentos similares contendrn palabras (trminos) similares.
1.1.2 Aplicaciones
La categorizacin automtica de documentos se investiga dentro del campo del recupero de informacin como una herramienta capaz de mejorar la calidad de las soluciones ofrecidas. Sus aplicaciones ms importantes son: - Mejorar el rendimiento de los motores de bsqueda de informacin mediante la categorizacin previa de todos los documentos disponibles [Van Rijsbergen, 1979; Dunlop y Van Rijsbergen, 1991; Faloutsos y Oard, 1995; Zamir et. al., 1999; Rger et. al., 2000]. Antes de comenzar a resolver las consultas, el conjunto de documentos es separado en grupos. A cada grupo de documentos se le asigna un representante de grupo; luego, al resolver una consulta, no se examinan todos los documentos, sino que se busca el representante de grupo que mejor responda a la consulta. Por la hiptesis del agrupamiento, el grupo encontrado estar compuesto de los documentos ms relevantes para esa bsqueda. - Facilitar la revisin de resultados por parte del usuario final, agrupando los resultados luego de realizar la bsqueda [Croft, 1978; Cutting et al., 1992; Allen et al., 1993; Leousky y Croft, 1996; Maarek et al., 2000]. Cuando se realizan bsquedas sobre un gran volumen de documentos, la cantidad de resultados puede ser muy grande. Si la
Eugenio Yolis
CAPITULO 1 - INTRODUCCION
lista se presenta sin ningn tipo de procesamiento previo, el usuario del sistema se ver obligado a revisar todos los documentos descartando aquellos que no son relevantes para l. Si los resultados se agrupan, la hiptesis del agrupamiento indica que los documentos del mismo grupo sern relevantes para una subconsulta ms especfica que la original. De esta forma, los documentos quedarn separados en grupos temticos (los grupos son una divisin de los documentos originales, y cada grupo responde a una subconsulta ms especfica dentro del tema buscado) [Rger et. al., 2000]. Asi, con slo revisar uno o dos documentos de cada grupo, el usuario podr determinar cul es el subtema al que responden todos los documentos del grupo, pudiendo descartar rpidamente los documentos irrelevantes para su bsqueda.
Utilizando esta frmula puede calcularse, por ejemplo: S (25,5) = 2 x 1016 , o, dicho en otras palabras, que hay ms de dos mil millones de millones de formas de agrupar 25 objetos en 5 grupos. Los 25 objetos del ejemplo, representan un problema de dimensiones demasiado pequeas para ser de utilidad. En la prctica, se querra aplicar la categorizacin automtica, por lo menos, a varios cientos de documentos. Sin embargo, haciendo algunos clculos sobre este ejemplo de dimensiones pequeas, puede comprenderse la complejidad del problema. Supngase un algoritmo que intente probar todas las posibles categorizaciones para encontrar la mejor de ellas, asignandoles puntajes de acuerdo a un criterio predefinido. Suponiendo que el algoritmo consiga calcular el puntaje de 100 mil soluciones por segundo (el algoritmo tendra que ser muy rpido, pero supngase que lo es), para probar las 2 x 1016 posibilidades, el algoritmo tomara ms de 6 mil aos en dar el resultado.
10
CAPITULO 1 - INTRODUCCION
Eugenio Yolis
Un algoritmo que evale cada una de las posibles categorizaciones no es aplicable en forma prctica a la categorizacin automtica de documentos, por lo que se han desarrollado algoritmos que hacen uso de heursticas [ Cutting et al., 1992; Zamir et. al., 1999; Jain et.al., 1999; Estivill-Castro, 2000; Zhao et.al., 2001] para explorar una parte de estas posibles categorizaciones buscando una solucin de calidad aceptable.
Eugenio Yolis
CAPITULO 1 - INTRODUCCION
11
12
CAPITULO 1 - INTRODUCCION
Eugenio Yolis
propuesto. Este algoritmo emplea algunas de las tcnicas descriptas en la seccin 4.1, pero su caracterstica principal es la utilizacin de los nuevos operadores que se presentan en esta tesis. El captulo 5 describe las pruebas que se realizaron para evaluar la efectividad de la solucin propuesta en el captulo 4. La seccin 5.1 describe los conjuntos de datos utilizados. Los mismos fueron extrados de una coleccin reconocida como un estndar dentro de la comunidad de investigadores dedicados a la categorizacin automtica de documentos. En las secciones 5.2 y 5.3 se detalla la metodologa seguida en la experimentacin. Se enumeran las variables que intervienen en los experimentos y los distintos tipos de experimentos realizados. La seccin 5.4 presenta los resultados de la experimentacin. La presentacin se hace en forma de grficos y para cada variable se incluye adems el resultado del test estadstico realizado sobre los resultados. En la seccin 5.5 se analizan brevemente los resultados, que luego se tratan con ms detalle en el captulo 6. El captulo 6 presenta las conclusiones extradas a partir de la investigacin realizada y los resultados experimentales obtenidos. En esta tesis se propone una adaptacin de un algoritmo gentico al problema de la categorizacin automtica de documentos, que incluye el diseo de un nuevo operador de cruza y cuatro operadores de mutacin. Los resultados experimentales obtenidos confirman la tesis que los algoritmos genticos son una poderosa herramienta para la resolucin de problemas en los cuales el espacio de soluciones es amplio y la funcin de optimizacin es compleja. En el apndice 1 se describen las pruebas realizadas para obtener los parmetros utilizados en el algoritmo propuesto. El apndice 2 detalla el anlisis estadstico realizado sobre los resultados que se exponen en el captulo 5, y que soportan las afirmaciones realizadas en la seccin 5.4 (Resultados) de ese captulo. El apndice 3 contiene la documentacin de los programas y conjuntos de datos que se incluyen en el CD que acompaa la presente tesis. Estos programas hacen posible la realizacin de los experimentos y la evaluacin de los resultados. El apndice 4 detalla la forma en la que se programaron los algoritmos comparados en la prueba experimental. Para realizar la prueba experimental, se desarroll una aplicacin de categorizacin automtica de documentos que permite
Eugenio Yolis
CAPITULO 1 - INTRODUCCION
13
seleccionar qu algoritmo se quiere utilizar. El desarrollo de la aplicacin se realiz en el lenguaje C++. La seccin A4.1 contiene la descripcin de los distintos mdulos en los que se separ la lgica del algoritmo y la interaccin que existe entre los mismos. En la seccin A4.2 se incluye el cdigo fuente de cada mdulo.
14
CAPITULO 1 - INTRODUCCION
Eugenio Yolis
categorizacin automtica de documentos son adaptaciones de los que se utilizan para el problema ms general de categorizar objetos de cualquier tipo. La seccin 2.4 muestra la ubicacin de la categorizacin automtica de documentos dentro de este rea, y detalla los algoritmos utilizados actualmente para categorizar documentos en forma automtica. En la seccin 2.6 se describe un algoritmo presentado recientemente, que supera a los mtodos clsicos, y contra el cual se comparar la solucin propuesta en esta tesis. La seccin 2.7 presenta los principios bsicos de los algoritmos genticos, en los que se basar el algoritmo de categorizacin presentado en esta tesis.
Eugenio Yolis
15
Dado un conjunto S, de N documentos, se quiere encontrar la particin S1 , S2 , ..., Sk, tal que cada uno de los N documentos se encuentre slamente en un grupo Si, y que cada documento sea ms similar a los documentos de su mismo grupo que a los documentos asignados a los otros grupos.
16
Eugenio Yolis
Una forma aceptada [Van Rijsbergen, 1979; Faloutsos et.al., 1995; Jones et.al., 1995] de representar los documentos es asignar a cada atributo del vector la presencia o ausencia del trmino correspondiente. De esta manera, para m trminos el vector consistira en m atributos binarios que pueden tomar valores de cero o uno, segn los trminos que aparezcan o no en el documento. Otra manera es representar a cada documento por su vector de frecuencia de trminos [Steinbach et.al., 2000]: dtf = ( tf1 , tf 2 , ... , tf m ), donde tf i es la frecuencia del trmino nmero i en el documento (cantidad de veces que aparece esa palabra en el documento). De esta forma, se considera que los documentos quedan caracterizados por la cantidad de veces que aparece cada trmino dentro del mismo. Un refinamiento de este modelo consiste en multiplicar a la frecuencia de cada trmino por su frecuencia documental inversa (en ingls, inverse document frecuency). sta tcnica, denominada tf-idf, se basa en la premisa que si un trmino aparece en gran parte de los documentos, es poco discriminante, y por lo tanto, debe restrsele importancia [Faloutsos et.al., 1995; Zhao et.al., 2001]. Asi, la representacin del documento resultara: dt f-idf = ( tf1 log(N / df1 ) , tf2 log(N / df2 ) , ... , tfm log(N / dfm) ), donde N es la cantidad total de documentos de la coleccin y df i es la cantidad de documentos que contienen al trmino i. La normalizacin de los vectores (|| d || = 1) asegura que los documentos se evalen por la composicin de su contenido, sin tener en cuenta su tamao, ya que en los documentos ms extensos, las frecuencias de aparicin de los trminos sern mayores.
s
i =1
vector centroide es el promedio del valor de esa componente para los miembros del
Eugenio Yolis
17
grupo [Steinbach et.al., 2000; Zhao et.al., 2001]; su propiedad ms importante es que la distancia promedio desde un punto cualquiera del espacio hasta cada elemento del grupo es igual a la distancia entre ese punto y el centroide del grupo.
18
Eugenio Yolis
categorizados, para ser utilizados como un conjunto de entrenamiento, por lo que a veces su aplicacin puede no ser posible. A continuacin se describe brevemente cada una de las tcnicas analizadas. a) Umbral de frecuencia documental Es el mtodo ms sencillo. Se calculan las frecuencias con que aparece cada trmino en la coleccin documental y los trminos que no superan cierto umbral mnimo son descartados. Se asume que las palabras muy poco frecuentes no contienen informacin sobre la categora a la que pertenece el documento, o que son trminos ruidosos (que pueden llegar a confundir al algoritmo de agrupamiento).
Eugenio Yolis
19
b) Ganancia de informacin, Informacin mutua, Estadstica X2 Teniendo un conjunto de documentos ya agrupados, para cada trmino se calcula (en base a frmulas probabilsticas) qu tan bueno es para predecir la categora a la que pertenece el documento. El puntaje ms alto es obtenido por aquellos trminos presentes en todos los documentos de una categora y que no aparecen en ningun documento de las dems categoras. Los trminos con puntaje ms bajo (que son aquellos que aparecen por igual en documentos de todas las categoras) son descartados. Los tres mtodos difieren en la forma de calcular los puntajes y normalizar los resultados. c) Fuerza del trmino Usando un grupo de documentos de entrenamiento, se toman aquellos pares de documentos cuya semejanza excede un determinado valor (parmetro del mtodo). Para cada trmino, se cuenta la cantidad de veces que el mismo aparece en ambos
documentos de cada par. En base a eso, se calcula la probabilidad de que el trmino est en el segundo documento del par, sabiendo que est en el primero. Se asignan puntajes ms altos cuanto mayor sea esa probabilidad, asumiendo que el trmino es descriptivo de la categora de esos documentos.
El anlisis comparativo [Yang et al., 1997], usando cada uno de los mtodos de remocin de trminos para diferentes algoritmos de agrupamiento, llega a la conclusin de que las tcnicas de Umbral de frecuencia, Ganancia de informacin y Estadstica X2 obtienen resultados similares, notando que el mtodo de Umbral de frecuencia no requiere documentos previamente clasificados, lo que ampla el rango de situaciones en las que puede ser aplicado.
En el modelo de representacin ms sencillo, en el que los atibutos del vector son valores binarios, y definiendo | v | como la cantidad de atributos de v que toman el valor 1, las medidas ms comunes son: - Coeficiente de Jaccard
d1 d 2 d1 d 2
- Coeficiente del coseno
d1 d 2 d1 d2
Ambas medidas definen el concepto de semejanza de los documentos por la cantidad de trminos en comn que contienen en relacin al tamao de los documentos. En el modelo de representacin ms utilizado [Qin He, 1996; Maarek et.al., 2000; Steinbach et.al., 2000], en el cual se calculan los vectores de frecuencia o de frecuencia inversa, y siendo ||v|| la longitud (norma) del vector v, las medidas ms comunes son [Cole, 1998; Strehl et.al., 2000; Zhao et.al., 2001]: - Coeficiente del coseno extendido
cos(d1 , d 2 ) =
d1 d 2 d1 d 2
Es una extensin del correspondiente del modelo binario para el caso de atributos con valores reales. Esta medida tiene la propiedad de no depender del tamao de los documentos, ya que cos(d1 ,d2 ) = cos(a.d1 ,d2 ) para a > 0. Sin embargo, los documentos se normalizan para que tengan longitud unitaria, ya que entonces,
cos(d1 , d 2 ) = d1 d2
Y la semejanza entre los documentos se puede calcular como el producto vectorial entre ellos. La similitud queda comprendida en el intervalo [0,1]. Para un documento cualquiera, el vector que lo representa es un punto en el espacio. Si se traza la recta que definen ese punto y el eje de coordenadas, todo documento que se encuentre sobre la
Eugenio Yolis
21
recta tiene similitud 1 con el documento que la define. Si se trazan hiperconos concntricos cuyo eje sea esa recta, la semejanza ir decreciendo a medida que se agranda el ngulo del hipercono, y todos los documentos situados en la pared de cada hipercono tienen la misma similitud con el documento que define el eje. La semejanza igual a cero se alcanza cuando el hipercono se convierte en el hiperplano perpendicular al eje que define el documento [Strehl et.al., 2000]. - Coeficiente de Jaccard extendido
jac( d 1 , d 2 ) =
d1
d1 d 2 2 + d 2 ( d1 d 2 )
Es una extensin del coeficiente de Jaccard del modelo binario para el caso de atributos con valores reales. Los valores posibles de similitud se encuentran en el rango [0,1]. Esta medida tiene propiedades intermedias entre el coeficiente del coseno extendido y la distancia Euclideana, que se detalla a continuacin. - Distancia Euclideana
dist _ euc( d 1 , d 2 ) = d 1 d 2
Es la frmula tradicional para calcular el tamao del segmento que une dos puntos. La semejanza de dos documentos queda definida en forma inversa, ya que los documentos ms similares sern los que estn a menor distancia. La frmula comunmente utilizada es:
euc( d 1 , d 2 ) =
1 1 d1 d 2
Los posibles valores de similitud estn en el rango [0,1], pero un documento tiene semejanza igual a 1 slamente consigo mismo. Para un documento cualquiera, el vector que lo representa es un punto en el espacio. Si se trazan hiperesferas concntricas alrededor del punto, todos los documentos ubicados en la superficie de una hiperesfera tienen el mismo valor de similitud con el documento que define el centro. La semejanza decrece a medida que aumenta el radio de las hiperesferas.
22
Eugenio Yolis
En el campo de la categorizacin automtica de documentos, la medida ms utilizada es el coeficiente del coseno extendido [Cutting et.al., 1992; Qin He, 1996; Steinbach et.al., 2000; Zhao et.al., 2001]. Se ha realizado [Strehl et.al., 2000] un anlisis completo de las medidas expuestas anteriormente, comparando el rendimiento de distintos algoritmos de agrupamiento utilizando cada una de las medidas de similitud, llegando a la conclusin de que los coeficientes del coseno y Jaccard extendidos son ms apropiados que la distancia euclideana para espacios de gran dimensionalidad y con datos dispersos, como es el caso del agrupamiento de documentos.
predeterminadas a cada elemento agruparlos en forma significativa, son susceptibles de dividirse segn el esquema de la figura 2.1 [Qin He, 1996]:
Clasificaciones
No exclusivas
Exclusivas
Extrnsecas
Intrnsecas
Jerrquicas
Particionales
Eugenio Yolis
23
- No exclusivas : Un mismo objeto puede pertenecer a varias categoras, clases o grupos. - Exclusivas : Cada objeto pertenece solamente a una categora, clase o grupo.
- Extrnsecas (supervisadas) : Las clases a las que pertenecen los objetos estn predefinidas, y se conocen ejemplos de cada una, algunos de los objetos ya estn clasificados y son utilizados por el algoritmo para aprender a clasificar a los dems. - Intrnsecas (no supe rvisadas) : La clasificacin se realiza en base a las caractersticas propias de los objetos, sin conocimiento previo sobre las clases a las que pertenecen.
- Jerrquicas : Los mtodos jerrquicos consiguen la categorizacin final mediante la separacin (mtodos divisivos) o la unin (mtodos aglomerativos) de grupos de documentos. As, estos mtodos generan una estructura en forma de rbol en la que cada nivel representa una posible categorizacin de los documentos [Willet, 1998] - Particionales (no jerrquicas) : Los mtodos no jerrquicos, tambien llamados particionales, o de optimizacin llegan a una nica categorizacin que optimiza un criterio predefinido o funcin objetivo, sin producir una serie de grupos anidados [Everitt, 1993].
La categorizacin automtica de documentos se encuentra en la categora intrnseca, ya que los criterios de agrupamiento se basan en la informacin contenida en los mismos para determinar sus similitudes
24
Eugenio Yolis
de la coleccin [Jain et.al., 1999]. Cada vrtice (nodo) del rbol es un grupo de elementos. La raz del rbol (primer nivel) se compone de un slo grupo que contiene todos los elementos. Cada hoja del ltimo nivel del rbol es un grupo compuesto por un slo elemento (hay tantas hojas como objetos tenga la coleccin). En los niveles intermedios, cada nodo del nivel n es dividido para formar sus hijos del nivel n + 1. Las figuras 2.2 y 2.3 ilustran estos conceptos mediante un ejemplo simple.
A E
F D
ABCDEF
A C E F
B D
A C E F
A E
F C
F C
A A E F C B D
Fig 2.3. Posible dendograma para la coleccin de la figura 2.2 y agrupamientos que representa cada nivel.
Los algoritmos de agrupamiento jerrquicos fueron uno de los primeros enfoques para los problemas de categorizacin de documentos, y todava se siguen utilizando debido a la forma simple e intuitiva en la que trabajan [Dash et.al., 2001]. De acuerdo a la metodologa que aplican para obtener el dendograma, los algoritmos jerrquicos pueden dividirse en aglomerativos y divisivos [Han, 2001].
Eugenio Yolis
25
Los mtodos aglomerativos parten de las hojas del rbol, ubicando a cada elemento en su propio grupo, y en cada paso buscan los dos grupos ms cercanos para juntarlos. Los divisivos, por su parte, hacen el camino inverso. Comenzando en la raz, en cada paso seleccionan un grupo para dividirlo en dos, buscando que el agrupamiento resultante sea el mejor de acuerdo a un criterio predeterminado. El anlisis necesario para pasar de un nivel a otro (decidir q grupo dividir o cuales juntar) es ms sencillo u para los mtodos aglomerativos [Dash et.al., 2001], y esto hace que stos sean ms utilizados que los divisivos [Fasulo, 1999; Steinbach et.al., 2000]. En adelante, cuando se hable de mtodos jerrquicos, se har referencia nicamente a los algoritmos de Agrupamiento Jerrquico Aglomerativo (HAC, su sigla en ingls). Las distintas variantes de algoritmos jerrquicos aglomerativos difieren
nicamente en la manera de determinar la semejanza entre los grupos a seleccionar los l dos grupos ms cercanos [ in He, 1996; Willet, 1998; Cole, 1998; Jain et.al., 1999; Q Fasulo 1999]. Debe notarse la diferencia entre medidas de semejanza entre documentos y medidas de semejanza entre grupos. La similitud de dos grupos se calcula en base a los valores de semejanza existentes entre sus documentos, pero la forma de hacer este clculo no es nica. Dada una medida de semejanza entre documentos, que puede considerarse la misma para todos, los distintos algoritmos jerrquicos aglomerativos se distinguen por la medida de semejanza entre grupos que utiliza cada uno. La figura 2.4 presenta un espacio bidimensional en el cual se han colocado 4 grupos de objetos. Los objetos de un mismo grupo se han representado mediante el mismo smbolo (x, *, # +).
+ + +
x x x # # # # #
* * * ** * * ** * *
*
Fig 2.4 Cuatro grupos de objetos en un espacio de 2 dimensiones
26
Eugenio Yolis
Las figuras 2.5, 2.6 y 2.7 muestran cmo los mtodos pueden diferir entre ellos al seleccionar cules son los grupos ms semejantes. En las figuras se utiliza la distancia Euclideana como medida de semejanza entre los documentos. La d isposicin presentada de los grupos se ha elegido especialmente para provocar las diferencias, si los grupos estn suficientemente separados y son compactos todos los mtodos coinciden en la seleccin de los grupos ms cercanos.
+ + +
x x x # # # # #
* * * ** * * ** * *
Fig 2.5 Distancias al grupo de las x segn el mtodo de enlace simple. La distancia entre los grupos ms cercanos est remarcada.
Eugenio Yolis
27
+ + +
x x x # # # # #
* * * ** * * ** * *
Fig 2.6
Distancias al grupo de las x segn grupos el mtodo de enlace est completo. La distancia entre los ms cercanos
remarcada.
+ + +
x x x # # # # #
* * * ** * * ** * *
Fig 2.7
Distancias al grupo de las x segn grupos el mtodo de enlace est promedio. La distancia entre los ms cercanos
remarcada.
28
Eugenio Yolis
Ws = || si C s || 2
i =1
W = Wi
i =1
Al comenzar el algoritmo, la suma de errores cuadrados vale cero, ya que cada elemento forma su propio grupo y coincide con el centroide. En cada paso, el mtodo evala cada una de las posibles uniones y elige aquella que produce el menor incremento del error. Este mtodo tiende a producir grupos de tamaos iguales, y su rendimiento es comparable al del mtodo de enlace promedio [Cole, 1998].
a) Su forma de trabajo es simple e intuitiva El enfoque utilizado por estos mtodos es semejante al que utilizara una persona para realizar la tarea del agrupamiento, especialmente los aglomerativos (comenzar juntando los documentos ms similares entre si, y luego buscar similitudes entre los grupos).
b) Su resultado es una serie de agrupamientos anidados Esto facilita la revisin de los resultados por parte del usuario, que puede recorrer la estructura de rbol para ver agrupamientos con diferentes niveles de detalle [Maarek et.al., 2000].
Eugenio Yolis
29
c) Son deterministas Al aplicar dos veces un algoritmo jerrquico a una coleccin de documentos, las dos veces seguir el mismo camino hacia la solucin. Hay algunos agrupamientos que el algoritmo nunca considerar, sin importar la cantidad de veces que se lo ejecute [Steinbach et.al.,2000].
d) No revisan las decisiones que toman en los pasos anteriores Una vez que dos documentos se han asignado al mismo grupo (o se han colocado en distintos grupos, en los divisivos), ningn paso posterior los volver a separar (o juntar), por lo que una mala asignacin en los primeros pasos no puede corregirse [Cole, 1998].
e) Requieren grandes tiempos de cmputo La forma de buscar en cada paso los grupos a unir (o dividir, en los divisivos), hacen que las implementaciones conocidas de estos algoritmos tengan tiempos de ejecucin del orden de n2 (enlace simple) n3 (enlace completo) [Zamir et.al., 1998].
30
Eugenio Yolis
La estructura general de stos mtodos se compone de los siguientes pasos [Han et.al., 2001]: 1) Seleccionar k puntos representantes (cada punto representa un grupo de la solucin). 2) Asignar cada elemento al grupo del representante ms cercano, de forma de optimizar un determinado criterio. 3) Actualizar los k puntos representantes de acuerdo a la composicin de cada grupo. 4) Volver al punto 2)
Este ciclo se repite hasta que no sea posible mejorar el criterio de optimizacin.
(ms rpido); las tcnicas Buckshot y Fractionation [Cutting et.al., 1992] son un ejemplo de esto ltimo.
Eugenio Yolis
31
frecuentemente
Criterios internos
Los criterios internos dan una medida de la cohesin interna de los grupos. Para cada grupo se calcula un valor en base a los objetos que lo componen (sin tener en cuenta elementos de otros grupos), y luego se suman los valores de cohesin de cada uno.
a) Maximizacin de la suma de similitudes promedio Para cada grupo se calcula el promedio de las similitudes que existen entre cada par de documentos que lo componen. Por ejemplo, para el grupo S, que tiene ns elementos:
Este criterio toma valores ms altos cuando los elementos de cada grupo son ms similares entre s.
32
Eugenio Yolis
b) Maximizacin de la suma de las similitudes con el centroide Para cada grupo se calcula la suma de las similitudes que existen entre cada elemento y el centroide. Por ejemplo, para el grupo S:
El valor total para el criterio se obtiene sumando las similitudes promedio de cada grupo.
Los valores ms altos se alcanzan cuando cada objeto se encuentra cerca del centro de su grupo.
c) Minimizacin de la suma de errores cuadrados Este criterio es el mismo que utiliza el mtodo de Ward, que se analiza en la seccin 2.5.1, dedicada a los mtodos jerrquicos.
Eugenio Yolis
33
Criterios externos
Los criterios externos tienen en cuenta la separacin que existe entre los distintos grupos. Se considera que un agrupamiento es mejor que otro cuando sus grupos estn ms separados del centro de la coleccin.
a) Minimizacin de la similitud de los centroides con centroide de la coleccin Este criterio calcula la similitud existente entre el centroide de cada grupo y el centro de la coleccin, y luego suma los valores multiplicados por el tamao de cada grupo.
b) Maximizacin de la distancia de los centroides al centroide de la coleccin En lugar de minimizar las similitudes, este criterio intenta maximizar las distancias.
ext _ dist = || C i C ||
i= 1
En [Zhao et.al., 2001] se evala cada uno de los criterios detallados, aplicados al agrupamiento de colecciones de documentos. El criterio interno de maximizacin de la suma de similitudes con el centroide (que es el que se utiliza ms comunmente en la bibliografa), obtiene los mejores resultados al aplicar cada uno de los criterios en forma individual. El trabajo propone una combinacin de ste criterio con el criterio externo de minimizacin de la similitud de los centroides con el centro de la coleccin, que mejora el rendimiento del algoritmo de agrupamiento, produciendo grupos de tamaos ms balanceados.
34
Eugenio Yolis
Algoritmo K-means
Este algoritmo, presentado originalmente por [McQueen, 1967], utiliza a los centroides de cada grupo como sus puntos representantes. Partiendo de una seleccin inicial de k centroides (que pueden ser k elementos de la coleccin seleccionados al azar, o los que se obtengan mediante la aplicacin de alguna tcnica de inicializacin), cada uno de los elementos de la coleccin se asigna al grupo con el centroide ms cercano. A continuacin, se calcula el centroide de cada uno de los grupos resultantes. En los primeros pasos se obtienen las mayores diferencias entre los centroides originales y los calculados luego de las reasignaciones. Los puntos de la coleccin vuelven a asignarse al grupo del centroide ms cercano, y estos pasos se repiten hasta que los k centroides no cambian luego de una iteracin (sto es equivalente a decir que el valor de la funcin utilizada como criterio de optimizacin no vara). El algoritmo k-means encuentra una categorizacin que representa un ptimo local del criterio elegido [Bradley et.al., 1998]. Las figuras 2.8, 2.9, 2.10 y 2.11 ilustran la forma de trabajo del algoritmo. En ellas puede verse cmo una iteracin del algoritmo refina el agrupamiento. Los objetos de la coleccin estn representados mediante signos +, y los centroides de cada grupo con los signos X. En la figura 2.8 se muestran los objetos de la coleccin y los centroides que el algoritmo ha encontrado hasta el paso N. En la figura 2.9, cada objeto de la coleccin se ha asignado al grupo con el centroide ms cercano. Los nuevos centroides, calculados a partir de la composicin de los grupos, se grafican en la figura
Eugenio Yolis
35
2.10. En la figura 2.11 puede verse la situacin inicial para el paso N+1. En ste paso, el algoritmo encontrar los 3 grupos claramente definidos que existen en la coleccin. La disposicin de los objetos se ha elegido especialmente para que la mejora en el agrupamiento sea evidente.
+ + + X + +
X +
+ + + X
+ + + X + +
X +
+ + + X
Fig 2.9 Los objetos de la coleccin se asignan al grupo del centroide ms cercano
+ + + X + + + X
X +
+ + +
36
Eugenio Yolis
+ + + X + + + X
X +
+ + +
a) Pueden ser no deterministas. Partiendo del mismo agrupamiento inicial, los mtodos llegarn siempre a la misma solucin. Sin embargo, los mtodos para la seleccin inicial son no deterministas. El algoritmo evaluar diferentes agrupamientos cada vez que se lo ejecute, y (si los grupos no estn claramente separados) podr llegar a soluciones distintas [Steinbach et.al., 2000].
b) Pueden corregir errores cometidos en pasos anteriores En cada paso del algoritmo los objetos de la coleccin se asignan al grupo ms apropiado segn el criterio de optimizacin. De esta manera, el algoritmo va refinando el agrupamiento en cada iteracin [Qin He, 1996].
c) Pueden implementarse en forma eficiente Las restricciones de recursos son la causa principal por la que se utilizan este tipo de mtodos. Estos algoritmos pueden implementarse de forma que sus tiempos de ejecucin sean del orden de n [Han et.al., 2001].
Eugenio Yolis
37
El algoritmo Bisecting K-Means sigue los siguientes pasos: 1) Colocar todos los documentos en un slo grupo 2) Elegir el grupo ms grande para dividirlo. 3) Dividir el grupo en 2 subgrupos usando el algoritmo K-Means (paso de biseccin). 4) Repetir el paso de biseccin 5 veces, y tomar la divisin que lleve a una mayor similitud promedio. 5) Repetir los pasos 2, 3 y 4 hasta alcanzar el nmero de grupo deseado.
Al utilizar el algoritmo K-Means para formar slamente 2 grupos cada vez, y repetir 5 veces cada divisin, se intenta atenuar la dependencia de este algoritmo con la seleccin inicial de los representantes.
38
Eugenio Yolis
Espacio de cromosomas
Espacio de soluciones
C1 C4 C3 CM
Fig 2.12 - Cada cromosoma codifica una posible solucin al problema
C2
S2 S1 SN S3
Eugenio Yolis
39
El algoritmo gentico va creando nuevas generaciones de esta poblacin, cuyos individuos son cada vez mejores soluciones al problema. La creacin de una nueva generacin de individuos se produce aplicando a la generacin anterior operadores genticos, adaptados de la gentica natural. La figura 2.13 representa el esquema de funcionamiento del algoritmo gentico. El proceso comienza seleccionando un nmero de cromosomas para que conformen la poblacin inicial. A continuacin se evala la funcin de adaptacin para estos individuos. L funcin de adaptacin da una a medida de la aptitud del cromosoma para sobrevivir en su entorno. Debe estar definida de tal forma que los cromosomas que representen mejores soluciones tengan valores ms altos de adaptacin. Los individuos ms aptos se seleccionan en parejas para reproducirse. La reproduccin genera nuevos cromosomas que combinan caractersticas de ambos padres. Estos nuevos cromosomas reemplazan a los individuos con menores valores de adaptacin. A continuacin, algunos cromosomas son seleccionados al azar para ser mutados. La mutacin consiste en aplicar un cambio aleatorio en su estructura. Luego, los nuevos cromosomas deben incorporarse a la poblacin; estos cromosomas deben reemplazar a cromosomas ya existentes. Existen diferentes criterios que pueden utilizarse para elegir a los cromosomas que sern reemplazados. El ciclo de seleccin, reproduccin y mutacin se repite hasta que se cumple el criterio de terminacin del algoritmo, momento en el cual el cromosoma mejor adaptado se devuelve como solucin (ver figura 2.13).
40
Eugenio Yolis
Seleccin de los individuos a reproducir Repetir hasta que se cumpla el criterio de terminacin Mutacin
Reproduccin
Mejor cromosoma
Decodificacin
Solucin
Eugenio Yolis
41
2.7.1 Representacin
El esquema de representacin es el que define de qu forma se corresponden los cromosomas con las soluciones al problema. Para disear el esquema de representacin, se buscan los parmetros que identifican a las soluciones, y luego se codifican estos parmetros dentro del cromosoma. 0 1 1 0 0 0 1 1 0 1
3 lados 1 0 1 0 0
13 mm 1 0 0 1 1
5 lados
19 mm
Fig 2.14 - Ejemplo de un esquema de representacin para polgonos regulares
La figura 2.14 muestra un posible esquema de representacin para un problema que tiene como soluciones a los polgonos regulares. Los parmetros que identifican a cada solucin son 2 (cantidad de lados y longitud del lado), y estos se codifican en el cromosoma en forma binaria. El cromosoma se compone de una cadena de 10 bits, en los que los primeros 3 son la cantidad de lados, y los siguientes 7 bits representan la longitud de los lados en milmetros. El esquema de representacin debera ser tal que exista al menos una posible codificacin para cada una de las soluciones posibles. Las soluciones que no estn dentro del espacio de cromosomas no sern exploradas por el algoritmo gentico. En el ejemplo de la figura 2.14, el algoritmo gentico no explorar soluciones que se compongan por polgonos de ms de 7 lados ni longitudes mayores a 127 milmetros, ya que con 3 y 7 bits pueden codificarse solamente nmeros del 0 al 7, y del 0 al 127, respectivamente. Por el mismo motivo (porque la bsqueda se hace sobre el espacio de cromosomas), es deseable que no haya redundancia en la representacin; que cada solucin sea representada por solamente un cromosoma. Si existen k cromosomas por
42
Eugenio Yolis
cada solucin, el espacio de bsqueda sobre el que opera el algoritmo gentico es k veces ms grande que el espacio de soluciones, haciendo ms lento el proceso de evolucin. La representacin ejemplificada en la figura 2.14 no tiene redundancia, cada polgono es representado slo por un cromosoma. Otro problema que puede presentarse es que haya cromosomas que no representan ninguna solucin. En el ejemplo de la figura 2.14, un cromosoma que tenga todos 0 en los primeros 3 en los ltimos 7 bits no representa un polgono vlido. En caso de que la representacin lo permita, los operadores del algoritmo gentico deben adaptarse para tratar con este tipo de cromosomas. La codificacin ejemplificada en la figura 2.14 se denomina binaria, ya que cada posicin del cromosoma contiene un bit. Esta es la representacin clsica propuesta por los primeros autores y que todava es utilizada ampliamente [Goldberg, 1989; Cole, 1998; Falkenauer, 1999]. Sin embargo, hay problemas para los cuales esta representacin no es la ms conveniente. El funcionamiento de los algoritmos genticos est basado en lo que se denomina la hiptesis de los bloques constructores [Goldberg, 1989]. Esta hiptesis requiere que los cromosomas se compongan por bloques significativos que codifiquen las caractersticas de la solucin lo ms independientemente posible. El ejemplo de la figura 2.14 es un claro ejemplo de una representacin que no cumple con esta premisa. Sera ms apropiado un esquema en el cual el cromosoma se componga por 2 nmeros enteros, uno de los cuales codifique el nmero de lados y el otro la longitud. La figura 2.15 muestra esta representacin.
3 3 5 5
13 13 mm 19 19 mm
Eugenio Yolis
43
denomina convergencia prematura: el algoritmo gentico encontrar una solucin sin haber explorado suficientemente el espacio de bsqueda. Sin embargo, a medida que la aptitud promedio va subiendo, el problema ser diferente. La diferencia ir decreciendo, y los cromosomas ms aptos obtendrn valores de adaptacin similares a los de los dems cromosomas, reduciendo la probabilidad de que el algoritmo gentico seleccione a los mejores individuos para la reproduccin. Los dos problemas pueden corregirse aplicando una funcin de escala a la funcin de adaptacin. La funcin de escala lineal calcula la nueva funcin de adaptacin f a partir de la funcin de adaptacin f usando la transformacin lineal f = a.f + b. Las constantes a y b se eligen de forma tal que el promedio de las dos funciones sea el mismo, y que el mximo para la funcin f asegure la diferencia de probabilidades deseada entre los elementos ms aptos y el promedio.
2.7.4 Seleccin
La seleccin de los individuos que van a reproducirse se realiza mediante un operador de seleccin. El operador de seleccin hace la eleccin basndose en los valores de adaptacin de los individuos. Existen distintos operadores de seleccin que pueden utilizarse [Miller et.al., 1995], de los cuales se describen los ms comunes.
Eugenio Yolis
45
C1 2,8
C2 10
C3
C4
C5 6
Totales 44,4 1
22,5 3,1
Nro Azar 1
Nro Azar 2
C1
0 0,07
C2
0,3
C3
0,8
C4
0,87
C5
1
El operador de seleccin por ruleta puede requerir la aplicacin de una funcin de escala sobre la funcin de adaptacin, ya que los segmentos son dimensionados en funcin del valor absoluto de aptitud de cada individuo.
46
Eugenio Yolis
Eugenio Yolis
47
2.7.5 Reproduccin
La fase de reproduccin se implementa por medio de un operador de reproduccin. El operador de reproduccin es el encargado de transferir el material gentico de una generacin a la siguiente. Es este operador el que confiere a la bsqueda de soluciones mediante algoritmos genticos su caracterstica ms distintiva
[Falkenauer, 1999]. A diferencia de otros mtodos de optimizacin, los algoritmos genticos no solamente exploran el vecindario de las buenas soluciones, sino que recombinan sus partes para formar nuevas soluciones. Se ha hecho notar que el descubrimiento de nuevas teoras combinando nociones ya conocidas es un mecanismo que el hombre ha utilizado constantemente a lo largo de la evolucin de la ciencia [Goldberg, 1989]. El objetivo de los operadores de reproduccin es, partiendo de dos cromosomas padres, generar uno o ms cromosomas hijos que hereden caractersticas de ambos padres, como se muestra en la figura 2.17. Se dice que en el hijo se recombinan las caractersticas de los padres. Si las caractersticas se traspasan en bloques significativos, se espera que un hijo que recombina caractersticas de buenas soluciones sea una buena solucin, tal vez mejor que cualquiera de sus padres [Falkenauer, 1999].
Padre 1
A1 A2 A3 A4 A5 A6 A7 A8 B1 B2 B3 B4 B5 B6 B7 B8 Recombinacin
Padre 2
Hijo
A1 A2 B3 A4 B5 A6 A7 B8
Fig 2.17 - En la recombinacin, el hijo hereda caractersticas de ambos padres
Los operadores de reproduccin ms tpicos generan dos hijos a partir de dos padres. A continuacin se describen los ms utilizados.
48 CAPITULO 2 ESTADO DEL ARTE Eugenio Yolis
C=3
Padre 1
A1 A2 A3 A4 A5 A6 A7 A8 B1 B2 B3 B4 B5 B6 B7 B8 Cruza monopunto
Padre 2
Hijo
1 2
A1 A2 A3 B4 B5 B6 B7 B8 B1 B2 B3 A4 A5 A6 A7 A8
Hijo
eligen M puntos de corte al azar, y las secciones de cada padre se pasan a los hijos en forma alternada. La figura 2.19 ejemplifica este procedimiento, para el caso en que M es igual a 2.
Eugenio Yolis
49
C 1= 2
C 2= 5
Padre 1
A1 A2 A3 A4 A5 A6 A7 A8 B1 B2 B3 B4 B5 B6 B7 B8 Cruza multipunto
Padre 2
Hijo
1 2
A1 A2 B3 B4 B5 A6 A7 A8 B1 B2 A3 A4 A5 B6 B7 B8
Hijo
50
Eugenio Yolis
2.7.6 Mutacin
La mutacin de cromosomas (junto con la generacin de la poblacin inicial) es la encargada de proveer al sistema de material gentico. La mutacin se implementa mediante un operador de mutacin. El operador de cruza genera nuevas soluciones intercambiando bloques de las soluciones existentes, pero sin el operador de mutacin, el algoritmo gentico no tendra forma de crear nuevos bloques. Este operador es el que permite que la exploracin del espacio de bsqueda sea amplia. El operador de mutacin trabaja a nivel de bloque dentro de los cromosomas, haciendo cambios aleatorios de acuerdo a una probabilidad PM (probabilidad de mutacin). La naturaleza del cambio depende de la composicin de los bloques de los cromosomas. Si cada bloque es un bit (en la codificacin binaria), el nico cambio posible es invertir su valor. Si los bloques son nmeros reales, la modificacin podra ser la suma o sustraccin de un pequeo valor aleatorio.
Eugenio Yolis
51
Insercin uniforme Los cromosomas a ser reemplazados se eligen al azar entre los miembros de la poblacin. Se corre el riesgo de eliminar buenas soluciones, ya que no se tiene en cuenta la aptitud de los cromosomas.
Insercin elitista Se eligen los cromosomas menos aptos para ser reemplazados. Este mtodo asegura que los mejores cromosomas pasarn siempre a la siguiente generacin, pero puede restringir la amplitud de la bsqueda que realiza el algoritmo gentico.
Insercin por torneo invertido Se utiliza en combinacin con el mtodo de seleccin por torneo. Funciona exactamente igual que el mtodo de seleccin por torneo pero seleccionando con probabilidad p al peor cromosoma del torneo para ser reemplazado, y tiene las mismas propiedades que ste, permitiendo regular la presin selectiva sin el uso de funciones de escala.
52
Eugenio Yolis
Eugenio Yolis
53
grande para llegar a la convergencia, dependiendo de las tasas de reproduccin y mutacin. Utilizando cualquiera de los dos criterios anteriores no puede estimarse un nmero mximo de generaciones, ya que esto depender parmetros del algoritmo gentico sino tambien del azar. Esto puede ser un problema, sobre todo si se quieren comparar los tiempos de resolucin de un problema mediante algoritmos genticos con otros mtodos [EstivillCastro, 2000]. El criterio de terminacin por cantidad de generaciones consiste simplemente en finalizar la ejecucin una vez que ha transcurrido un nmero determinado de generaciones. Este mtodo permite determinar con precisin los tiempos de ejecucin del algoritmo a costa de detener la evolucin sin la certeza de que las soluciones no seguirn mejorando. no solamente de los
54
Eugenio Yolis
Eugenio Yolis
55
Algoritmo K-Means El algoritmo K-Means es mucho ms eficiente (los tiempos de cmputo requeridos son lineales con la cantidad documentos a agrupar [Han et.al., 2001]), pero es dependiente de la seleccin inicial de centroides [Bradley, 1998]. Sus resultados pueden ser bastante pobres y suelen variar mucho si se aplica varias veces a la misma coleccin de documentos, ya que si la seleccin de centroides al azar es mala, la solucin encontrada tambin lo ser.
Algoritmo Bisecting K-Means Aunque este algoritmo ha demostrado obtener mejores soluciones que el algoritmo k-means y los mtodos jerrquicos aglomerativos [Steinbach et.al., 2000], en tiempos de cmputo lineales con la cantidad de documentos a agrupar, la forma en que explora el espacio de bsqueda es claramente sub-ptima. Al momento de dividir un
grupo, el algoritmo Bisecting K-Means realiza 5 divisiones diferentes del grupo (aplicando 5 veces el algoritmo K-Means con k=2 a los elementos del grupo), y luego elige una de ellas (la que ms hace crecer el criterio de optimizacin), descartando las dems divisiones que cre. El siguiente anlisis muestra por qu esta forma de trabajo no es eficiente: Cuando el grupo es fcilmente divisible (hay 2 subgrupos claramente definidos), las 5 corridas del algoritmo K-Means encontrarn la misma divisin, o divisiones con muy pocas variaciones. En este caso, el algoritmo estara repitiendo 5 veces el mismo trabajo. Cuando no hay dos subgrupos claramente definidos, las 5 corridas del algoritmo K-Means encontrarn divisiones diferentes. En este caso, el problema es que el algoritmo Bisecting K-Means no tiene ningn mecanismo para aprovechar el trabajo realizado al armar las divisiones que son descartadas. Es muy posible que en alguna de ellas haya encontrado un grupo excelente y uno muy malo que en promedio hagan que descarte esa divisin, y no tiene ningn mecanismo que le permita quedarse con la parte buena y descartar slo lo malo.
56
Eugenio Yolis
Estos problemas de los algoritmos actuales dan lugar a las siguientes cuestiones:
Cuestin 1: Pueden ayudar los algoritmos genticos a explorar el espacio de bsqueda en forma ms eficiente? Cuestin 2: Pueden ayudar los algoritmos genticos a encontrar soluciones de mejor calidad?
Eugenio Yolis
57
Esto lleva a plantear la cuestin: Cuestin 3: De qu manera puede definirse la representacin de las soluciones y el operador de cruza para que el algoritmo gentico pueda ser aplicado a la categorizacin automtica de documentos de acuerdo a la hiptesis de los bloques constructores?
58
Eugenio Yolis
que explorar todo el espacio de bsqueda, ya que lo gua por aquellos sectores en los cuales las soluciones son significativas. Sin la aplicacin de conocimiento especfico del problema que se est resolviendo en los operadores, es casi imposible que el algoritmo gentico supere en trminos de eficiencia a los algoritmos diseados ad hoc para el problema [Goldberg, 1989; Estivill-Castro, 2000]. Sin embargo, solamente un trabajo hace uso de este conocimiento [Estivill-Castro, 2000], aunque falla en reconocer la importancia de la sensibilidad al contexto del operador de cruza.
Lo expuesto en esta seccin da lugar a la siguiente cuestin: Cuestin 4: De qu manera pueden disearse los operadores del algoritmo gentico para hacer uso del conocimiento especfico del dominio?
Eugenio Yolis
59
4.1.1 Representacin
Los mtodos ms comunes para codificar un agrupamiento en un cromosoma son los siguientes:
Eugenio Yolis
61
Pero en un agrupamiento no importa el nmero de cada grupo, sino slamente cules objetos contiene cada uno, por lo que el siguiente cromosoma representa el mismo agrupamiento:
0 1
0 1
1 0
0 1
1 0
62
Eugenio Yolis
Suponiendo que el agrupamiento usado como ejemplo sea el mximo local para esa bsqueda. Estos mtodos tienen ciertas particularidades que deben tenerse en cuenta: Puede suceder que haya agrupamientos imposibles de codificar con estos esquemas (que no se pueda encontrar una permutacin para la cual ese agrupamiento sea el mximo local). Los algoritmos de bsqueda local ms comunes son del orden de (nk) o de (n2 k) [Cole, 1998].
Eugenio Yolis
63
4.1.4 Seleccin
En el captulo 2 (Estado del arte), seccin 2.7.4, se describen los distintos operadores de seleccin que utilizan los algoritmos genticos. No se encuentran operadores de seleccin especialmente adaptados al problema, en los trabajos previos que aplicaron los algoritmos genticos a la categorizacin automtica.
4.1.5 Cruza
Se detallan los operadores de cruza utilizados habitualmente para la
64
Eugenio Yolis
estos mtodos presentan un problema denominado insensibilidad al contexto [Falkenauer, 1999] . Este problema surge del hecho de que la cruza opera sobre los cromosomas sin tener en cuenta qu es lo que estos cromosomas representan. Asi, el cromosoma hijo tiene elementos de los cromosomas padres, pero el agrupamiento representado por el hijo tiene muy poco (o nada) en comn con los agrupamientos representados por los padres, como muestra el ejemplo siguiente:
Como los dos padres representan el mismo agrupamiento, con los grupos {1,2,4} y {3,5}, se esperara que el hijo represente el mismo agrupamiento. Sin embargo representa un agrupamiento distinto, que contiene los grupos {1,2,3,5} y {4}. Una forma de intentar resolver el problema es renumerar los grupos de cada padre en forma cannica (por ejemplo, de forma ascendente, de izquierda a derecha) antes de realizar la cruza [Jones et.al., 1991]. En ese caso, los dos cromosomas padres del ejemplo anterior seran idnticos. Sin embargo, hay casos en los cuales esto no es suficiente:
Eugenio Yolis
65
En este caso, los cromosomas padres ya estn numerados en forma cannica. El grupo {3,4,5,6} se repite en los dos padres, por lo que se esperara que pase al hijo sin cambios. Sin embargo, en el agrupamiento resultante el grupo se ha dividido.
Las intersecciones no vacas entre los grupos sern: { 1 } , { 2 } , { 3, 4, 5, 6 } , { 7 } Como son 4 intersecciones, y el hijo debe tener 3 grupos (al igual que los padres), deben juntarse 2 de las intersecciones. Puede verse que en ningn caso el grupo que es comn entre los dos padres puede dividirse. Si juntamos las intersecciones { 2 } y { 7 }, el hijo ser 1 2 3 3 3 3 2
Sin embargo, si bien el operador es sensible al contexto, no aplica informacin especfica del dominio para mejorar la calidad del hijo que est creando (por ejemplo, no intenta juntar las intersecciones que contienen elementos ms similares entre si).
66
Eugenio Yolis
4.1.6 Mutacin
Los operadores de mutacin utilizados en la literatura funcionan en forma anloga a los operadores de mutacin clsicos, cambiando elementos de grupo en forma aleatoria en base a alguna probabilidad de mutacin [Jones et.al., 1991; Bezdek et.al., 1994].
4.2.1 Representacin
La representacin elegida fue la Numeracin de grupo; este mtodo es el ms frecuentemente utilizado en la literatura [Falkenauer, 1999]. Para elegir el mtodo de representacin se evaluaron los siguientes puntos: Que la representacin fuera sencilla e intuitiva, Que se pudiera implementar eficientemente la funcin de evaluacin, Que se pudieran implementar eficientemente los operadores.
Eugenio Yolis
67
Vector de elementos (1..N) : es el vector que contiene, para cada elemento, el nmero de grupo al que pertenece CantGrupos : es la cantidad de grupos que tiene el agrupamiento CantElementos : es la cantidad de elementos que tiene el grupo NroGrupo : es el nmero que identifica al grupo VecCentroide : es el centroide del grupo
Vector de grupos
La cantidad de grupos (CantGrupos) y el Vector de grupos no son estrictamente necesarios, ya que todos los datos que contienen pueden obtenerse realizando operaciones a partir de la informacin del vector de elementos. Sin embargo, como estos datos se acceden muy frecuentemente, se incluyen en el cromosoma por razones de eficiencia.
relativamente pocas generaciones, pero el proceso de generacin de la poblacin inicial exige demasiado tiempo (an teniendo en cuenta que el
68 CAPITULO 4 SOLUCION PROPUESTA Eugenio Yolis
tamao de la poblacin inicial puede reducirse), ya que el algoritmo k -means es del orden de (n.k).
Buscando una solucin intermedia, se decidi aplicar el algoritmo k-means para generar los agrupamientos de la poblacin inicial, pero en lugar de formar k grupos, se generan agrupamientos de log(k) grupos. De esta forma, la generacin de la poblacin inicial lleva tiempos del orden de (n.log(k)). El algoritmo gentico tiene operadores que se ocupan de ir dividiendo a los grupos para llegar a soluciones que tengan k grupos, que se detallan ms adelante.
4.2.5 Seleccion
Para el algoritmo propuesto se utiliza el mtodo de Torneo, por los siguientes motivos: Es independiente de la escala de la funcin de adaptacin, No requiere ordenar los valores de adaptacin de cada cromosoma, Permite regular la presin de seleccin.
Eugenio Yolis
69
4.2.6 Cruza
Dado que ninguno de los operadores de cruza encontrados en la literatura daba solucin a las cuestiones planteadas en el captulo 3 (Descripcin del problema), se dise un nuevo operador de cruza que cumpliera con las caractersticas buscadas. El operador fue diseado con los siguientes lineamientos: La implementacin deba ser eficiente, El operador deba ser sensible al contexto, El operador deba aplicar informacin especfica del dominio para generar agrupamientos de buena calidad.
1 - Pasa agrupamiento
2 - Pasa grupo
Hijo
Fig 4.1 - Esquema bsico del funcionamiento del operador Cruza Pasa Grupo
El agrupamiento de uno de los padres es copiado al hijo sin modificaciones, y luego uno de los grupos del segundo padre se pasa al hijo, reacomodando los elementos que hagan falta.
70
Eugenio Yolis
Los pasos que sigue el algoritmo para generar cada uno de los hijos son: 1. Crear un cromosoma con el mismo agrupamiento que el primer padre (el padre que pasa el agrupamiento), 2. Seleccionar un grupo fuente del segundo padre (el padre que pasa el grupo), 3. Seleccionar un grupo destino en el hijo, que va a transformarse en el grupo del padre, 4. Reacomodar los elementos del hijo segn sea necesario para que el grupo destino contenga los elementos que contiene el grupo fuente.
Paso 1 - Crear el cromosoma hijo Este paso consiste simplemente en crear un cromosoma copiando los mismos valores que contiene el padre que pasa el agrupamiento.
Paso 2 - Seleccin del grupo fuente En este paso se selecciona un grupo del padre que pasa el grupo. Hay un parmetro del algoritmo gentico que controla la probabilidad de que se elija el mejor grupo (aquel con mayor similitud promedio) para pasarlo al hijo. En caso contrario, se elige un grupo al azar para pasarlo al hijo. Este parmetro v ara entre los valores 0,8 y 0,9 durante la ejecucin del algoritmo gentico, lo que quiere decir que en ms del 80% de los casos, se elegir el grupo con mayor similitud promedio para pasarlo al hijo.
Paso 3 - Seleccin del grupo destino En este paso se selecciona un grupo del hijo, al que se le quitarn y agregarn elementos para que contenga los mismos elementos que contiene el grupo fuente. Hay cuatro formas de seleccionar este grupo, cada una de ellas con cierta probabilidad: a) El grupo ms similar (probabilidad 0,56): se busca en el hijo el grupo con el centroide ms cercano al centroide del grupo fuente. b) El grupo con ms elementos en comn (probabilidad 0,40): se busca en el hijo el grupo con ms elementos en comn con el grupo fuente. c) Menor similitud promedio (probabilidad 0,02): se busca en el hijo el grupo que tenga la menor similitud promedio. d) Al azar (probabilidad 0,02): se selecciona un grupo al azar del hijo.
Eugenio Yolis
71
Paso 4 - Reacomodamiento de los elementos del hijo En este paso, se agregan y quitan elementos del grupo destino para que resulte igual al grupo fuente. Los elementos que estn en el grupo fuente (en el padre) pero que
no estn en el grupo destino (en el hijo), se sacan del grupo en el que estn en el hijo, y se agregan al grupo destino. Los elementos que estn en el grupo destino (en el hijo) pero que no estn en el grupo fuente (en el padre), se quitan del grupo destino del hijo, y se colocan en otro grupo. El grupo al que se reasigna cada uno de estos elementos se elige de la siguiente forma: a) Con probabilidad 0,95, se busca, dentro de los 2 grupos del hijo ms similares al grupo fuente del padre, aquel que tenga el centroide ms cercano al elemento que se est reasignando. b) Con probabilidad del 0,05, se elige al azar el grupo al cual se mover el elemento a reasignar.
Utilizacin de informacin especfica del dominio El operador no elige al azar qu grupo del padre pasar al hijo, sino que elige en ms del 80% de los casos el grupo con mayor similitud promedio. As, durante la cruza no slo se heredan caractersticas de los padres, sino que se intenta que estas caractersticas sean deseables. En forma similar, cuando hay que reasignar un elemento a otro grupo, en un 95% de los casos se busca una alternativa mejor que la eleccin al azar del grupo destino, tratando de que el agrupamiento resultante sea de buena calidad.
72 CAPITULO 4 SOLUCION PROPUESTA Eugenio Yolis
4.2.7 Mutacin
Durante las pruebas realizadas se observ que los operadores de mutacin clsicos retrasaban considerablemente la convergencia del algoritmo gentico, ya que lo obligaban a explorar regiones del espacio de bsqueda al azar, donde la mayor parte de las veces no se encontraban mejores soluciones. Al disear un algoritmo gentico que pueda competir en trminos de eficiencia con los algoritmos especficos del dominio, debe sacrificarse en parte la amplitud de la exploracin, restringindola a aquellas regiones donde es ms probable que haya buenas soluciones. Esto puede lograrse diseando operadores de mutacin que no hagan cambios totalmente aleatorios, sino que, de la misma forma que el operador de cruza, tiendan a hacer cambios que aumenten la calidad de las soluciones, dejando algunas pocas decisiones libradas al azar. Estos operadores se aplicarn luego con probabilidades bastante altas comparadas con las de los operadores de mutacin estndar, ya que son necesarios no slo para la exploracin del espacio de bsqueda, sino tambien para el aumento de la calidad de la poblacin. A continuacin se describen los 4 nuevos operadores de mutacin diseados para el algoritmo propuesto.
Eugenio Yolis
73
74
Eugenio Yolis
El otro grupo se puede seleccionar con alguno de estos criterios: Ms similar (probabilidad 0,95): se selecciona el grupo con el centroide ms cercano al del primer grupo elegido. Al azar (probabilidad 0,05): el segundo grupo se selecciona al azar.
Una vez que se tiene el grupo a dividir, se lo divide en 2 aplicando a los elementos del grupo la primera iteracin (fase inicial) del algoritmo k-means, con k = 2.
Eugenio Yolis
75
76
Eugenio Yolis
Eugenio Yolis
77
Eugenio Yolis
79
Los documentos en la coleccin son noticias reales que aparecieron en cables de la agencia Reuters durante 1987. Los documentos fueron recopilados y categorizados manualmente por personal de la agencia y de la compaa Carnegie Group, Inc., en 1987. En 1990, la agencia entreg los documentos al Laboratorio de Recupero de Informacin (Information Retrieval Laboratory) de la Universidad de Massachusetts. Desde 1991 hasta 1996, la coleccin se distribuy bajo la denominacin Reuters 22173. En 1996, durante la conferencia ACM SIGIR (una de las reuniones ms importantes en el campo de recupero de informacin y categorizacin de documentos), un grupo de investigadores realiz un trabajo sobre esta coleccin con el objetivo de que los resultados de distintos trabajos que utilizaran la coleccin fueran ms fciles de comparar entre s [ACM SIGIR, 1996]. El resultado fue la distribucin 21578, que es la que actualmente se utiliza en los trabajos sobre categorizacin automtica de documentos para asegurar una metodologa de prueba uniforme. La coleccin se compone de 21.578 documentos (cantidad que le da nombre a la misma), distribuidos en 22 archivos. Cada documento tiene 5 campos de categorizacin distintos: Valor Bursatil, Organizacin, Persona, Lugar y Tema. En cada campo, el documento puede tener un slo valor, varios, o ninguno. Los criterios utilizados en esta tesis para medir la calidad de un agrupamiento requieren que cada documento tenga solamente una categora asignada, por lo que para los experimentos se decidi utilizar dos subconjuntos extraidos de esta coleccin previamente utilizados por otros investigadores [Zhao et.al., 2001]. El procedimiento seguido para extraer los subconjuntos fue tomar solamente los documentos que tenan slamente un valor en el campo Tema, luego dividir los posibles valores del campo en dos subconjuntos y asignar a cada documento al subconjunto correspondiente. Esto di lugar a dos conjuntos de datos (re0 y re1), de 1504 y 1657 documentos respectivamente. Las principales razones para usar estos documentos para las pruebas experimentales fueron: La coleccin Reuters 21578 es un estndar para la prueba de algoritmos de categorizacin, por lo que los resultados obtenidos tendrn mucha ms validez que si los experiementos se realizaran sobre un conjunto de datos recopilado sin seguir una metodologa estndar.
80
Eugenio Yolis
En los subconjuntos re0 y re1 extraidos de esta coleccin [Zhao et.al., 2001] ya se han filtrado aquellos documentos sin clasificar, o con ms de una clasificacin (que complican innecesariamente la evaluacin de los
resultados) y son ms fciles de manipular que la coleccin completa. Los documentos de los subconjuntos re0 y re1 ya se han preprocesado utilizando tcnicas estndar. Primero, se han removido de cada documento
las palabras comunes que no sirven para el proceso de categorizacin, utilizando una stop list, y el resto de las palabras fueron llevadas a su raz utilizando el algoritmo de Porter [Porter, 1980].
Eugenio Yolis
81
1 n j di d j sim _ prom j = 2 n j i =1 d i * d j j= 1
La similitud promedio de todo el agrupamiento se obtiene sumando la similitud promedio de cada grupo multiplicada por la cantidad de elementos del grupo, y dividiendo el total por la cantidad total de elementos de la muestra,
k
sim _ prom =
n j * sim _ prom j
j =i
De esta manera se pondera la similitud promedio de cada grupo asignndole un peso acorde con la cantidad de elementos que contiene. Esta ponderacin permite que un grupo grande con baja similitud promedio impacte negativamente en la evaluacin del agrupamiento y no sea compensado tan fcilmente por un grupo pequeo. Si no se
82 CAPITULO 5 PRUEBA EXPERIMENTAL Eugenio Yolis
realizara esta ponderacin, una muestra de 1.000 documentos que se dividiera en un grupo de 900 elementos con muy baja similitud promedio y 10 grupos compactos de 10 elementos cada uno, podra sumar mejor similitud promedio que un agrupamiento balanceado de 11 grupos con buena similitud promedio en cada uno. Esta medida da cuenta de cunto tienen en comn los elementos de cada grupo. Cuanto ms homogeneo sea cada grupo, mayor valor tendr este parmetro. Valores ms grandes de similitud promedio indican una mejor calidad del agrupamiento.
5.2.2.2 Entropa
La entropa es una medida externa (para calcularla es necesario conocer a qu categora real pertenece cada documento). El concepto de entropa tiene su origen en el campo de la fsica (ms especificamente, en el area de la termodinmica), y es utilizada como medida del grado de desorden de un sistema [Carter, 2000]. En 1948, Shannon [Shannon, 1948] incorpora el trmino a la teora de la informacin como una funcin que mide la cantidad de informacin generada por un proceso. Un ejemplo simple permitir entender qu es lo que mide la entropa y cmo puede utilizarse para medir la calidad de un agrupamiento dado. Supngase que se tiene un grupo con 1000 documentos de 8 categoras distintas. Una persona debe tomar cada documento, y escribir un cdigo (en forma binaria) para describir la categora a la cual pertenece. La forma ms simple de hacerlo sera escribir, para cada documento, el nmero de la categora (de 0 a 7), en base 2. Para esto, necesitara 3 bits por cada documento (en base 2 se requieren 3 bits para codificar los nmeros 0 a 7). Supngase ahora que los documentos del grupo no pertenecen a cada categora en cantidades iguales, sino que el 42% de los documentos son de la primer categora, el 40% son de la segunda categora, y el 18% restante pertenece a las otras 6 categoras en cantidades iguales. La persona encargada de anotar la categora de cada documento podra desarrollar una codificacin ms eficiente (la forma simple, descrita
anteriormente le insuma 3 bits por cada uno). Por ejemplo, podra adoptar el siguiente cdigo:
Eugenio Yolis
83
CATEGORA
0 1 2 3 4 5 6 7
Puede calcularse fcilmente, que, al utilizar solamente 2 bits en el 82% de los casos, y 4 bits en el 18% de los casos restantes, estar utilizando en promedio 2,36 bits por cada documento. Aplicada a una situacin como la descrita anteriormente, la entropa mide justamente la mnima cantidad de bits promedio para codificar la categora de cada documento del grupo. Si se tienen h categoras y pi es la probabilidad de que un documento sea de la categora i, la formula para calcular la entropa en una situacin como sta es,
H = pi * log( pi ) . La mxima entropa se obtiene cuando los documentos
i =0 h
pertenecen en cantidades iguales a las categoras (en ese caso, H = 3, que es el caso de la codificacin en base 2 del nmero de categora). En el caso que se describe en la tabla, el valor de H es aproximadamente 1,96, lo que indica que la codificacin elegida no es la ptima. Cuanto ms desparejas sean las probabilidades, el valor de la entropa ir disminuyendo. Si todos los documentos del grupo fueran de una sla categora, el sistema estar totalmente ordenado, y la entropa ser igual a 0 (no har falta escribir de qu categora es cada documento). Para medir la calidad de un agrupamiento utilizando la entropa, primero se calcula entropa de cada grupo. Para cada categora real i, se calcula la probabilidad pij de que un miembro del grupo j sea de la categora i, pij =
nij
n j , donde nij es la
cantidad de documentos de la categora i que se encuentran en el grupo j y nj es la cantidad de documentos del grupo j. La entropa de cada grupo se calcula usando la
84
Eugenio Yolis
frmula: H j = pij * log( pij ) , donde i recorre todas las categoras reales de los
i
documentos. La entropa total del agrupamiento se calcula luego ponderando la entropa de cada grupo de acuerdo a su tamao,
H=
n j * H j
j =1
La entropa tendr un valor mximo cuando los documentos de cada categora estn distribuidos uniformemente entre los grupos, y un valor igual a 0 cuando cada categora tenga sus documentos en un slo grupo. Valores ms chicos de entropa indican una mejor calidad del agrupamiento.
Eugenio Yolis
85
algebraicas), es una aproximacin razonable. De todas maneras, alrededor del 90% de las operaciones que realizan los algoritmos son multiplicaciones de vectores, por lo que el error es despreciable. Lgicamente, un menor nmero de operaciones realizadas (para resultados similares) indica una mayor eficiencia del algoritmo.
86
Eugenio Yolis
conjuntos de resultados, lo que hubiera hecho muy dificil un anlisis estadstico de los mismos. El rendimiento de los algoritmos se hubiera comparado basndose solamente en la categorizacin de dos muestras, que podran haber sido casos favorables para alguno de ellos, quitndole validez a las conclusiones. Con el objetivo de obtener resultados que fueran vlidos desde un punto de vista estadstico, tratando de minimizar las probabilidades de que un caso particular favorable a uno u otro algoritmo influyera en los resultados en forma excesiva, se prepararon las muestras de datos de la siguiente manera: de cada subconjunto de datos (re0 y re1) se extrajeron 10 muestras de 500 documentos al azar, y se realizaron 5 corridas de cada algoritmo sobre cada muestra. De esta manera, los resultados particulares que no reflejan el comportamiento estadstico de los algoritmos tienen menos posibilidades de distorsionar los resultados. Para cada una de las muestras de datos, se obtuvieron agrupamientos de 5, 10, 15 y 20 grupos con cada algoritmo y se calcularon las medidas de evaluacin para cada uno. El procedimiento se repiti 5 veces, y se promediaron las medidas de evaluacin de las 5 iteraciones. Esto di como resultado 20 tablas (una para cada muestra de datos), con las medidas de evaluacin de cada algoritmo para los agrupamientos de 5, 10, 15 y 20 grupos. Promediando los valores de las 20 tablas, se construy una tabla de promedios generales, con el valor promedio de cada medida de evaluacin para cada algoritmo, para los agrupamientos de 5, 10, 15 y 20 grupos. Para la confeccin de los grficos, se utiliz la tabla de promedios generales. Para la realizacin del test de Wilcoxon, se utilizaron los valores cada una de las 20 tablas, ya que cada una de ellas se corresponde a una muestra de datos.
Eugenio Yolis
87
Probabilidad de aplicar el operador de mutacin Refinar KM: Generacin 1 a 40: 10% Generacin 40 a 50: 25%
Tamao y presin selectiva del torneo: Generacin 1 a 10: tamao 2, presin 75% Generacin 10 a 20: tamao 3, presin 75% Generacin 20 a 40: tamao 3, presin 80% Generacin 40 a 50: tamao 3, presin 85%
88
Eugenio Yolis
5.4 Resultados
5.4.1 Experimentos variando la cantidad de grupos
En esta seccin se presentan los resultados que se obtuvieron en los experimentos realizados variando la cantidad de grupos. Para seguir el comportamiento de cada una de las variables independientes al ir variando la cantidad de grupos, se confeccionaron grficos con los promedios generales para cada algoritmo. En cada grfico, el eje x representa la cantidad de grupos en que se fueron dividiendo las muestras de datos con los algoritmos. El eje y representa la variable independiente que se mide en cada grfico. El ttulo del grfico lleva el nombre de la variable independiente. Los valores que se grafican son los promedios generales para cada algoritmo. Adems, se utiliz el test de Wilcoxon sobre cada una de las variables para obtener un anlisis estadstico de los resultados.
Eugenio Yolis
89
Similitud Promedio
0,2
0,18
0,16
0,1
Fig 5.1 Similitud promedio de los agrupamientos encontrados en funcin de la cantidad de grupos.
La figura 5.1 muestra la similitud promedio de los agrupamientos encontrados en funcin de la cantidad de grupos armados. La curva de resultados del algoritmo Gentico se encuentra ligeramente por encima de la curva del algoritmo Bisecting KMeans con refinamiento, mientras que la curva para el algoritmo Gentico con refinamiento supera claramente a la del algoritmo Bisecting K-Means con
refinamiento. Esta apreciacin es consistente con los resultados que arroja el test de Wilcoxon para esta variable (que se detalla en el apndice 2). Tomando en cuenta los resultados de las 20 muestras, el test permite afirmar con un margen de confianza del 95% que el promedio de valores de similitud promedio para el algoritmo Bisecting K Means con refinamiento es inferior al de los otros 2 algoritmos.
90
Eugenio Yolis
Entropa
Bisecting KM Ref Genetico 1,9 Genetico Ref 1,8
1,7
1,6
1,5
1,4
1,3
La figura 5.2 muestra la entropa de los agrupamientos encontrados en funcin de la cantidad de grupos armados. Las curvas de resultados de los algoritmos Gentico y Bisecting K-Means con refinamiento son bastante similares, y tienen diferencias en uno y otro sentido que no permiten afirmar que una sea mejor que la otra, mientras que la curva para el algoritmo Gentico con refinamiento est claramente por debajo de ambas. Esta apreciacin es consistente con los resultados que arroja el test de Wilcoxon para esta variable. Tomando en cuenta los resultados de las 20 muestras, el test no puede distinguir si los valores de entropa son diferentes para los algoritmos Gentico y Bisecting K-Means con refinamiento, mientras que permite afirmar con un grado de confianza de 95% que los valores para el algoritmo Gentico con refinamiento refinamiento. son menores que para el algoritmo Bisecting K-Means con
Eugenio Yolis
91
Cant. Operaciones
Bisecting KM Ref Genetico 200000 Genetico Ref
180000
160000
140000
120000
100000
80000
Fig 5.3 Cantidad de operaciones realizadas por los algoritmos en funcin de la cantidad de grupos.
La figura 5.3 muestra la cantidad de operaciones realizada por los algoritmos en funcin de la cantidad de grupos armados. Se ve claramente que los valores para el algoritmo Gentico estn muy por debajo que los del algoritmo Bisecting K-Means con refinamiento, mientras que para el algoritmo Gentico con refinamiento se encuentran en una posicin intermedia, tambien claramente por debajo del algoritmo Bisecting K-Means con refinamiento. Esta apreciacin es consistente con los resultados que arroja el test de Wilcoxon para esta variable. Tomando en cuenta los resultados de las 20 muestras, el test permite afirmar con un margen de confianza del 95% que el promedio de operaciones realizadas por el algoritmo Bisecting K -Means con refinamiento es superior en ms de un 40% a las realizadas por el algoritmo Gentico y en ms de un 15% a las realizadas por el algoritmo Bisecting K-Means con refinamiento.
92
Eugenio Yolis
Similitud promedio
Bisecting KM Ref
0,172 0,17 0,168 0,166 0,164 0,162 0,16 0,158 0,156 0,154 300 500 700 900 1100
1300
Fig 5.4 Similitud promedio de los agrupamientos encontrados en funcin de la cantidad de documentos.
La figura 5.4 muestra la evolucin de la similitud promedio de los agrupamientos encontrados al variar la cantidad de documentos. Puede observarse que se confirma la tendencia encontrada. La curva de similitud promedio para el algoritmo Bisecting K-Means con refinamiento se encuentra por debajo de las curvas para los algoritmos Gentico y Gentico con refinamiento.
Eugenio Yolis
93
Entropa
1,56 1,54 1,52 1,5 1,48 1,46 1,44 1,42 1,4 1,38 1,36 300
500
700
900
1100
1300
La evolucin de la entropa con la cantidad de grupos (figura 5.5) muestra el mismo comportamiento observado en el primer tipo de experimento, aunque en este grfico la entropa para los agrupamientos encontrados por el algoritmo Gentico es menor que para el algoritmo Bisecting K-Means con refinamiento, aunque esto puede deberse a particularidades de las muestras utilizadas, ya que el anlisis estadstico realizado con los resultados del primer tipo de experimento no permitan afirmar esto.
94
Eugenio Yolis
Cant. Operaciones
550000 500000 450000 400000 350000 300000 250000 200000 150000 100000 50000 300
500
700
900
1100
1300
Fig 5.6 Cantidad de operaciones realizadas por los algoritmos en funcin de la cantidad de documentos.
La cantidad de operaciones en funcin de los documentos a agrupar (figura 5.6) sigue la tendencia esperada, siendo el algoritmo Bisecting K-Means con refinamiento el que requiere mayor cantidad de operaciones, seguido por el algoritmo Gentico con refinamiento y quedando el algoritmo Gentico en tercer lugar.
Eugenio Yolis
95
Cuestin 1: Pueden ayudar los algoritmos genticos a explorar el espacio de bsqueda en forma ms eficiente? Los resultados experimentales demuestran que si, ya que los algoritmos Gentico y Gentico con refinamiento encuentran soluciones de igual o mayor calidad que el algoritmo Bisecting K-Means con refinamiento tomado como referencia, requiriendo una menor cantidad de operaciones para lograrlo.
Cuestin 2: Pueden ayudar los algoritmos genticos a encontrar soluciones de mejor calidad? Los resultados muestran que las soluciones encontradas por los algoritmos Gentico y Gentico con refinamiento son de mayor calidad que las halladas con el algoritmo Bisecting K-Means con refinamiento tomado como referencia, para las medidas de calidad definidas.
96
Eugenio Yolis
Captulo 6 Conclusiones
En esta tesis se propone una adaptacin de un algoritmo gentico al problema de la categorizacin automtica de documentos, que incluye el diseo de un nuevo operador de cruza y cuatro operadores de mutacin. Los resultados experimentales obtenidos confirman la tesis que los algoritmos genticos son una poderosa herramienta para la resolucin de problemas en los cuales el espacio de soluciones es amplio y la funcin de optimizacin es compleja. Se ha encontrado tambien que, tal como lo han afirmado otros autores [Falkenauer, 1999; Estivill-Castro, 2000], los algoritmos genticos no son un mtodo de solucin universal de problemas, sino un paradigma que debe adaptarse correctamente al problema a resolver. El algoritmo propuesto logra resultados efectivos porque en el diseo del mismo se han adaptado los conceptos que aplican los algoritmos genticos y se han creado nuevos operadores especficos para el problema a resolver.
Eugenio Yolis
CAPITULO 6 - CONCLUSIONES
97
El algoritmo Gentico, al crear nuevos grupos (o modificar los existentes) con cualquiera de sus operadores, no descarta de inmediato ninguno de ellos, aunque sean malas soluciones. Los malos agrupamientos se van eliminando ms tarde mediante el operador de seleccin. Mientras tanto, esos agrupamientos pueden ser seleccionados para su cruza con otros, momento en el cual tienen la oportunidad de pasar alguna de sus caractersticas positivas a uno de sus hijos. Es el operador de cruza el que permite al algoritmo Gentico obtener su solucin en forma ms eficiente, ya que puede aprovechar las buenas caractersticas de cada una de las variaciones que se fue realizando, por lo que prcticamente ningn trabajo es desperdiciado.
Cuestin 2: Pueden ayudar los algoritmos genticos a encontrar soluciones de mejor calidad? Las soluciones halladas por el algoritmo gentico propuesto son de mayor calidad (de acuerdo a las medidas definidas) que las del algoritmo Bisecting K -Means con refinamiento, segn lo muestran los resultados expuestos en el captulo 5. El algoritmo Bisecting K-Means no puede llegar a ninguna solucin que le obligue a pasar por un punto en el que disminuya el criterio de optimizacin (siempre elige la divisin que ms hace crecer el criterio de optimizacin). Esto hace que haya regiones del espacio de bsqueda a las que le pueda resultar difcil llegar. Por otra parte, el algoritmo Gentico es capaz de generar soluciones de menor calidad como parte del proceso, y extraer caractersticas positivas de ellas. De esta manera, el algoritmo gentico nunca se encuentra restringido a una regin del espacio de bsqueda. Los elementos de azar que intervienen en la cruza y la mutacin pueden llegar a generar agrupamientos en cualquier punto del espacio de bsqueda. La figura 6.1 ilustra ste concepto. La figura muestra un espacio de bsqueda unidimensional (simplificacin necesaria para que se lo pueda graficar en forma simple), en la que la curva representa el valor del criterio de optimizacin para cada punto.
98
REFERENCIAS
Eugenio Yolis
La figura muestra con smbolos cuadrados dos posibles agrupamientos entre los cuales debe elegir el algoritmo Bisecting K-Means. Este algoritmo elegir la solucin con mayor valor para el criterio de optimizacin, y esto puede tener como consecuencia que se encuentre una solucin subptima, ya que tal vez la regin con el mximo ms alto nunca se explore. Los smbolos triangulares representan los posibles miembros de la poblacin del algoritmo gentico. Si los operadores del algoritmo gentico generaran el agrupamiento graficado con lnea punteada, este agrupamiento pasara a formar parte de la poblacin (an cuando existan soluciones mejores), dndole al algoritmo gentico la posibilidad de explorar esa regin.
Fig 6.1 Comparacin de la exploracin de los algoritmos Bisecting K-Means con refinamiento y Gentico.
Cuestin 3: De qu manera puede definirse la representacin de las soluciones y el operador de cruza para que el algoritmo gentico pueda ser aplicado a la categorizacin automtica de documentos de acuerdo a la hiptesis de los bloques constructores? Esta cuestin se responde en las secciones 4.2.1 y 4.2.6.1, que detallan la representacin utilizada en el algoritmo propuesto y el operador de cruza Cruza Pasa Grupo diseado para trabajar sobre esa representacin. Este operador de cruza asegura que se transfieran caractersticas significativas entre los miembros de la poblacin, llevando a que el algoritmo gentico opere dentro de la hiptesis de los bloques constructores.
Eugenio Yolis
CAPITULO 6 - CONCLUSIONES
99
Cuestin 4: De qu manera pueden disearse los operadores del algoritmo gentico para hacer uso del conocimiento especfico del dominio? Los 5 nuevos operadores presentados como parte de la solucin propuesta (el operador de cruza y los 4 operadores de mutacin, que se detallan en las secciones 4.2.6.1 y 4.7) dan respuesta a esta cuestin. Estos operadores hacen uso de esta informacin para guiar la bsqueda del algoritmo gentico por regiones donde haya ms posibilidades de encontrar soluciones de buena calidad.
100
REFERENCIAS
Eugenio Yolis
Referencias
ACM SIGIR. (1996). Proceedings of the 19th annual international ACM SIGIR conference on Research and development in information retrieval, ACM Press, New York, USA. Allen, R. B., Obry, P. y Littman, M. (1993). An interface for navigating clustered document sets returned by queries, Proceedings of the ACM Conference on Organizational Computing Systems. Anderberg, Michael R. (1973). Cluster analysis for Applications. Academic Press, New York. Bezdeck, J. C., Boggavaparu, S., Hall, L. O. y Bensaid, A. (1994). Genetic algorithm guided clustering, in Proc. of the First IEEE Conference on Evolutionary Computation, 3440. Boley, D., Gini, M., Gross, R., Eui Hong, H., Hastings, K., Karypis, G., Kumar, V., Mobasher, B., Moore, J. (1999). Partitioning-based clustering for Web Document Categorization. Decision Support Systems, volumen 27, nmero 3, pginas 329-341. Box, G.E.P., Hunter, W.G., Hunter, J.S. (1978). Statistics for experimenters: An introduction to design, data analysis and model building. John Wiley and Sons, New York. Bradley, P.S. y Fayyad, U.M. (1998). Refining initial points for k-means clustering. In J. Shavlik, editor, Proceedings of the Fifteenth International Conference on Machine Learning (ICML '98), pages 91--99, San Francisco, CA, 1998. Morgan Kaufmann Canavos, G.C. (1984). Probabilidad y estadstica, Aplicaciones y Mtodos. McGrawHill. Carter, T. (2000). An introduction to information theory and entropy. Complex Systems Summer School. Clerking, P., Cunningham, P., Hayes, C. (2001). Ontology Discovery for the Semantic Web Using Hierarchical Clustering. Department of Computer Science, Trinity College, Dublin. Citeseer (Research Index). The NEC Research Institute Digital Library. Sitio dedicado a la difusin de literatura cientfica. http://citeseer.nj.nec.com/.
Eugenio Yolis
REFERENCIAS
101
Cole, Rowena M. (1998). Clustering with Genetic Algorithms. Thesis for the degree of Master of Science, Department of Computer Science, University of Western Australia. Croft, W. B. (1978). Organizing and searching large files of documents, Ph.D. Thesis, University of Cambridge. Cutting, D. R., Karger, D. R., Pedersen, J. O. y Tukey, J. W. (1992). Scatter/Gather: A cluster-based approach to browsing large document collections, Proceedings of the 15th International ACM SIGIR Conference on Research and Development in Information Retrieval, Pginas 318-29. Dash, M., y Liu, H. (2001). Efficient Hierarchical Clustering Algorithms Using Partially Overlapping Partitions. Pacific-Asia Conference on Knowledge Discovery and Data Mining, pginas 495-506. Davis, L. (1991). Handbook of Genetic Algorithms. New York. Van Nostrand Reihold. De Jong, K.A. (1975). An analysis of the behavior of a class of genetic adaptive systems. Dissertation Abstracts International 36 (10), 514B. University of Michigan, Microfilm No. 76-9381. Dunlop, M.D. y Van Rijsbergen, C. J. (1991). Hypermedia and free text retrieval. RIA091 Conference, Barcelona. Duran, B. S. y Odell, P. L. (1974). Cluster Analysis: A survey. Berlin. Springer-Verlag. Estivill-Castro, V. (2000). Hybrid Genetic Algorithms Are Better for Spatial Clustering. Pacific Rim International Conference on Artificial Intelligence, pages 424434. Estivill-Castro, V. y Murray, A. (1997). Spatial Clustering for Data Mining with Genetic Algorithms. FIT, Technical Report, 97-10. Everitt, Brian S. (1993). Cluster analysis. Halsted Press, 3ra edicin. Falkenauer, Emanuel. (1999). Evolutionary Algorithms: Applying Genetic Algorithms to Real-World Problems. Springer, New York, Pag 65--88. Faloutsos, Christos y Oard, Douglas W. (1995). A survey of Information Retrieval and Filtering Methods. Technical Report CS-TR3514, Dept. of Computer Science, Univ. of Maryland. Fasulo, Daniel. (1999). An analysis of recent work on clustering algorithms. Technical Report #01-03-12, Dept. of Computer Science & Engineering, University of Washington.
102
REFERENCIAS
Eugenio Yolis
Goldberg, David E. (1989). Genetic Algorithms - in Search, Optimization and Machine Learning. Addison-Wesley Publishing Company, Inc. Google. Motor de bsqueda de pginas en internet. http://www.google.com/. Guha, S., Rastogi, R., y Shim, K. (1998). CURE: An efficient clustering algorithm for large databases. In Proceedings of 1998 ACM-SIGMOD International Conference on Management of Data. Hall, L.O., Ozyurt, B. y Bezdek, J.C. (1999). Clustering with a genetically optimized approach. IEEE Trans. On Evolutionaty Computation, 3, 2, 103-112. Han, J., Kamber, M. y Tung, A.K.H. (2001). Spatial clustering methods in data mining: A survey. Geographic Data Mining and Knowledge Discovery, H. Miller and J. Han, editors, Taylor and Francis. Hearst, Marti A. y Pedersen, Jan O. (1996). Reexaminig the Cluster Hypothesis: Scatter/Gather on Retrieval Results. Proceedings of ACM SIGIR 96, Zurich. Hilera, J.R. y Martnez, V.J., (1995). Redes Neuronales Artificiales. Fundamentos, Modelos y Aplicaciones. Editorial Ra-Ma, Serie Paradigma, Madrid. Holland, J. H. (1975). Adaptation in natural and artificial systems. Ann Arbor: The University of Michigan Press. Honkela, T., Kaski, S., Lagus, K., y Kohonen, T. (1996). Newsgroup exploration with WEBSOM method and browsing interface. Technical Report A32, Helsinky University of Technology, Laboratory of Computer and Information Science. ISO/IEC 2382-1:1993 Information technology -- Vocabulary --. Part 1: Fundamental terms Jain, A. K., Murty, M.N., y Flinn, P.J. (1999). Data Clustering: A review. ACM Computing Surveys, Vol. 31, Nro 3, Septiembre 1999. Joachims, T. (1998). Text Categorization with Support Vector Machines: Learning with Many Relevant Features. Proceedings of ECML-98, 10th European Conference on Machine Learning, Springer Verlag, Heidelberg, DE. Johnson, A., Fotouhi, F. (1996). Adaptive Clustering of Hypermedia Documents. Information Systems, Vol. 21, No. 6, pp. 459. Jones, D. R. y Beltramo, M. A. (1991) Solving partitioning problems with genetic algorithms. Proceedings of the fourth International Conference on Genetic Algorithms, pages 442-449.
Eugenio Yolis
REFERENCIAS
103
Jones, G., Robertson, A.M., Santimetvirul, C. y Willet, P. (1995). Non-hierarchical document clustering using a genetic algorithm. Information Research, an electronic journal, Vol 1, No 1, April, 1995. Kaufmann, Leonard y Rousseeuw, Peter J. (1990). Finding Groups in data: An introduction to Cluster Analysis, John Wiley & Sons, Inc., NY. Karipys, G., Han, E.H., Kumar, V. (1999). CHAMELEON: A hierarchical clustering algorithm using dynamic modeling, IEEE Computer: Special Issue on Data Analysis and Mining, 32(8), 68-75. Kohonen, T. (1982). Self-organized formation of topologically correct feature maps, Biological Cybernetics, 43 : 59-69. Koza, John R. (1997). Genetic Programming. Cambridge : M.I.T. Press. Krovetz, R. (1993). Viewing morphology as an inference process. In Proceedings of ACM-SIGIR93, pages 191--203 Leousky, A. V. y Croft, W. B. (1996). An evaluation of techniques for clustering search results, Technical Report IR-76, Department of Computer Science, University of Massachusetts, Amherst. Lewis, D. (1991). Evaluating text categorization, Proceedings of the Speech and Natural Language Workshop, Asilomar, Morgan. Lewis, D. (1997). Reuters-21578 text categorization test collection, http://www.daviddlewis.com/resources/testcollections/reuters21578/ http://kdd.ics.uci.edu/databases/reuters21578/reuters21578.html.
Liu, G.L. (1968). Introduction to combinatorial mathematics, McGraw Hill. Maarek, Yoelle S., Fagin, Ronald, Ben-Shaul, Israel Z. y Pelleg, Dan. (2000). Ephemeral Document Clustering for Web Applications. IBM Research Report RJ 10186. Macskassy, S.A., Banerjee, A., Davison, B.D., Hirsh, H. (2001). Human performance on clustering web pages. Technical Report DCS-TR-355, Department of computer Science, Rutgers, State University of New Jersey. Mahfouz, S.Y., Toropov, V.V., Westbrook, R.K. (2000). Modification, tunning and testing of a GA for structural optimization problems. Department of Civil and Environmental Engineering, University of Bradford, UK. Miller, B.L., Goldberg, D.E. (1995). Genetic algorithms, Selection Schemes and the Varying Effects of Noise, IlliGAL report No. 95009.
104
REFERENCIAS
Eugenio Yolis
McQueen, J. (1967). Some methods for classification and analysis of multivariate observations, 5-th Berkeley Symposium on mathematics, Statistics and Probability, 1, S. 281-298. Myers, R.H., Montgomery, D.C. (1995). Response surface methodology: process and product optimization using designed experiments. John Wiley and Sons, New York. Painho, M. y Bao, F. (2000). Using Genetic Algorithms in Clustering Problems. Proceedings of the 5th International Conference on GeoComputation, University of Greenwich, United Kingdom. Pentakalos, O., Menasc, D. y Yesha, Y. (1996). Automated Clustering-Based Workload Characterization. 5th NASA Goddard Mass Storage Systems and Technologies Conference. Porter, M. F., (1980). An Algorithm for Suffix Stripping, Program, vol.14, no. 3, 130137, 1980 Qin He, (1996). A review of clustering algorithms as applied in IR, UIUCLIS1996/6+IGR, University of Illinois at Urbana-Champaign. Raghavan, V. V. y Birchard, K. (1978). A clustering strategy based on a formalism of the reproductive process in natural systems. Proceedings of the 2nd International Conference on Research and Development in Information Retrieval. 10-22. Raghavan, V., Bollmann, P., y Jung, G. (1989). A critical investigation of recall and precision as measures of retrieval system performance. ACM Transactions on Information Systems, 7(3):205--229. Rasmussen, E. (1992). Clustering Algorithms, W. B. Frakes and R. Baeza-Yates, editors, Information Retrieval, Pginas 419-442. Prentice Hall, Eaglewood Cliffs, N. J. Rger, S. M. R. y Gauch, S. E. (2000). Feature reduction for document clustering and classification. Technical report, Computing Department, Imperial College, London, UK. Sarle, W.S., ed. (1997) Neural Network FAQ, part 1 of 7: Introduction, actualizacin peridica al grupo de noticias de Usenet comp.ai.neural-nets, ftp://ftp.sas.com/pub/neural/FAQ.html Schtze, Hinrich y Silverstein Craig (1997) Projections for Efficient Document Clustering, in Proceedings of ACM/SIGIR97, pp.74-81. Shannon, C.E. (1948) A mathematical theory of communication, Bell System Technical Journal, vol. 27, pp. 379-423 and 623-656, July and October.
Eugenio Yolis
REFERENCIAS
105
Steinbach, M., Karypis, G., y Kumar, V. (2000). A comparison of Document Clustering Techniques. Technical Report #00-034. University of Minnesota. In KDD Workshop on Text Mining. Strehl, A., Ghosh, J. y Mooney, R. (2000). Impact of Similarity Measures on Web-page Clustering. AAAI-2000: Workshop of Artificial Inteligence for Web Search. Trocine, L., Malone, L.C. (2000). Finding important independent variables through screening designs: a comparison of methods. Proceedings of the 2000 Winter Simulation Conference, University of Central Florida, Orlando, U.S.A. Unal, R., Dean E.B. (1991). Taguchi approach to design optimization for quality and cost: an overview, 1991 International Conference of the International Society of Parametric Analysts. Van Rijsbergen, C. J. (1979). Information Retrieval, Butterworths, London, 2da edicin. Webster, P.G. (2002). Design of experiments in the Mbius Modeling Framework, Thesis presented for the degree of Master of Science in Electrical Engineering, University of Illinois. Wilf, H.S. (1986). Algorithms and Complexity, Prentice Hall. Willet, P. (1998). Recent trends in hierarchical document clustering: a critical review. Information Processing and Management. 24:577-97. Yang, Y. (1997). An evaluation of statistical approaches to text categorization. School of Computer Science, Carnegie Mellon University, CMU-CS-97-127. Yang, Y. y Liu, Xin, (1999). A re-examination of text categorization methods. 22nd Annual International SIGIR. Yang, Y. y Pedersen J., (1997). A comparative study on feature selection in text categorization. Proc. of the 14th International Conference on Machine Learning ICML97, pginas 412 - 420. Zamir, Oren y Etzioni, Oren. (1998). Web Document Clustering: A feasibility demonstration. Proceedings of ACM/SIGIR98. Zamir, Oren y Etzioni, Oren. (1999). Grouper: A Dynamic Clustering Interface to Web Search Results. Proceedings of the Eighth International World Wide Web Conference, Computer Networks and ISDN Systems.
106
REFERENCIAS
Eugenio Yolis
Zhao, Y. y Karypis, G., (2001). Criterion Functions for Document Clustering. Technical Report #01-40, Department of Computer Science, University of Minnesota. Zervas, Giorgio y Rger, Stefan. (2000).The curse of dimensionality and document clustering. Dept. of Computing, Imperial College, England.
Eugenio Yolis
REFERENCIAS
107
A1.1.1 generacionesMximo
Este parmetro especifica el nmero fijo de generaciones que se ejecutar el algoritmo gentico. El valor de este parmetro debe ser dependiente de la cantidad de documentos que se van a agrupar. Lo que debe determinarse es la frmula para calcular el nmero de generaciones en funcin de la cantidad de documentos.
A1.1.2 poblacionTamao
Este parmetro indica el nmero de cromosomas en la poblacin. El posible rango de valores es de 10 a 50 cromosomas.
A1.1.3 torneoTamao
Este parmetro determina el tamao del torneo para el operador de seleccin. Los valores para este parmetro pueden variar entre 2 y 4.
Eugenio Yolis
109
A1.1.4 torneoProbMejor
Este parmetro especifica la probabilidad con la cual se elige al mejor individuo del torneo en el operador de seleccin. Su valor puede variar entre 0.6 y 1.
A1.1.5 cruzaPasaGrupoProbMejor
Este parmetro indica la probabilidad de que, en el operador de cruza, el grupo con mayor similitud promedio del padre que pasa el grupo se incluya en el hijo. Su valor puede variar entre 0.6 y 1.
A1.1.6 mutacionRefinarKMProb
Este parametro especifica la probabilidad de aplicar el operador de mutacin Refinar KM a cada hijo generado por el operador de cruza. El posible rango de valores es de 0 a 0.15.
A1.1.7 mutacionRefinarSelectivoProb
Este parametro especifica la probabilidad de aplicar el operador de mutacin Refinar Selectivo a cada hijo generado por el operador de cruza. El posible rango de valores es de 0 a 0.1.
110
Eugenio Yolis
Los experimentos para cada parmetro consistieron en hacer que el parmetro estudiado tomara distintos valores, dejando fijo el valor de los otros parmetros. Los parmetros que no se estaban evaluando se fijaron en un valor igual al promedio de los extremos de sus rangos de valores. Esta metodologa se denomina un factor a la vez (en ingls: one factor at a time) y suele usarse para observar cmo afecta a un sistema la modificacin de uno de sus parmetros [Myers et.al., 1995; Webster, 2002]. Si bien no permite percibir los efectos de comportamiento causados por la variacin combinada de ms de un parmetro, da una buena nocin de la sensibilidad del sistema con respecto a cada uno de sus parmetros. Durante la ejecucin del algoritmo gentico, se tom el promedio de la funcin de adaptacin para los cromosomas de la poblacin cada 5 generaciones, y se confeccionaron curvas con la evolucin de la aptitud promedio de la poblacin en funcin del nmero de generacin. En cada grfico se incluy una curva para cada valor del parmetro evaluado. A continuacin se listan los valores utilizados para cada parmetro en los experimentos que no lo involucraban: poblacionTamao : 30 torneoTamao : 3 torneoProbMejor : 0.8 cruzaPasaGrupoProbMejor : 0.8 mutacionRefinarKMProb : 0.1 mutacionRefinarSelectivoProb : 0.05
Eugenio Yolis
111
A1.3 Resultados
A1.3.1 generacionesMximo
Se realizaron experimentos con muestras de datos tomadas al azar conteniendo 400, 700, 1000 y 1300 documentos, y se grafic la evolucin de la aptitud promedio de la poblacin en funcin del nmero de generacin para cada tamao de muestra.
Cantidad de documentos
400 700 1000 1300 generacionesMximo
0,17 0,15
Aptitud promedio
Generacin
100
150
200
Fig A1.1 Aptitud promedio en funcin del nmero de generacin para distintas cantidades de documentos.
Puede observarse que la evolucin de las curvas es similar. Todas presentan un crecimiento relativamente rapido en las primeras generaciones. Luego, la tasa de crecimiento decrece paulatinamente y la aptitud promedio de la poblacin tiende a estabilizarse (la poblacin converge). Como se describe en el captulo 4 (Solucin propuesta), seccin 4.2.10, se busca detener al algoritmo gentico antes de la
112
Eugenio Yolis
convergencia, ya que esta toma demasiado tiempo. En el grfico se incluye una lnea que corta a cada curva en el punto donde se observa que el crecimiento comienza a ser lento. Se encuentra experimentalmente que la funcin: generacionesMaximo = (N / 20) + 25 donde N es la cantidad de documentos a categorizar, es una buena aproximacin de esta lnea.
A1.3.2 poblacionTamao
poblacionTamao
10 20 30 40
0,18
0,16
Aptitud promedio
0,14
0,12
0,1
0,08
Generacin
Fig A1.2 Aptitud promedio en funcin del nmero de generacin para distintos tamaos de poblacin.
Se observa que la evolucin de la aptitud promedio no presencia variaciones significativas para los distintos tamaos de poblacin en el primer tramo de la curva. Cuando la velocidad de evolucin decrece, la mayor diversidad de material gentico presente en las poblaciones ms grandes hace que stas continen evolucionando
Eugenio Yolis
113
(aunque muy lentamente), mientras que las poblaciones de pocos individuos convergen rapidamente. Para elegir el tamao de la poblacin a utilizar, se tuvieron en cuenta los siguientes puntos: El algoritmo gentico se detendr antes de la convergencia de la poblacin, y en esa parte de la curva la evolucin es similar para todos los tamaos de poblacin. El tamao de la poblacin impacta significativamente en la cantidad de operaciones que requiere el algoritmo para llegar a una solucin, ya que la generacin de cada individuo de la poblacin inicial insume una cantidad de operaciones considerable. En el algoritmo propuesto, se comienza con un tamao de poblacin de 12 individuos, que se reduce a 10 una vez que han transcurrido el 40% de las generaciones previstas. Se encontr experimentalmente que esta reduccin en el tamao de la poblacin aceleraba ligeramente la convergencia del algoritmo sin afectar la calidad de la solucin obtenida.
114
Eugenio Yolis
A1.3.3 torneoTamao
torneoTamao
2
0,18
0,16
Aptitud promedio
0,14
0,12
0,1
0,08
Generacin
Fig A1.3 Aptitud promedio en funcin del nmero de generacin para distintos tamaos de torneo.
El comportamiento observado es el que podra esperarse a travs de un anlisis terico del impacto de este parmetro. Tamaos de torneo ms grandes resultan en una presin selectiva mayor, que acelera la evolucin de la poblacin hasta cierto punto, pero provoca una convergencia prematura de la poblacin hacia una solucin subptima. En el algoritmo propuesto se utiliza un tamao de torneo igual a 2 hasta que transcurre el 20% de las generaciones previstas, que luego se cambia al valor 3. De esta forma, se asegura que la presin selectiva al inicio (cuando hay ms peligro de que soluciones mediocres dominen la poblacin) sea pequea, para luego acelerar la velocidad de evolucin en forma moderada.
Eugenio Yolis
115
A1.3.4 torneoProbMejor
torneoProbMejor
0.6
0,18
0.8
0,16
Aptitud promedio
0,14
0,12
0,1
0,08
Generacin
Fig A1.4 Aptitud promedio en funcin del nmero de generacin para distintos valores del parmetro probTorneoMejor.
Se observa que este parmetro tiene un impacto sobre la presin selectiva, que es an mayor que el del parmetro anterior (tamao del torneo). Una presin selectiva demasiado pequea (valor igual a 0.6) no hace evolucionar a l poblacin, mientras que a si es demasiado alta (valor igual a 1), se produce la convergencia prematura. El valor de 0.8 produce los mejores resultados. El algoritmo propuesto utiliza para este parmetro un valor igual a 0.75 hasta que transcurre el 40% de las generaciones previstas, luego se aumenta el valor a 0.8 hasta llegar al 80% de las generaciones, donde se vuelve a aumentar a 0.85 para las generaciones restantes. De esta manera, se va acelerando progresivamente la velocidad de evolucin del algoritmo.
116
Eugenio Yolis
A1.3.5 cruzaPasaGrupoProbMejor
cruzaPasaGrupoProbMejor
0.6
0,18
0.8
0,16
Aptitud promedio
0,14
0,12
0,1
0,08
Generacin
Fig A1.5 Aptitud promedio en funcin del nmero de generacin para distintos valores del parmetro cruzaPasaGrupoProbMejor.
Un valor de 0.6 para este parmetro resulta demasiado pequeo y provoca una involucin de la poblacin, ya que en un 40% de los casos el grupo que pasa al hijo es seleccionado al azar, lo que puede ocasionar que los hijos sean soluciones de peor calidad que los padres. Los valores de 0.8 y 1 presentan curvas de evolucin similares. En el algoritmo propuesto se utiliza un valor de 0.8 hasta que transcurre el 80% de las generaciones previstas, y luego se aumenta este valor a 0.9, para acelerar la convergencia en la fase final.
Eugenio Yolis
117
A1.3.6 mutacionRefinarKMProb
mutacionRefinarKMProb
0.05
0,18
0.1
0.15
0,16
Aptitud promedio
0,14
0,12
0,1
0,08
Generacin
Fig A1.6 Aptitud promedio en funcin del nmero de generacin para distintos valores del parmetro mutacionRefinarKMProb.
Puede observarse que el operador de mutacin Refinar KM es de suma importancia para la evolucin de la poblacin, ya que (como se detalla en el captulo 4) utiliza conocimiento especfico del dominio para mejorar la calidad de las soluciones. Una probabilidad de 0.05 es demasiado baja para este operador, y la poblacin no alcanza soluciones de buena calidad. Con probabilidades de 0.1 0.15 se obtienen buenos resultados. En el algoritmo propuesto se utiliza un valor de 0.1 para este parmetro hasta que transcurre el 80% de las generaciones previstas, y luego se aumenta el valor a 0.25. De esta forma, en la fase final del algoritmo, cuando la evolucin es ms lenta, se apunta a mejorar la calidad de las soluciones utilizando este operador.
118
Eugenio Yolis
A1.3.7 mutacionRefinarSelectivoProb
mutacionRefinarSelectivoProb
0
0,18
0.05
0.1
0,16
Aptitud promedio
0,14
0,12
0,1
0,08
Generacin
Fig A1.7 Aptitud promedio en funcin del nmero de generacin para distintos valores del parmetro mutacionRefinarSelectivoProb.
Puede observarse que la aplicacin de este operador puede ser nociva para la evolucin de la poblacin. Para un valor de probabilidad de 0.1, el algoritmo gentico no alcanza soluciones aceptables. Tal como se describe en el captulo 4 este operador suele formar unos pocos grupos con gran similitud promedio, aunque reduciendo la calidad general de la solucin mutada. Si se lo utiliza desde el inicio de la evolucin, cada vez que se aplica reduce la calidad del agrupamiento que muta, impidiendo que el algoritmo alcance soluciones de buena calidad. En el algoritmo propuesto, se lo utiliza solamente sobre el final del algoritmo (en el ltimo 20% de las generaciones) con probabilidad 0.3. En esta fase, casi todas las soluciones son de la misma calidad y este operador permite obtener material gentico no presente en las soluciones.
Eugenio Yolis
119
Eugenio Yolis
121
A la afirmacin promedio = 500 se la llama hiptesis nula, y se escribe como: H0 : promedio = 500 A la afirmacin promedio < 500 se la llama hiptesis alternativa, y se escribe como: H1 : promedio < 500 La hiptesis nula debe considerarse verdadera a menos que exista suficiente evidencia en su contra. Es decir, se rechazar la afirmacin de que la vida til promedio es de 500 horas slo si la evidencia experimental se encuentra muy en contra de sta afirmacin. En caso contrario, no se podr rechazar la afirmacin basndose en la evidencia experimental. Debe notarse que no poder rechazar la afirmacin no es lo mismo que aceptarla. El caso es anlogo al de un juicio, donde hay un sospechoso acusado de un crimen: si la evidencia es suficiente, se lo declarar culpable. De lo contrario, se dir que la evidencia no alcanza para demostrar su culpabilidad. Existen entonces dos posibles decisiones con respecto a la hiptesis nula: rechazarla no poder rechazarla. A su vez, la hiptesis nula puede ser verdadera o falsa. Esto deja cuatro posibles escenarios:
Cuando H0 es verdadera
Rechazar H0
No poder Rechazar H0
Se denomina a a la probabilidad de cometer un error de tipo I, y a la probabilidad de cometer un error de tipo II. Los valores de a y son interdependientes. Para cada experimento, al disminuir uno de ellos, aumenta el otro. El error de tipo I se considera ms grave que el de tipo II (volviendo a la analoga con el juicio, se prefiere dejar ir a un culpable y no condenar a un inocente), por lo que el procedimiento seguido habitualmente consiste en fijar un valor pequeo para a (por ejemplo, 5%), y luego tratar de minimizar lo ms que se pueda.
122
Eugenio Yolis
Los experimentos realizados para comparar los algoritmos de categorizacin automtica de documentos, son un caso que se denomina de muestras apareadas, en el cual se miden variables numricas. Para estos casos, el test de Wilcoxon es el ms apropiado [Canavos, 1984]. El trmino muestras apareadas se refiere a que las mediciones realizadas no son independientes, sino que son tomadas de a pares (la muestra de datos 1 es categorizada con los algoritmos 1 y 2). Esto hace que lo que deba analizarse sean las diferencias que existen en cada par de valores, que es precisamente lo que hace el test de Wilcoxon.
Eugenio Yolis
123
Luego de la realizacin de los experimentos, se confecciona una tabla que tiene la siguiente forma (ejemplo para 4 muestras):
Muestra
Algoritmo 1
Algoritmo 2
Diferencia (1 -2)
Ranking
1 2 3 4
1 4 3 2
-1 -4 3 -2
Como se ve, los valores pueden tener grandes variaciones de muestra a muestra, pero lo que importa es la diferencia entre los valores de cada algoritmo para cada muestra, ya que eso es lo que indicar el mejor o peor rendimiento de cada uno. La hiptesis nula que es puesta a prueba es que el promedio de los valores es igual para los dos algoritmos (es decir, que las calidades de los agrupamientos producidos es equivalente). Se plantean dos hiptesis alternativas, una de ellas afirma que el promedio de los valores es mayor para el algoritmo 1, y la otra que el promedio de los valores es mayor para el algoritmo 2. La metodologa del test es la siguiente: Se calculan las diferencias de los valores para cada muestra, Luego, se asigna a cada diferencia un valor en un ranking (de menor a mayor) en base a su valor absoluto, Por ltimo, a cada valor del ranking se le asigna el signo de la diferencia que le di origen. Se denomina T+ a la suma de los valores positivos y T- a la suma de los negativos. Si no hubiera diferencias entre los algoritmos, es de esperar que T+ resulte igual a T- (en valor absoluto). Para muestras lo suficientemente grandes (N > 15), la variable T+ puede aproximarse por medio de una distribucin normal con media E(T+) y varianza Var(T+), donde
E (T + ) =
N ( N + 1) 4
Var(T + ) =
N ( N + 1)( 2 N + 1) 24
124
Eugenio Yolis
zT + =
(T + ) E (T +) Var(T + )
La variable zT+ tiene una distribucin normal estndar (media igual a 0 y varianza igual a 1). El valor del parmetro a determina los lmites mnimo y mximo para el valor observado de zT+, ms all de los cuales se rechaza la hiptesis nula. Si el valor de zT+ es superior al lmite m ximo, se aceptar la hiptesis alternativa de que el promedio de valores para el algoritmo 1 es mayor que para el algoritmo 2. Si el valor de zT+ es inferior al lmite mnimo, se aceptar la hiptesis alternativa de que el promedio de valores para el algoritmo 2 es mayor que para el algoritmo 1.
Eugenio Yolis
125
126
Eugenio Yolis
A2.3.2 Entropa
Debe recordarse que valores ms chicos para la entropa indican una mejor calidad del agrupamiento.
Eugenio Yolis
127
128
Eugenio Yolis
Eugenio Yolis
129
Programa AGDocClus
Agrupamientos
130
Eugenio Yolis
El primer paso consiste en generar subconjuntos de datos que contengan elementos (elegidos al azar) de estos archivos. Estos subconjuntos de datos se generan en la forma de archivos con el mismo formato que los conjuntos originales, y adems se guardan en la base de datos de datasets. El programa Armar Datasets es el que hace este trabajo. Luego, los archivos conteniendo cada subconjunto son procesados por el programa que realiza los agrupamientos (AGDocClus). Este programa genera archivos de salida que contienen la informacin de los agrupamientos. A continuacin, el programa Evaluar Agrupamientos toma como entrada los agrupamientos generados y los datos de cada subconjunto de la base de datos de datasets para armar una planilla excel con los resultados (los valores de las medidas de calidad para cada agrupamiento).
Eugenio Yolis
131
Eugenio Yolis
133
Luego debe seleccionarse la solapa System DNS y presionar el botn Add..., como se muestra en la figura A3.3.
Debe seleccionarse el driver de conexin Microsoft Access Driver (*.mdb), como se muestra en la figura A3.4.
134
Eugenio Yolis
Luego debe configurarse el origen de datos ODBC para utilizar el archivo MDB que se copi al disco en el paso descripto en la seccin A3.3.1, de la forma que muestra la figura A3.5. En la figura se utiliza el nombre bdReuters2 para el origen de datos. Se recomienda el uso de este nombre, ya que es el que tienen configurado por defecto los programas que acceden a la base de datos.
Eugenio Yolis
135
136
Eugenio Yolis
En
esta
pantalla
deben
configurarse
continuacin se detalla el significado de cada uno de ellos: Nombre del origen ODBC : Este parmetro es utilizado para identificar la base de datos MDB de datasets. Debe colocarse el mismo nombre que se utiliz al configurar el origen de datos ODBC de la forma en que se describe en la seccin A3.3. Ubicacin archivos datasets : Este parmetro indica la ruta a los archivos
Eugenio Yolis
137
datos re0 y re1. En este directorio se ubicarn tambien los archivos de las nuevas muestras de datos generadas por el programa. Dataset fuente : Este parmetro permite seleccionar el conjunto de datos del cual se quiere extraer la muestra de datos al azar. Este parmetro puede tomar los valores re0 y re1. Cantidad elementos dataset fuente : En este parmetro debe colocarse la cantidad de documentos que contiene el conjunto de datos ingresado en el parmetro anterior. Los conjuntos de datos re0 y re1 contienen 1504 y 1657 documentos, respectivamente. Cantidad elementos nuevos datasets : Este parmetro indica la cantidad de documentos que van a contener las muestras de datos extradas. Debe ser menor o igual a la cantidad de documentos del conjunto de datos origen. Nuevos datasets, desde : Este parmetro indica el nmero de la primera muestra de datos a generar. Si el parmetro tiene el valor 1, y el conjunto de datos origen es re0, la primera muestra de datos ser re0_1. Nuevos datasets, hasta : Este parmetro indica el nmero de la ltima muestra de datos a generar. Si el conjunto de datos origen es re0, el parmetro Nuevos datasets, desde toma el valor 1, y el parmetro Nuevos datasets, hasta toma el valor 3, las muestras de datos generadas sern re0_1, re0_2 y re0_3.
Una vez configurados los valores de los parmetros, debe presionarse el botn Procesar. El programa generar los archivos correspondientes a las muestras de datos, y guardar tambien la informacin de los mismos en la base de datos de datasets.
138
Eugenio Yolis
El programa comenzar preguntando por el directorio en el cual se encuentran ubicados los archivos de muestras de datos.
Directorio donde se encuentran los archivos (ej: 'd:\Tesis_Docs') :
Debe ingresarse el mismo directorio que se indic como salida en el programa Armar Datasets, ya que en ese directorio se habrn generado los archivos de muestras de datos.
Debe ingresarse el nombre de la muestra de datos que se quiere categorizar, por ejemplo, re0_1.
Eugenio Yolis
139
Las opciones (1) a (3) permiten cambiar parmetros que afectarn la realizacin de los experimentos. La opcin (1) permite cambiar la cantidad de grupos que se formarn. La opcin (2) permite cambiar la cantidad de corridas del algoritmo seleccionado que se realizarn. La opcin (3) permite cambiar la cantidad de generaciones que se ejecutarn en el algoritmo gentico. Las opciones (a) y (b) permiten realizar los agrupamientos con cada uno de los algoritmos. Al seleccionar la opcin (a) se agruparn los elementos de la muestra de datos utilizando el algoritmo Bisecting K-Means con refinamiento. Al seleccionar la opcin (b) se agruparn los elementos de la muestra de datos utilizando los algoritmos Gentico y Gentico con refinamiento.
El programa generar los archivos de salida para cada corrida de los algoritmos en el subdirectorio salida. Estos archivos de salida son utilizados por el programa Evaluar Agrupamientos.
140
Eugenio Yolis
En
esta
pantalla
deben
configurarse
los
continuacin se detalla el significado de cada uno de ellos: Nombre del origen ODBC : Este parmetro es utilizado para identificar la base de datos MDB de datasets. Debe colocarse el mismo nombre que se utiliz al configurar el origen de datos ODBC de la forma en que se describe en la seccin A3.3. Dataset a evaluar : Este parmetro indica el dataset para el cual se desea evaluar la salida generada. Ubicacin del programa AGDocClus : En este parmetro debe colocarse el directorio en el cual se copi el programa AGDocClus. El programa Evaluar Agrupamiento buscar los archivos de salida en el subdirectorio salida del directorio indicado en este parmetro
Eugenio Yolis
141
Una vez configurados los valores de los parmetros, debe presionarse el botn Procesar. El programa buscar los archivos de salida generados por el programa AGDocClus, obtendr la informacin del dataset de la base de datos de datasets, y generar una planilla en el programa Microsoft Excel con las medidas de calidad para cada uno de los agrupamientos procesados.
CORRIDA
salida_re0_1_BisKM(ref)2_15_0.txt salida_re0_1_BisKM(ref)2_15_1.txt salida_re0_1_BisKM(ref)2_15_2.txt salida_re0_1_BisKM(ref)2_15_3.txt salida_re0_1_BisKM(ref)2_15_4.txt PROM. BisKM(ref)2_15 salida_re0_1_Gen(ref)_15_0.txt salida_re0_1_Gen(ref)_15_1.txt salida_re0_1_Gen(ref)_15_2.txt salida_re0_1_Gen(ref)_15_3.txt salida_re0_1_Gen(ref)_15_4.txt PROM. Gen(ref)_15 salida_re0_1_Gen_15_0.txt salida_re0_1_Gen_15_1.txt salida_re0_1_Gen_15_2.txt salida_re0_1_Gen_15_3.txt salida_re0_1_Gen_15_4.txt PROM. Gen_15
Para cada corrida de cada uno de los algoritmos se muestran sus medidas de calidad, con los promedios agrupados para las corridas de cada algoritmo.
142
Eugenio Yolis
subconjuntos de documentos. ArchivosTexto.cpp: Implementacin de las funciones que leen los subconjuntos de documentos.
Eugenio Yolis
APNDICE 4 - PROGRAMACION
143
144
APNDICE 4 - PROGRAMACION
Eugenio Yolis
automtica de documentos. Este algoritmo (que se describe en detalle en el captulo 4) es una adaptacin de un algoritmo gentico al problema de la categorizacin automtica de documentos, e incluye nuevos operadores diseados especficamente para el problema a resolver. Este mdulo se compone de los siguientes archivos de cdigo fuente: ClsGenetico.h: Declaracin de la clase c_Genetico. Esta clase
implementa todos los operadores del algoritmo gentico, incluyendo los nuevos operadores diseados como parte de la solucin propuesta. ClsGenetico.cpp: Implementacin de los operadores del algoritmo gentico. Este archivo contiene el constructor de la clase c_Genetico, donde se fijan todos los parmetros que utiliza el algoritmo gentico (tamao de la poblacin, tamao del torneo, y probabilidades con las que se aplica cada operador).
Eugenio Yolis
APNDICE 4 - PROGRAMACION
145
funciones auxiliares. Ppal.cpp: Implementacin de las funciones de interfaz con el usuario, y de los procedimientos que ejecutan las acciones seleccionadas.
146
APNDICE 4 - PROGRAMACION
Eugenio Yolis
Eugenio Yolis
APNDICE 4 - PROGRAMACION
147
A4.2.2 ArchivosTexto.cpp
#include "def.h" #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "skipl.h" #include "archtxt.h" #include "filtrarpalabras.h" #include "steeming.h" #include "vecArchivos.h" uent CargarListaArchivos(char *dir, c_SkipList <xt) /* carga en ltxt los archivos de texto "*.txt" del directorio dir devuelve la cantidad de archivos de texto que se cargaron En vecfh va poniendo la fecha y hora de cada archivo txt */ { t_dir d; char arch[MAX_LONG_NOMARCH], archlwr[MAX_LONG_NOMARCH]; /* empiezo a contar desde 1 */ uent cant=1; uword auxlong; d = PrimeroDir(dir,arch); while (d!=-1) /* mientras haya archivos en el directorio */ { strcpy(archlwr,arch); strlwr(archlwr); if (strstr(archlwr,".txt")) /* si es un .txt */ { /* paso cant a long */ auxlong = (long)cant; ltxt.Buscar_Insertar((ubyte*)arch,auxlong); cant++; //xxxdebug //printf("Arch : %d - %s\n",cant-1,arch); } d = SiguienteDir(d,arch); } return (cant-1); } uent CargarListaArchivosMAT(char *szMat, c_SkipList <xt) /* carga en ltxt los nombres de archivos de texto del .mat. devuelve la cantidad de archivos de texto que se cargaron (en realidad, el nombre de archivo va a ser _D_nro.txt y la cantidad de archivos la sacamos de la primera linea del .mat) */ {
148
APNDICE 4 - PROGRAMACION
Eugenio Yolis
char arch[MAX_LONG_NOMARCH]; /* empiezo a contar desde 1 */ uent cant,i; uword auxlong; FILE *fMat; /* leemos el primer numero del .mat */ fMat = fopen(szMat,"r"); fscanf(fMat,"%d",&cant); fclose(fMat); /* cargamos la lista */ for (i=1;i <= cant; i++) /* para cada "archivo" */ { sprintf((char*)&arch,"_D_%d.txt",i); /* paso "i" a long */ auxlong = (long)i; ltxt.Buscar_Insertar((ubyte*)arch,auxlong); //xxxdebug //printf("Arch : %d - %s\n",i,arch); } return cant; } uent ProcesarArchivosTexto(c_SkipList <xt, c_SkipList &lexico, uent tbufftxt, uent &cantlex, c_SkipList *lLexArchivos[]) /* Devuelve la tabla de lexico en lexico Utiliza el tamanio de buffer especificado en tbufftxt para los archivos de texto devuelve en cantlex la cantidad de terminos del lexico Devuelve OK o el error que corresponda */ { uent nropal; uword nroarch; ubyte nomtxt[MAX_LONG_NOMARCH], pal[MAX_LONG_PALABRA]; c_ArchTexto atxt; uword auxlong; c_SkipList *lLexA; uword nroTerm; uent frecTerm; uent codRet; cantlex = 1; if (ltxt.MoverPrimero() == ERROR) /* la lista estaba vacia, no hay archivos */ return OK; if (atxt.CrearBuffer(tbufftxt) == ERROR_MEMORIA) return ERROR_MEMORIA; do { ltxt.ObtenerClave(nomtxt); nroarch = ltxt.ObtenerValor(); lLexArchivos[nroarch] = new c_SkipList(); if (lLexArchivos[nroarch] == NULL)
Eugenio Yolis
APNDICE 4 - PROGRAMACION
149
return ERROR_MEMORIA; /* obtenemos los datos del archivo de texto */ if (atxt.Abrir((char*)nomtxt) == ERROR_ARCHIVO) return ERROR_ARCHIVO; lexico.ResetFrecs(); /* reseteamos las frecuencias de la lista de lexico */ while (atxt.LeerPalabra(pal)) /* leemos todas las palabras y las metemos en el lexico si es que no estan */ { /* procesamos la palabra */ codRet = ProcesarPalabra(pal); if (codRet != ERROR) /* Hay que guardar esta palabra */ { /* le aplicamos las reglas de steeming */ steeming_porter((char*)pal); nropal = cantlex; /* pasamos el nropal a long */ auxlong = nropal; if (lexico.Buscar_Insertar(pal,auxlong) == ERROR_MEMORIA) return ERROR_MEMORIA; nropal = (uent)auxlong; if (nropal == cantlex) { cantlex++; } } } atxt.Cerrar(); /* no hay mas palabras, completemos la lista de ese archivo */ if (lexico.MoverPrimero() == OK) { /* vamos a trabajar con la lista de ese archivo */ lLexA = lLexArchivos[nroarch]; do { if (lexico.ObtenerFrec() != 0) /* si la palabra estaba en el archivo que procesamos */ { /* la insertamos en la lista del archivo */ lexico.ObtenerClave(pal); nroTerm = lexico.ObtenerValor(); frecTerm = lexico.ObtenerFrec(); if (lLexA->Buscar_Insertar(pal,nroTerm) == ERROR_MEMORIA) return ERROR_MEMORIA; /* seteamos la frecuencia del termino */ lLexA->SetearFrecuencia(frecTerm); } } while (lexico.MoverSiguiente() == OK); } } while (ltxt.MoverSiguiente() == OK); lexico.ResetFrecs(); /* cantlex habia quedado con 1 de mas */ cantlex--; return OK;
150
APNDICE 4 - PROGRAMACION
Eugenio Yolis
} uent ProcesarArchivosTextoMAT(char *szMat, c_SkipList &lexico, uent &cantlex, c_SkipList *lLexArchivos[]) /* Devuelve la tabla de lexico en lexico devuelve en cantlex la cantidad de terminos del lexico Devuelve OK o el error que corresponda */ { ubyte pal[MAX_LONG_PALABRA]; c_SkipList *lLexA; uword nroTerm; uent frecTerm; uent cantArchivos, iArchivo; FILE *fp; char szCLabel[200],dummyChar; float fNroTerm,fFrecTerm; /* la cantidad de archivos es el primer nro del .mat y la cantidad de trminos es el segundo */ fp = fopen(szMat,"r"); fscanf(fp,"%d %d",&cantArchivos,&cantlex); fclose(fp); /* abrimos el archivo de palabras (.mat.clabel) y las vamos ingresando el la lista de lexico */ sprintf((char*)&szCLabel,"%s.clabel",szMat); fp = fopen((char*)&szCLabel,"r"); for (nroTerm = 1; nroTerm <= cantlex; nroTerm++) { fscanf(fp,"%s",(char*)&pal); fscanf(fp,"%c",&dummyChar); if (lexico.Buscar_Insertar(pal,nroTerm) == ERROR_MEMORIA) return ERROR_MEMORIA; } fclose(fp); /* ahora abrimos el .mat y leemos los archivos (cada linea del .mat, excepto la primera, se corresponde con un archivo) */ fp = fopen(szMat,"r"); /* la primera linea la salteamos */ while (fgetc(fp) != '\n'); for (iArchivo = 1; iArchivo <= cantArchivos; iArchivo++) { /* creamos una nueva lista para ese archivo */ lLexArchivos[iArchivo] = new c_SkipList(); /* la ordenamos por numero */ lLexArchivos[iArchivo]->SetearOrden(1); if (lLexArchivos[iArchivo] == NULL) return ERROR_MEMORIA; lLexA = lLexArchivos[iArchivo]; lexico.ResetFrecs(); /* vamos leyendo los pares (palabra,frecuencia) de ese archivo */
Eugenio Yolis
APNDICE 4 - PROGRAMACION
151
do { fscanf(fp,"%f %f",&fNroTerm,&fFrecTerm); nroTerm = (uword)fNroTerm; frecTerm = (uent)fFrecTerm; /* buscamos esa palabra en el lexico */ lexico.Buscar(pal,nroTerm); /* la insertamos el la lista del archivo */ if (lLexA->Buscar_Insertar(pal,nroTerm) == ERROR_MEMORIA) return ERROR_MEMORIA; /* asignamos la frecuencia en ambas listas */ lexico.SetearFrecuencia(frecTerm); lLexA->SetearFrecuencia(frecTerm); /* leemos un caracter, a ver si viene el fin de linea */ fscanf(fp,"%c",&dummyChar); } while (dummyChar != '\n'); } lexico.ResetFrecs(); fclose(fp); return OK; } uent ArmarVectoresArchivos(c_SkipList &lexico, uword cantArchivos, c_SkipList *lLexArchivos[], c_VecArchivo *vVecArchivos[]) /* arma los vectores de terminos de los archivos */ /* devuelve OK o el error que corresponda */ { uent codRet,iArch, iPal, frec, countFrecs; ubyte pal[MAX_LONG_PALABRA],pal2[MAX_LONG_PALABRA]; uent nroPalEnt; uword nroPalWord; real tfIdf; /* para cada archivo */ for (iArch=1; iArch <= cantArchivos; iArch++) { /* creamos el vector con la cantidad de entradas que necesitamos */ vVecArchivos[iArch] = new c_VecArchivo(); if (vVecArchivos[iArch] == NULL) return ERROR_MEMORIA; codRet = vVecArchivos[iArch]->CrearVector((uent)lLexArchivos[iArch]>ObtenerCantElementos()); if (codRet != OK) return codRet; /* las entradas en el vector empiezan en 0 */ iPal = 0; if (0 < lLexArchivos[iArch]->ObtenerCantElementos()) { lLexArchivos[iArch]->MoverPrimero(); do { /* para cada palabra del archivo */ /* buscamos la palabra y la frecuencia en el archivo */ lLexArchivos[iArch]->ObtenerClave(pal); frec = lLexArchivos[iArch]->ObtenerFrec(); nroPalWord = lLexArchivos[iArch]->ObtenerValor(); /* buscamos el nuevo numero de palabra y la cantidad
152
APNDICE 4 - PROGRAMACION
Eugenio Yolis
de archivos en la que aparece */ strcpy((char *)pal2,(char *)pal); lexico.Buscar(pal,nroPalWord); nroPalEnt = (uent)nroPalWord; countFrecs = lexico.ObtenerCountFrecs(); /* calculamos el valor tf-idf */ tfIdf = (real)frec * ((real)log((double)cantArchivos/(double)countFrecs) / (real)log(2.0)); /* insertamos la entrada en el vector */ vVecArchivos[iArch]>ModificarEntrada(iPal,nroPalEnt,tfIdf,false); iPal++; } while (lLexArchivos[iArch]->MoverSiguiente() == OK); } /* ahora lo normalizamos */ vVecArchivos[iArch]->Normalizar(); /* y calculamos las palabras claves */ vVecArchivos[iArch]->ActualizarPalabrasClave(); } return OK; }
Eugenio Yolis
APNDICE 4 - PROGRAMACION
153
A4.2.3 VecArchivos.h
/* Clase de vector de archivos El vector contiene entradas compuestas de dos valores : un valor entero y un valor real El vector se crea con un tamao y luego no se puede cambiar */ #ifndef __vecArchivosH__ #define __vecArchivosH__
#include <malloc.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include "def.h" #include "sis.h" #define NRO_ENT_KEYWORDS 5 typedef struct _t_RegVecArchivo { uent valEnt; real valReal; } t_RegVecArchivo;
class c_VecArchivo { private: uent cantEntradas; /* numero de entradas en el vector */ t_RegVecArchivo *entradas; /* vector con una entrada por cada palabra del archivo */ t_RegVecArchivo keywords[NRO_ENT_KEYWORDS]; /* palabras clave que describen al archivo */ real normaValor; /* valor de la norma del vector */ bool normaActualizada; /* true si el valor de la norma est actualizado */ uent SumarPriv(c_VecArchivo &otroVec, real signo, bool soloEntradasEnComun); public: static uword contMultiplicaciones; /* cuenta las veces que se llam a la funcion multiplicacion */ static uword contCalculoNorma; /* cuenta la cantidad de veces que se llam a la funcion calcular norma */ c_VecArchivo(); uent CrearVector(uent parCantEntradas); uent Duplicar(c_VecArchivo &otroVec); void ModificarEntrada(uent nroEntrada, uent parValEnt, real parValReal, bool usarKeywords); void ConseguirEntrada(uent nroEntrada, uent &parValEnt, real &parValReal, bool usarKeywords);
154
APNDICE 4 - PROGRAMACION
Eugenio Yolis
uent ConseguirCantEntradas(bool usarKeywords); real Multiplicar(c_VecArchivo &otroVec, bool usarKeywords); uent EnComun(c_VecArchivo &otroVec, bool usarKeywords); uent Sumar(c_VecArchivo &otroVec); uent Restar(c_VecArchivo &otroVec); real CalcularNorma(bool incContador); void MultiplicarPorReal(real nroReal); ~c_VecArchivo(); void Normalizar(); void ActualizarPalabrasClave(); }; #endif
Eugenio Yolis
APNDICE 4 - PROGRAMACION
155
A4.2.4 VecArchivos.cpp
#include "vecArchivos.h" uword c_VecArchivo::contMultiplicaciones = 0; uword c_VecArchivo::contCalculoNorma = 0; c_VecArchivo::c_VecArchivo() /* constructor */ { cantEntradas = 0; entradas = NULL; normaValor = (real)0.0; normaActualizada = false; } c_VecArchivo::~c_VecArchivo() /* destructor */ { if (cantEntradas != 0) free((void*)entradas); } uent c_VecArchivo::CrearVector(uent parCantEntradas) /* reserva espacio para la cantidad de entradas pedida */ /* devuelve OK o el error que corresponda */ { uent i; cantEntradas = parCantEntradas; /* inicializamos el vector de palabras claves */ for (i=0; i < NRO_ENT_KEYWORDS; i++) { keywords[i].valEnt = 0; keywords[i].valReal = 0.0; }
if (cantEntradas == 0) return OK; entradas = (t_RegVecArchivo*)malloc(cantEntradas * sizeof(t_RegVecArchivo)); if (entradas == NULL) return ERROR_MEMORIA; return OK; } uent c_VecArchivo::Duplicar(c_VecArchivo &otroVec) { /* copia el vector otroVec en el actual el actual no debe estar inicializado devuelve OK o el error que corresponda */ /* copiamos las keywords */
156
APNDICE 4 - PROGRAMACION
Eugenio Yolis
memcpy((void*)keywords,(void*)otroVec.keywords,NRO_ENT_KEYWORDS * sizeof(t_RegVecArchivo)); /* copiamos las entradas */ cantEntradas = otroVec.cantEntradas; entradas = (t_RegVecArchivo*)malloc(cantEntradas * sizeof(t_RegVecArchivo)); if (entradas == NULL) return ERROR_MEMORIA; memcpy((void*)entradas,(void*)otroVec.entradas,cantEntradas * sizeof(t_RegVecArchivo)); /* copiamos el valor de la norma y el flag que marca si est actualizada */ normaValor = otroVec.normaValor; normaActualizada = otroVec.normaActualizada; return OK; } void c_VecArchivo::ModificarEntrada(uent nroEntrada,uent parValEnt,real parValReal, bool usarKeywords) /* modifica la entrada */ /* si el valor "parValReal" le permite a la palabra ser una de las keywords del archivo, la incluye en el vector y saca una de ellas */ { if (usarKeywords) { keywords[nroEntrada].valEnt = parValEnt; keywords[nroEntrada].valReal = parValReal; } else { entradas[nroEntrada].valEnt = parValEnt; entradas[nroEntrada].valReal = parValReal; } /* la norma no est actualizada porque cambi una entrada */ normaActualizada = false; } void c_VecArchivo::ConseguirEntrada(uent nroEntrada,uent &parValEnt,real &parValReal, bool usarKeywords) /* devuelve los valores de la entrada */ { if (usarKeywords) { if (nroEntrada < NRO_ENT_KEYWORDS) { parValEnt = keywords[nroEntrada].valEnt; parValReal = keywords[nroEntrada].valReal; } else { parValEnt = 0; parValReal = 0; } } else { if (nroEntrada < cantEntradas) { parValEnt = entradas[nroEntrada].valEnt; parValReal = entradas[nroEntrada].valReal; } else {
Eugenio Yolis
APNDICE 4 - PROGRAMACION
157
parValEnt = 0; parValReal = 0; } } } uent c_VecArchivo::ConseguirCantEntradas(bool usarKeywords) { if (usarKeywords) return NRO_ENT_KEYWORDS; else return cantEntradas; } real c_VecArchivo::Multiplicar(c_VecArchivo &otroVec, bool usarKeywords) /* multiplica el vector por el que viene como parametro */ /* producto interno */ /* devuelve el resultado */ { real rAux,valReal1,valReal2; uent i1,i2,valEnt1,valEnt2; uent ent1,ent2; contMultiplicaciones++; ent1 = ConseguirCantEntradas(usarKeywords); ent2 = otroVec.ConseguirCantEntradas(usarKeywords); i1 = 0; i2 = 0; ConseguirEntrada(i1,valEnt1,valReal1,usarKeywords); otroVec.ConseguirEntrada(i2,valEnt2,valReal2,usarKeywords); rAux = 0; while (i1 < ent1 && i2 < ent2) { if (valEnt1 == valEnt2) { rAux += valReal1 * valReal2; i1++; ConseguirEntrada(i1,valEnt1,valReal1,usarKeywords); i2++; otroVec.ConseguirEntrada(i2,valEnt2,valReal2,usarKeywords); } else if (valEnt1 < valEnt2) { i1++; ConseguirEntrada(i1,valEnt1,valReal1,usarKeywords); } else { i2++; otroVec.ConseguirEntrada(i2,valEnt2,valReal2,usarKeywords); } } return rAux; } uent c_VecArchivo::EnComun(c_VecArchivo &otroVec, bool usarKeywords) /* devuelve la cantidad de elementos en comun */ {
158
APNDICE 4 - PROGRAMACION
Eugenio Yolis
real valReal1,valReal2; uent i1,i2,valEnt1,valEnt2,entAux; uent ent1,ent2; ent1 = ConseguirCantEntradas(usarKeywords); ent2 = otroVec.ConseguirCantEntradas(usarKeywords); i1 = 0; i2 = 0; ConseguirEntrada(i1,valEnt1,valReal1,usarKeywords); otroVec.ConseguirEntrada(i2,valEnt2,valReal2,usarKeywords); entAux = 0; while (i1 < ent1 && i2 < ent2) { if (valEnt1 == valEnt2) { entAux++; i1++; ConseguirEntrada(i1,valEnt1,valReal1,usarKeywords); i2++; otroVec.ConseguirEntrada(i2,valEnt2,valReal2,usarKeywords); } else if (valEnt1 < valEnt2) { i1++; ConseguirEntrada(i1,valEnt1,valReal1,usarKeywords); } else { i2++; otroVec.ConseguirEntrada(i2,valEnt2,valReal2,usarKeywords); } } return entAux; } uent c_VecArchivo::Sumar(c_VecArchivo &otroVec) { return SumarPriv(otroVec,(real)1.0,false); } uent c_VecArchivo::Restar(c_VecArchivo &otroVec) { return SumarPriv(otroVec,(real)-1.0,true); } uent c_VecArchivo::SumarPriv(c_VecArchivo &otroVec, real signo, bool soloEntradasEnComun) /* suma al vector las entradas del otro vector, multiplicandolas por el valor "signo" Si "soloEntradasEnComun" es true, se ignoran todas las entradas que estn en el otro vector y no en este Si "soloEntradasEnComun" es false, si es necesario, le agrega entradas al vector devuelve OK o el error que corresponda */ { real valReal1,valReal2; uent i1,i2,iNuevo,valEnt1,valEnt2; uent ent1,ent2,entComun,nuevoTam; t_RegVecArchivo *nuevasEntradas; bool usarKeywords;
Eugenio Yolis
APNDICE 4 - PROGRAMACION
159
real normaVec; /* vamos a aprovechar para calcular la norma */ bool ignoramosEntrada; usarKeywords = false; ent1 = ConseguirCantEntradas(usarKeywords); ent2 = otroVec.ConseguirCantEntradas(usarKeywords); if (soloEntradasEnComun == false) { entComun = EnComun(otroVec,usarKeywords); /* el nuevo tamao es la suma menos la interseccion */ nuevoTam = ent1 + ent2 - entComun; nuevasEntradas = (t_RegVecArchivo*)malloc(nuevoTam*sizeof(t_RegVecArchivo)); if (nuevasEntradas == NULL) return ERROR_MEMORIA; } else { nuevasEntradas = entradas; } i1 = 0; i2 = 0; iNuevo = 0; normaVec = (real)0.0; ConseguirEntrada(i1,valEnt1,valReal1,usarKeywords); otroVec.ConseguirEntrada(i2,valEnt2,valReal2,usarKeywords); while (i1 < ent1 && i2 < ent2) { ignoramosEntrada = false; if (valEnt1 == valEnt2) { nuevasEntradas[iNuevo].valEnt = valEnt1; nuevasEntradas[iNuevo].valReal = valReal1 + (signo * valReal2); i1++; ConseguirEntrada(i1,valEnt1,valReal1,usarKeywords); i2++; otroVec.ConseguirEntrada(i2,valEnt2,valReal2,usarKeywords); } else if (valEnt1 < valEnt2) { /* esta entrada solo est en este vector */ nuevasEntradas[iNuevo].valEnt = valEnt1; nuevasEntradas[iNuevo].valReal = valReal1; i1++; ConseguirEntrada(i1,valEnt1,valReal1,usarKeywords); } else { /* esta entrada solo est en el otro vector */ if (soloEntradasEnComun == false) { nuevasEntradas[iNuevo].valEnt = valEnt2; nuevasEntradas[iNuevo].valReal = signo * valReal2; } else { ignoramosEntrada = true;
160
APNDICE 4 - PROGRAMACION
Eugenio Yolis
} i2++; otroVec.ConseguirEntrada(i2,valEnt2,valReal2,usarKeywords); } if (ignoramosEntrada == false) { normaVec += nuevasEntradas[iNuevo].valReal * nuevasEntradas[iNuevo].valReal; iNuevo++; } } /* alguno de los vectores se termin */ while (i1 < ent1) { /* se termin el otro vector */ nuevasEntradas[iNuevo].valEnt = valEnt1; nuevasEntradas[iNuevo].valReal = valReal1; i1++; ConseguirEntrada(i1,valEnt1,valReal1,usarKeywords); normaVec += nuevasEntradas[iNuevo].valReal * nuevasEntradas[iNuevo].valReal; iNuevo++; } while ((i2 < ent2) && (soloEntradasEnComun == false)) { /* se termin este vector */ nuevasEntradas[iNuevo].valEnt = valEnt2; nuevasEntradas[iNuevo].valReal = signo * valReal2; i2++; otroVec.ConseguirEntrada(i2,valEnt2,valReal2,usarKeywords); normaVec += nuevasEntradas[iNuevo].valReal * nuevasEntradas[iNuevo].valReal; iNuevo++; } if (soloEntradasEnComun == false) { /* liberamos el viejo vector de entradas */ free((void*)entradas); /* asignamos el nuevo vector de entradas */ entradas = nuevasEntradas; } cantEntradas = iNuevo; /* guardamos la norma y marcamos que est actualizada */ normaValor = (real)sqrt((double)normaVec); normaActualizada = true; return OK; } real c_VecArchivo::CalcularNorma(bool incContador) { /* calculamos la norma (raiz del vector multiplicado por si mismo */ real normaVec; uent i; if (incContador) contCalculoNorma++;
Eugenio Yolis
APNDICE 4 - PROGRAMACION
161
if (normaActualizada == false) { /* la norma no est actualizada, hay que calcularla */ normaVec = (real)0.0; for (i=0; i < cantEntradas; i++) { normaVec += entradas[i].valReal * entradas[i].valReal; } normaVec = (real)sqrt((double)normaVec); /* la guardamos, y marcamos que est actualizada */ normaValor = normaVec; normaActualizada = true; } else { normaVec = normaValor; } return normaVec; } void c_VecArchivo::Normalizar() { /* divide las entradas del vector por su norma, de forma tal que la norma del vector sea igual a 1 */ real normaVec,unoSobre; normaVec = CalcularNorma(false); /* dividimos los valores de todas las entradas por la norma */ unoSobre = (real)1.0 / normaVec; MultiplicarPorReal(unoSobre); } void c_VecArchivo::MultiplicarPorReal(real nroReal) { /* Multiplica las entradas del vector por el numero real */ uent i; for (i=0; i < cantEntradas; i++) { entradas[i].valReal *= nroReal; } /* si la norma estaba actualizada, va a quedar bien si la multiplicamos tambien por el real */ normaValor *= nroReal; } void c_VecArchivo::ActualizarPalabrasClave() { /* actualiza la lista de palabras clave del vector */ uent iEntradas,i,j; for (j=0; j < NRO_ENT_KEYWORDS; j++)
162
APNDICE 4 - PROGRAMACION
Eugenio Yolis
{ keywords[j].valReal = (real)0.0; keywords[j].valEnt = 0; } for (iEntradas=0; iEntradas < cantEntradas; iEntradas++) { i = 0; for (j=0; j < NRO_ENT_KEYWORDS; j++) if (entradas[iEntradas].valReal > keywords[j].valReal) i++; if (i > 0) /* la palabra entra en las keywords, en la posicion i-1 */ { i--; for (j = 0; j < i; j++) { keywords[j].valEnt = keywords[j+1].valEnt; keywords[j].valReal = keywords[j+1].valReal; } keywords[i].valEnt = entradas[iEntradas].valEnt; keywords[i].valReal = entradas[iEntradas].valReal; } } }
Eugenio Yolis
APNDICE 4 - PROGRAMACION
163
A4.2.5 ClsAgrupamiento.h
/* Clase que implementa un agrupamiento */ #ifndef __clsAgrupamiento__ #define __clsAgrupamiento__ #include <malloc.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "def.h" #include "vecArchivos.h" #define AGRUP_MIN_GRUPOS 5 #define AGRUP_INC_CANT_GRUPOS 5 typedef struct _t_RegVecGrupos { uent nroGrupo; /* identificador del grupo */ uent menorNroElem; /* menor numero de elemento del grupo */ c_VecArchivo *vecCentroide; /* centroide del grupo */ uent cantElementos; /* cantidad de elementos del grupo */ } tRegVecGrupos; class c_Agrupamiento { friend class c_KMeans; friend class c_Agrup_Imprime; friend class c_Genetico; private: tRegVecGrupos *vecGrupos; uent *vecElementos; uent capacidadVecGrupos; void CopiarRegVecGrupos(uent i, uent j, tRegVecGrupos *nuevoVecGrupos); public: uent cantGrupos; uent cantElementos; uent IndiceDeGrupo(uent nroGrupo, bool puedeNoEstar); uent SiguienteNroGrupo(); c_Agrupamiento(); ~c_Agrupamiento(); uent Inicializar(uent parCantElementos); uent Duplicar(c_Agrupamiento &agrup); uent AgruparAlAzar(uent cantGrupMin, uent cantGrupMax); uent AgregarGrupos(uent cantidad); void RenumerarGrupos(); void MoverElemento(uent nroElem, uent indGrupNuevo, uent indGrupAnterior); void EliminarRegVecGrupos(uent indGrupo); };
#endif
164
APNDICE 4 - PROGRAMACION
Eugenio Yolis
A4.2.6 ClsAgrupamiento.cpp
#include "clsAgrupamiento.h" c_Agrupamiento::c_Agrupamiento() { cantElementos = 0; capacidadVecGrupos = 0; cantGrupos = 0; } c_Agrupamiento::~c_Agrupamiento() { uent i; for (i=0 ; i < cantGrupos ; i++) { if (vecGrupos[i].vecCentroide != NULL) delete(vecGrupos[i].vecCentroide); } if (vecGrupos != NULL) free((void*)vecGrupos); if (vecElementos != NULL) free((void*)vecElementos); } uent c_Agrupamiento::SiguienteNroGrupo() { /* devuelve el siguiente nmero de grupo que se puede utilizar para un grupo nuevo */ uent i; uent max; max = 1; for (i=0; i < cantGrupos; i++) if (vecGrupos[i].nroGrupo > max) max = vecGrupos[i].nroGrupo; /* veamos si no hay un numero mayor, en ese caso, devolvemos 0 */ if (max >= MAX_UENT) return 0; return (max + 1); } uent c_Agrupamiento::IndiceDeGrupo(uent nroGrupo,bool puedeNoEstar) { /* devuelve el indice en el vector de grupos del grupo cuyo nmero es "nroGrupo" si "puedeNoEstar" es true, quiere decir que no es error si no est el nro de grupo buscado. en ese caso, devolvemos el indice de un grupo al azar */ uent i = 0; while ((i < cantGrupos) && (vecGrupos[i].nroGrupo != nroGrupo)) i++; if (i >= cantGrupos) /* no lo encontramos */
Eugenio Yolis
APNDICE 4 - PROGRAMACION
165
{ if (puedeNoEstar) return RANDOM(cantGrupos); else return MAX_UENT; /* para que de error y detectemos el problema */ } else return i; } uent c_Agrupamiento::Inicializar(uent parCantElementos) { /* inicializa el agrupamiento para que contenga "parCantElementos" elementos */ /* devuelve OK o el error que corresponda */ uent i; vecElementos = (uent*)malloc(parCantElementos * sizeof(uent)); if (vecElementos == NULL) return ERROR_MEMORIA; cantElementos = parCantElementos; for (i=0; i < cantElementos; i++) vecElementos[i] = 0; return OK; } uent c_Agrupamiento::Duplicar(c_Agrupamiento &agrup) { /* el agrupamiento copia exactamente al agrupamiento agrup el agrupamiento no debe estar inicializado (agrup si) devuelve OK o el error que corresponda */ uent i, codRet; /* copiamos el vector de elementos */ cantElementos = agrup.cantElementos; vecElementos = (uent*)malloc(cantElementos * sizeof(uent)); if (vecElementos == NULL) return ERROR_MEMORIA; memcpy((void*)vecElementos,(void*)agrup.vecElementos,cantElementos * sizeof(uent)); /* copiamos el vector de grupos */ capacidadVecGrupos = agrup.capacidadVecGrupos; cantGrupos = agrup.cantGrupos; vecGrupos = (tRegVecGrupos*)malloc(capacidadVecGrupos * sizeof(tRegVecGrupos)); if (vecGrupos == NULL) return ERROR_MEMORIA; memcpy((void*)vecGrupos,(void*)agrup.vecGrupos,capacidadVecGrupos * sizeof(tRegVecGrupos)); /* duplicamos los centroides */ for (i = 0; i < cantGrupos; i++) { if (agrup.vecGrupos[i].vecCentroide != NULL) { vecGrupos[i].vecCentroide = new c_VecArchivo(); codRet = vecGrupos[i].vecCentroide>Duplicar(*(agrup.vecGrupos[i].vecCentroide)); if (codRet != OK) return codRet;
166
APNDICE 4 - PROGRAMACION
Eugenio Yolis
} else { vecGrupos[i].vecCentroide = NULL; } } return OK; } uent c_Agrupamiento::AgruparAlAzar(uent cantGrupMin, uent cantGrupMax) { /* Agrupa los elementos al azar */ /* Debe llamarse luego de ::Inicializar() */ /* Devuelve OK o el error que corresponda */ uent i; uent nroElemRand; uent grupAsig; /* la cantidad de grupos debe estar entre cantGrupMin y cantGrupMax */ cantGrupos = RANDOM(1 + cantGrupMax - cantGrupMin) + cantGrupMin; vecGrupos = (tRegVecGrupos*)malloc(cantGrupos * sizeof(tRegVecGrupos)); if (vecGrupos == NULL) return ERROR_MEMORIA; capacidadVecGrupos = cantGrupos; /* inicializamos cada grupo */ for (i=0; i < cantGrupos; i++) { vecGrupos[i].cantElementos = 0; vecGrupos[i].nroGrupo = i+1; /* en el campo menorNroElem ponemos el numero "cantElementos" del agrupamiento, para que sea mayor a cualquier nmero de elemento */ vecGrupos[i].menorNroElem = cantElementos; vecGrupos[i].vecCentroide = NULL; } /* ahora nos aseguramos de poner 1 elemento por grupo */ for (i=0; i < cantGrupos; i++) { /* elegimos un elemento al azar */ nroElemRand = RANDOM(cantElementos); /* si ya est asignado, buscamos otro */ while (vecElementos[nroElemRand] != 0) nroElemRand = RANDOM(cantElementos); /* le asignamos el grupo */ vecElementos[nroElemRand] = vecGrupos[i].nroGrupo; } /* ahora recorremos el vector y vamos asignando grupos al azar */ for (i=0; i < cantElementos; i++) { /* veamos si ese elemento no tiene grupo */ if (vecElementos[i] == 0) { /* le asignamos uno */ grupAsig = RANDOM(cantGrupos); vecElementos[i] = vecGrupos[grupAsig].nroGrupo; } else
Eugenio Yolis
APNDICE 4 - PROGRAMACION
167
{ /* buscamos el grupo del elemento */ grupAsig = IndiceDeGrupo(vecElementos[i],false); } /* sumamos un elemento al grupo */ vecGrupos[grupAsig].cantElementos++; /* vemos si este elemento es el menor nro de elementos del grupo */ if (vecGrupos[grupAsig].menorNroElem > i) vecGrupos[grupAsig].menorNroElem = i; } return OK; } void c_Agrupamiento::CopiarRegVecGrupos(uent i, uent j, tRegVecGrupos *nuevoVecGrupos) { /* copia la entrada "i" del vector de grupos a la entrada j del nuevo vector de grupos */ nuevoVecGrupos[j].cantElementos = vecGrupos[i].cantElementos; nuevoVecGrupos[j].menorNroElem = vecGrupos[i].menorNroElem; nuevoVecGrupos[j].nroGrupo = vecGrupos[i].nroGrupo; nuevoVecGrupos[j].vecCentroide = vecGrupos[i].vecCentroide; } uent c_Agrupamiento::AgregarGrupos(uent cantidad) { /* agrega "cantidad" grupos al agrupamiento, alocando ms memoria si es necesario */ /* los grupos se crean vacos, por lo que el agrupamiento queda en un estado inconsistente */ /* devuelve OK o el error que corresponda */ uent capacidadAgregar, incrementosAgregar; tRegVecGrupos *nuevoVecGrupos; uent i; uent siguienteNro; uent cantGrupOld; /* veamos cuanto tenemos que agrandar el vector */ if (capacidadVecGrupos < (cantGrupos+cantidad)) { capacidadAgregar = (cantGrupos+cantidad) - capacidadVecGrupos; incrementosAgregar = 1 + (capacidadAgregar / AGRUP_INC_CANT_GRUPOS); capacidadVecGrupos += (incrementosAgregar*AGRUP_INC_CANT_GRUPOS); nuevoVecGrupos = (tRegVecGrupos*)malloc(capacidadVecGrupos * sizeof(tRegVecGrupos)); if (nuevoVecGrupos == NULL) return ERROR_MEMORIA; /* copiamos el vector anterior al nuevo */ for (i=0; i < cantGrupos; i++) { CopiarRegVecGrupos(i, i, nuevoVecGrupos); } /* damos de baja el viejo vector y usamos el nuevo */ free((void*)vecGrupos); vecGrupos = nuevoVecGrupos; } /* veamos si quedan suficientes numeros de grupo para agregar */
168
APNDICE 4 - PROGRAMACION
Eugenio Yolis
siguienteNro = SiguienteNroGrupo(); if ((siguienteNro + cantidad) > MAX_UENT) /* renumeramos los grupos */ { RenumerarGrupos(); siguienteNro = SiguienteNroGrupo(); } /* agregamos los nuevos grupos al vector */ cantGrupOld = cantGrupos; for (i=0; i < cantidad; i++) { vecGrupos[cantGrupOld + i].cantElementos = 0; /* en el campo "menorNroElemento" ponemos la cantidad de elementos del agrupamiento, para que sea mayor a cualquier numero de elemento */ vecGrupos[cantGrupOld + i].menorNroElem = cantElementos; vecGrupos[cantGrupOld + i].nroGrupo = siguienteNro; vecGrupos[cantGrupOld + i].vecCentroide = NULL; siguienteNro++; cantGrupos++; } return OK; }
void c_Agrupamiento::RenumerarGrupos() { /* renumera los grupos */ /* esta funcin debe utilizarse en el improbable caso de que se hayan usado ms de 65536 nmeros de grupo, por agregar y borrar grupos muchas veces */ uent i,j, nroAnterior; for (i=0; i < cantGrupos; i++) { nroAnterior = vecGrupos[i].nroGrupo; vecGrupos[i].nroGrupo = i + 1; for (j=0; j < cantElementos; j++) if (vecElementos[j] == nroAnterior) vecElementos[j] = vecGrupos[i].nroGrupo; } } void c_Agrupamiento::EliminarRegVecGrupos(uent indGrupo) { /* Elimina la entrada con ndice "indGrupo" del vector de grupos */ uent i; if (vecGrupos[indGrupo].vecCentroide != NULL) delete(vecGrupos[indGrupo].vecCentroide); for (i = indGrupo; i < cantGrupos - 1; i++) CopiarRegVecGrupos(i+1, i, vecGrupos); cantGrupos--; } void c_Agrupamiento::MoverElemento(uent nroElem, uent indGrupNuevo, uent indGrupAnterior) { /*
Eugenio Yolis
APNDICE 4 - PROGRAMACION
169
Mueve el elemento "nroElem" del grupo con ndice "indGrupAnterior" al grupo con ndice "indGrupNuevo" Si el grupo anterior queda vaco, lo elimina */ uent i; if (indGrupNuevo != indGrupAnterior) { vecElementos[nroElem] = vecGrupos[indGrupNuevo].nroGrupo; vecGrupos[indGrupNuevo].cantElementos++; /* veamos si el que agregamos al nuevo grupo es el menor nro de elemento */ if (nroElem < vecGrupos[indGrupNuevo].menorNroElem) vecGrupos[indGrupNuevo].menorNroElem = nroElem; if (vecGrupos[indGrupAnterior].cantElementos <= 1) EliminarRegVecGrupos(indGrupAnterior); else { vecGrupos[indGrupAnterior].cantElementos--; /* veamos si el que le sacamos era el menor numero de elemento */ if (nroElem == vecGrupos[indGrupAnterior].menorNroElem) { /* buscamos el nuevo menor numero de elemento */ i = nroElem + 1; while (i < cantElementos) { if (vecElementos[i] == vecGrupos[indGrupAnterior].nroGrupo) break; i++; } vecGrupos[indGrupAnterior].menorNroElem = i; } } } }
170
APNDICE 4 - PROGRAMACION
Eugenio Yolis
A4.2.7 ClsAgrupImprime.h
/* Clase que imprime agrupamientos, grupos y documentos para ser desplegados al usuario */ #ifndef __clsAgrupImprime__ #define __clsAgrupImprime__ #include <malloc.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "def.h" #include "sis.h" #include "vecArchivos.h" #include "clsAgrupamiento.h" #include "skipl.h" #include "clsKMeans.h" class c_Agrup_Imprime { private: public: static bool salidaCompacta; c_Agrup_Imprime() {}; ~c_Agrup_Imprime() {}; static uent ImprimirVecArchivo(FILE *fp, c_VecArchivo &vecArchivo, c_SkipList &lexico); static uent ImprimirTodo(FILE *fp, c_Agrupamiento &agrup, c_VecArchivo *vVecArchivos[], c_SkipList &lexico, c_SkipList <xt); static uent ImprimirGrupo(FILE *fp, uent indGrupo, c_Agrupamiento &agrup, c_VecArchivo *vVecArchivos[], c_SkipList &lexico, c_SkipList <xt); static uent ImprimirDocumento(FILE *fp, uent nroElem, c_VecArchivo *vVecArchivos[], c_SkipList &lexico); };
#endif
Eugenio Yolis
APNDICE 4 - PROGRAMACION
171
A4.2.8 ClsAgrupImprime.cpp
#include "clsAgrupImprime.h" /* si se setea salidaCompacta en true, la salida va a estar preparada para ser procesada en forma automtica por otro programa */ bool c_Agrup_Imprime::salidaCompacta = false; uent c_Agrup_Imprime::ImprimirVecArchivo(FILE *fp, c_VecArchivo &vecArchivo, c_SkipList &lexico) { /* En "fp" recibe un archivo de texto abierto */ /* Imprime las palabras claves del vector */ uent i, cantKeywords; ubyte palabra[MAX_LONG_PALABRA]; uent nroPalEnt; uword nroPalLong; real auxReal; cantKeywords = vecArchivo.ConseguirCantEntradas(true); /* recorremos la lista de atras para adelante porque las ultimas entradas son las de mayor peso */ for (i=cantKeywords; i > 0; i--) { vecArchivo.ConseguirEntrada(i-1,nroPalEnt,auxReal,true); if (nroPalEnt > 0) { /* la buscamos en la lista de lexico */ nroPalLong = (uword)nroPalEnt; lexico.Buscar(palabra,nroPalLong); /* la imprimimos */ fprintf(fp,"%s",(char*)palabra); } if (i > 1) fprintf(fp," ; "); } return OK; } uent c_Agrup_Imprime::ImprimirDocumento(FILE *fp, uent nroElem, c_VecArchivo *vVecArchivos[], c_SkipList &lexico) { /* En "fp" recibe un archivo de texto abierto */ /* Imprime las palabras claves del documento */ uent codRet; if (salidaCompacta) { fprintf(fp,"%d",nroElem); } else { codRet = ImprimirVecArchivo(fp,*(vVecArchivos[nroElem]),lexico); if (codRet != OK) return codRet;
172
APNDICE 4 - PROGRAMACION
Eugenio Yolis
} return OK; }
uent c_Agrup_Imprime::ImprimirGrupo(FILE *fp,uent indGrupo,c_Agrupamiento &agrup,c_VecArchivo *vVecArchivos[],c_SkipList &lexico, c_SkipList <xt) { /* en fp recibe un archivo abierto */ /* imprime el numero del grupo, sus palabras claves, y cada uno de los documentos que lo componen */ uent j; uword jLong; ubyte nomArch[MAX_LONG_NOMARCH]; real similPromGrupo; real simElemCent; /* calculamos la similitud promedio de los elementos del grupo (es igual al cuadrado de la norma del centroide) */ if (agrup.vecGrupos[indGrupo].vecCentroide != NULL) similPromGrupo = agrup.vecGrupos[indGrupo].vecCentroide>CalcularNorma(false); else similPromGrupo = 0; similPromGrupo *= similPromGrupo; /* al cuadrado */ /* imprimimos el numero del grupo */ if (salidaCompacta) { fprintf(fp,"_G_%d[%f]=",indGrupo,similPromGrupo); } else { fprintf(fp,"Grupo %d (%d). Elementos=%d. Similitud Promedio=%f : ",indGrupo+1,agrup.vecGrupos[indGrupo].nroGrupo,agrup.vecGrupos[indGrupo].cantElementos ,similPromGrupo); if (agrup.vecGrupos[indGrupo].vecCentroide != NULL) { agrup.vecGrupos[indGrupo].vecCentroide->ActualizarPalabrasClave(); ImprimirVecArchivo(fp,*(agrup.vecGrupos[indGrupo].vecCentroide),lexico); } //xxxdebug else ImprimirVecArchivo(fp,*(vVecArchivos[agrup.vecGrupos[indGrupo].menorNroElem + 1]),lexico); fprintf(fp,"\n"); } /* imprimimos los elementos del grupo */ for (j=0; j < agrup.cantElementos; j++) if (agrup.vecElementos[j] == agrup.vecGrupos[indGrupo].nroGrupo) if (salidaCompacta) { jLong = (uword)j + 1; ltxt.Buscar(nomArch,jLong); fprintf(fp,"%s;",(char*)nomArch);
Eugenio Yolis
APNDICE 4 - PROGRAMACION
173
//ImprimirDocumento(fp,j+1,vVecArchivos,lexico); //fprintf(fp,";"); } else { jLong = (uword)j + 1; ltxt.Buscar(nomArch,jLong); simElemCent = c_KMeans::ValorCriterioActual(agrup,vVecArchivos,j,indGrupo); fprintf(fp,"\t%s (%f)\n",(char*)nomArch,simElemCent); fprintf(fp,"\t\t"); ImprimirDocumento(fp,j+1,vVecArchivos,lexico); fprintf(fp,"\n"); } fprintf(fp,"\n"); return OK; } uent c_Agrup_Imprime::ImprimirTodo(FILE *fp,c_Agrupamiento &agrup,c_VecArchivo *vVecArchivos[],c_SkipList &lexico, c_SkipList <xt) { /* imprime el agrupamiento */ uent i, codRet; for (i=0; i < agrup.cantGrupos ; i++) { codRet = ImprimirGrupo(fp,i,agrup,vVecArchivos,lexico,ltxt); if (codRet != OK) return codRet; }
return OK; }
174
APNDICE 4 - PROGRAMACION
Eugenio Yolis
A4.2.9 ClsKMeans.h
/* Clase que implementa las funciones del algoritmo kmeans */ #ifndef __clsKMeans__ #define __clsKMeans__ #include <malloc.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "def.h" #include "sis.h" #include "vecArchivos.h" #include "clsAgrupamiento.h" //xxxdebug #include "skipl.h" #include "clsAgrupImprime.h" class c_KMeans { private: static uent ElegirKCentroides(c_Agrupamiento &agrup, uent nroGrupo, uent *indGrupos, c_VecArchivo *vVecArchivos[], bool bOptimizarSeparacion, uent cantMuestras); public: static uword contMoverYRecalcular; /* cuenta las veces que se llam a la funcin de mover y recalcular */ static uent k; static uent codCriterio; /* el criterio de optimizacion que se utiliza para refinar */ /* 1 : minima distancia de cada elemento al centroide del grupo */ /* 2 : ... */ c_KMeans() {}; ~c_KMeans() {}; static uent FaseInicial(c_Agrupamiento &agrup, uent nroGrupo, c_VecArchivo *vVecArchivos[], uent *indGrupos, bool bOptimizarSeparacion, uent cantMuestras); static uent FaseInicialLite(c_Agrupamiento &agrup, uent nroGrupo, c_VecArchivo *vVecArchivos[], uent *indGrupos, bool bOptimizarSeparacion, uent cantMuestras); static uent CalcularCentroides(c_Agrupamiento &agrup,c_VecArchivo *vVecArchivos[],uent cantGrup,uent *vecIndGrupos); static uent FaseRefinar(c_Agrupamiento &agrup, c_VecArchivo *vVecArchivos[], uent *indGrupos,bool iteracionesFijas, uent &cantIteraciones, uent &cantCambiosTotal); static uent FaseRefinarLite(c_Agrupamiento &agrup, c_VecArchivo *vVecArchivos[], uent *indGrupos,bool iteracionesFijas, uent &cantIteraciones, uent &cantCambiosTotal); static bool NroGrupoEstaEnVectorIndices(uent nro, uent *vector,uent cantEntradas, c_Agrupamiento &agrup, uent &indGrupo); static real ValorCriterioActual(c_Agrupamiento &agrup, c_VecArchivo *vVecArchivos[], uent nroElemAnalisis, uent indGrupoAnalisis); static real ValorCriterioAlternativa(c_Agrupamiento &agrup, c_VecArchivo *vVecArchivos[], uent nroElemAnalisis, uent indGrupoCandidato, real valCriterioActual);
Eugenio Yolis
APNDICE 4 - PROGRAMACION
175
static uent MoverElementoyRecalcular(c_Agrupamiento &agrup,c_VecArchivo *vVecArchivos[],uent nroElem,uent indGrupoOrig,uent indGrupoGanador, bool restarACentroide); static uent BisectingKMeans(c_Agrupamiento* &agrup, uent nroGrupo, c_VecArchivo *vVecArchivos[], uent kBisect, bool refinar); };
#endif
176
APNDICE 4 - PROGRAMACION
Eugenio Yolis
A4.2.10 ClsKMeans.cpp
#include "clsKMeans.h" #define MAX_VALOR_CRITERIO (real)1000000.0 /* maximo valor que va a tomar cualquiera de los criterios de optimizacion */ #define MARGEN_CRITERIO (real)0.1 /* por defecto k = 5 */ uent c_KMeans::k = 5; uword c_KMeans::contMoverYRecalcular = 0; /* por defecto criterio = 1 */ uent c_KMeans::codCriterio = 1; uent c_KMeans::ElegirKCentroides(c_Agrupamiento &agrup, uent nroGrupo, uent *indGrupos, c_VecArchivo *vVecArchivos[], bool bOptimizarSeparacion, uent cantMuestras) { /* elige K centroides al azar los K centroides al azar los toma del grupo "nroGrupo" En el campo "menorNroElem" del grupo "nroGrupo" pone el nro de elemento de uno de los centroides. Tambien crea (k - 1) grupos ms en el agrupamiento y al campo "menorNroElem" de cada uno de esos grupos le asigna su respectivo centroide Deja el agrupamiento en un estado inconsistente, ya que se usa el campo de menor grupo de elemento para designar al centroide elegido. (solo es inconsistente para el grupo "nroGrupo", para los nuevos grupos, el centroide es el nico elemento En el vector "indGrupos" (que se recibe con memoria alocada para k nmeros) devuelve un vector con los ndices del grupo original y los grupos que se crearon En el caso particular de que haya que elegir 2 centroides, si el parmetro bOptimizarSeparacion es true, toma "cantMuestras" elementos al azar y elige los 2 que estn ms distantes el uno del otro */ uent *nrosAzar, *vNroElem; uent indGrupo, cantElemGrupo, cantGruposAnterior; uent codRet; uent i, j, indElem, indElemGrupo; uent parejaMasDistante[2]; real menorSimProm, simProm; c_VecArchivo *vArch1, *vArch2; indGrupo = agrup.IndiceDeGrupo(nroGrupo,false); cantElemGrupo = agrup.vecGrupos[indGrupo].cantElementos; cantGruposAnterior = agrup.cantGrupos; /* generamos los numeros al azar */ if ((bOptimizarSeparacion == false) || (k != 2)) { /* deben generarse k numeros al azar */ cantMuestras = k; }
Eugenio Yolis
APNDICE 4 - PROGRAMACION
177
/* generamos cantMuestras nmeros que esten entre 1 y la cantidad de elementos del grupo */ nrosAzar = kNumerosRandom(cantMuestras,1,cantElemGrupo,true); if (nrosAzar == NULL) return ERROR_MEMORIA; vNroElem = (uent*)malloc(cantMuestras * SINT); if (vNroElem == NULL) return ERROR_MEMORIA; /* asignamos el numero de elemento que corresponde a cada uno */ indElem = 0; indElemGrupo = 0; for (i=0; i < cantMuestras; i++) { while(indElemGrupo < nrosAzar[i]) { if (agrup.vecElementos[indElem] == nroGrupo) indElemGrupo++; indElem++; } vNroElem[i] = indElem - 1; } if ((bOptimizarSeparacion == true) && (k == 2)) { /* tenemos que elegir los 2 elementos mas distantes */ menorSimProm = (real)10000.0; /* vamos del primero al anteultimo */ for (i = 0; i < cantMuestras - 1; i++) { vArch1 = vVecArchivos[vNroElem[i]+1]; /* vamos desde el siguiente a i hasta el ultimo */ for (j=i+1; j < cantMuestras; j++) { vArch2 = vVecArchivos[vNroElem[j]+1]; /* calculamos la similitud */ simProm = vArch1->Multiplicar(*vArch2,false); if (simProm < menorSimProm) { menorSimProm = simProm; parejaMasDistante[0] = vNroElem[i]; parejaMasDistante[1] = vNroElem[j]; } } } vNroElem[0] = parejaMasDistante[0]; vNroElem[1] = parejaMasDistante[1]; } /* creamos k - 1 grupos mas */ codRet = agrup.AgregarGrupos(k - 1); if (codRet != OK) return codRet; /* ahora, al campo "menorNroElem" de cada grupo le asignamos el nmero de elemento elegido al azar */ indElem = 0; indElemGrupo = 0; for (i=0; i < k; i++) {
178
APNDICE 4 - PROGRAMACION
Eugenio Yolis
if (i == 0) /* el primero es el grupo original */ { agrup.vecGrupos[indGrupo].menorNroElem = vNroElem[i]; indGrupos[i] = indGrupo; } else /* los siguientes son los que se agregaron */ { agrup.vecGrupos[cantGruposAnterior - 1 + i].menorNroElem = vNroElem[i]; indGrupos[i] = cantGruposAnterior - 1 + i; } } free((void*)nrosAzar); free((void*)vNroElem); return OK; }
uent c_KMeans::FaseInicial(c_Agrupamiento &agrup, uent nroGrupo, c_VecArchivo *vVecArchivos[], uent *indGrupos, bool bOptimizarSeparacion, uent cantMuestras) { /* Fase inicial del algoritmo kmeans Se supone que el agrupamiento "agrup" se ha inicializado y contiene al menos 1 grupo En "nroGrupo" recibe el numero de grupo a separar En la fase inicial, se arma un agrupamiento de la siguiente forma: - se eligen k elementos como los centroides - se asigna cada elemento al grupo del centroide ms cercano En el vector "indGrupos" (que se recibe con memoria alocada para k nmeros) devuelve un vector con los ndices de los grupos en los que se separaron los elementos Devuelve OK o el error que corresponda */ uent grupGanador, indGrupo, cantGruposAnterior; real similGanador, similAux; uent codRet; uent *ordenProceso, *nrosElementos; uent cantElemGrupo, i, j, indElemGrupo, nroElem; c_VecArchivo *vecArchivoElem; bool esCentroide,ganoEmpate; uent empates; /* tomamos el ndice del grupo y la cantidad de grupos */ indGrupo = agrup.IndiceDeGrupo(nroGrupo,false); cantGruposAnterior = agrup.cantGrupos; /* elegimos los k centroides de los elementos del grupo */ codRet = ElegirKCentroides(agrup,nroGrupo,indGrupos,vVecArchivos,bOptimizarSeparacion,cantMuestr as); if (codRet != OK) return codRet; /* elegimos un orden al azar para procesar los elementos del grupo */ cantElemGrupo = agrup.vecGrupos[indGrupo].cantElementos; ordenProceso = kNumerosRandom(cantElemGrupo,1,cantElemGrupo,false);
Eugenio Yolis
APNDICE 4 - PROGRAMACION
179
if (ordenProceso == NULL) return ERROR_MEMORIA; /* armamos un vector con los numeros de elemento del grupo */ nrosElementos = (uent*)malloc(cantElemGrupo * SINT); indElemGrupo = 0; for (i = 0; i < agrup.cantElementos; i++) { if (agrup.vecElementos[i] == nroGrupo) { //xxxdebug //printf("c_KMeans::FI::orAzar : %d ;; nroElem : %d\n",ordenProceso[indElemGrupo]-1,i); nrosElementos[ordenProceso[indElemGrupo]-1] = i; indElemGrupo++; } } /* el centroide de cada grupo es el elemento que figura en el campo "menorNroElem" */ for (i = 0; i < k; i++) { if (i == 0) j = indGrupo; else j = cantGruposAnterior + i - 1; if (agrup.vecGrupos[j].vecCentroide != NULL) delete(agrup.vecGrupos[j].vecCentroide); agrup.vecGrupos[j].vecCentroide = new c_VecArchivo; agrup.vecGrupos[j].vecCentroide>Duplicar(*(vVecArchivos[agrup.vecGrupos[j].menorNroElem + 1])); } /* los procesamos en el orden al azar, buscando su nuevo grupo */ for (i = 0; i < cantElemGrupo; i++) { empates = 0; esCentroide = false; nroElem = nrosElementos[i]; vecArchivoElem = vVecArchivos[nroElem + 1]; /* veamos la similitud con el centroide del grupo original */ if (nroElem == agrup.vecGrupos[indGrupo].menorNroElem) { esCentroide = true; grupGanador = indGrupo; } else { similGanador = vecArchivoElem>Multiplicar(*(agrup.vecGrupos[indGrupo].vecCentroide),false); grupGanador = indGrupo; } /* ahora con los otros */ for (j = 0; j < k-1; j++) { if (!esCentroide) { if (nroElem == agrup.vecGrupos[cantGruposAnterior + j].menorNroElem) { esCentroide = true;
180
APNDICE 4 - PROGRAMACION
Eugenio Yolis
grupGanador = cantGruposAnterior + j; } else { similAux = vecArchivoElem>Multiplicar(*(agrup.vecGrupos[cantGruposAnterior + j].vecCentroide),false); ganoEmpate = false; if (similAux == similGanador) { empates++; ganoEmpate = (RANDOM(empates+1)==0); } if ((similAux > similGanador) || ganoEmpate) { similGanador = similAux; grupGanador = cantGruposAnterior + j; } } } } if (bOptimizarSeparacion) { c_KMeans::MoverElementoyRecalcular(agrup,vVecArchivos,nroElem,indGrupo,grupGa nador,false); } else { /* si hace falta, lo movemos */ if (grupGanador != indGrupo) { agrup.MoverElemento(nroElem, grupGanador, indGrupo); } } //xxxdebug //if (esCentroide) //printf("c_KMeans:FI: Elem : %d ;; Es centroide de : %d\n",nroElem,grupGanador + 1); //else //printf("c_KMeans:FI: Elem : %d ;; SimGan : %f ;; GrupGan : %d\n",nroElem,similGanador,grupGanador + 1); } free((void*)ordenProceso); free((void*)nrosElementos); return OK; } uent c_KMeans::FaseInicialLite(c_Agrupamiento &agrup, uent nroGrupo, c_VecArchivo *vVecArchivos[], uent *indGrupos, bool bOptimizarSeparacion, uent cantMuestras) { /* Igual que la fase inicial pero version "Lite" */ uent grupGanador, indGrupo, cantGruposAnterior; real similGanador, similAux; uent codRet;
Eugenio Yolis
APNDICE 4 - PROGRAMACION
181
uent *ordenProceso, *nrosElementos; uent cantElemGrupo, i, j, indElemGrupo, nroElem; c_VecArchivo *vecArchivoElem; bool esCentroide,ganoEmpate; uent empates; uent cantGruposMuestra; uent *vecIndGruposMuestra; /* tomamos el ndice del grupo y la cantidad de grupos */ indGrupo = agrup.IndiceDeGrupo(nroGrupo,false); cantGruposAnterior = agrup.cantGrupos; /* elegimos los k centroides de los elementos del grupo */ codRet = ElegirKCentroides(agrup,nroGrupo,indGrupos,vVecArchivos,bOptimizarSeparacion,cantMuestr as); if (codRet != OK) return codRet; /* elegimos un orden al azar para procesar los elementos del grupo */ cantElemGrupo = agrup.vecGrupos[indGrupo].cantElementos; ordenProceso = kNumerosRandom(cantElemGrupo,1,cantElemGrupo,false); if (ordenProceso == NULL) return ERROR_MEMORIA; /* armamos un vector con los numeros de elemento del grupo */ nrosElementos = (uent*)malloc(cantElemGrupo * SINT); indElemGrupo = 0; for (i = 0; i < agrup.cantElementos; i++) { if (agrup.vecElementos[i] == nroGrupo) { //xxxdebug //printf("c_KMeans::FI::orAzar : %d ;; nroElem : %d\n",ordenProceso[indElemGrupo]-1,i); nrosElementos[ordenProceso[indElemGrupo]-1] = i; indElemGrupo++; } } /* la cantidad de grupos muestra es del orden de log k */ cantGruposMuestra = (uent)(log(k)/log(2))*2; /* los procesamos en el orden al azar, buscando su nuevo grupo */ for (i = 0; i < cantElemGrupo; i++) { /* armamos el vector de muestra de grupos */ vecIndGruposMuestra = kNumerosRandom(cantGruposMuestra,0,k-1,true); if (vecIndGruposMuestra == NULL) return ERROR_MEMORIA; empates = 0; esCentroide = false; nroElem = nrosElementos[i]; vecArchivoElem = vVecArchivos[nroElem + 1]; /* veamos la similitud con el centroide del grupo original */ if (nroElem == agrup.vecGrupos[vecIndGruposMuestra[0]].menorNroElem) { esCentroide = true; grupGanador = vecIndGruposMuestra[0]; } else
182
APNDICE 4 - PROGRAMACION
Eugenio Yolis
{ similGanador = vecArchivoElem>Multiplicar(*(vVecArchivos[agrup.vecGrupos[vecIndGruposMuestra[0]].menorNroElem + 1]),false); grupGanador = vecIndGruposMuestra[0]; } /* ahora con los otros */ for (j = 1; j < cantGruposMuestra-1; j++) { if (!esCentroide) { if (nroElem == agrup.vecGrupos[vecIndGruposMuestra[j]].menorNroElem) { esCentroide = true; grupGanador = vecIndGruposMuestra[j]; } else { similAux = vecArchivoElem>Multiplicar(*(vVecArchivos[agrup.vecGrupos[vecIndGruposMuestra[j]].menorNroElem + 1]),false); ganoEmpate = false; if (similAux == similGanador) { empates++; ganoEmpate = (RANDOM(empates+1)==0); } if ((similAux > similGanador) || ganoEmpate) { similGanador = similAux; grupGanador = vecIndGruposMuestra[j]; } } } } /* si hace falta, lo movemos */ if (grupGanador != indGrupo) { agrup.MoverElemento(nroElem, grupGanador, indGrupo); } free((void*)vecIndGruposMuestra); //xxxdebug //if (esCentroide) //printf("c_KMeans:FI: Elem : %d ;; Es centroide de : %d\n",nroElem,grupGanador + 1); //else //printf("c_KMeans:FI: Elem : %d ;; SimGan : %f ;; GrupGan : %d\n",nroElem,similGanador,grupGanador + 1); } free((void*)ordenProceso); free((void*)nrosElementos); return OK; }
Eugenio Yolis
APNDICE 4 - PROGRAMACION
183
uent c_KMeans::CalcularCentroides(c_Agrupamiento &agrup,c_VecArchivo *vVecArchivos[],uent cantGrup,uent *vecIndGrupos) { /* calcula los centroides de los grupos */ /* devuelve OK o el error que corresponda */ /* si cantGrup es 0, calcula los centroides de todos los grupos si no, calcula solamente los centroides de los grupos que estan en vecIndGrupos */ uent i,codRet,indAux; uent j, cantElemGrup; real unoSobre; c_VecArchivo *centroide; for (i=0; i < agrup.cantGrupos; i++) { if ((cantGrup == 0) || NroGrupoEstaEnVectorIndices(agrup.vecGrupos[i].nroGrupo,vecIndGrupos,cantGrup,agrup,ind Aux)) { /* si tena el centroide creado, lo reinicializamos */ if (agrup.vecGrupos[i].vecCentroide != NULL) { delete(agrup.vecGrupos[i].vecCentroide); } centroide = new c_VecArchivo; agrup.vecGrupos[i].vecCentroide = centroide; codRet = centroide->CrearVector(0); if (codRet != OK) return codRet; cantElemGrup = agrup.vecGrupos[i].cantElementos; /* sumamos los elementos de ese grupo */ for (j=0; j < agrup.cantElementos; j++) if (agrup.vecElementos[j] == agrup.vecGrupos[i].nroGrupo) centroide->Sumar(*(vVecArchivos[j+1])); /* dividimos cada entrada por la cantidad de elementos del grupo */ unoSobre = (real)1.0 / (real)cantElemGrup; centroide->MultiplicarPorReal(unoSobre); /* actualizamos las palabras clave */ centroide->ActualizarPalabrasClave(); } } return OK; } uent c_KMeans::FaseRefinar(c_Agrupamiento &agrup, c_VecArchivo *vVecArchivos[], uent *indGrupos,bool iteracionesFijas, uent &cantIteraciones, uent &cantCambiosTotal) { /* ejecuta la fase de refinamiento del algoritmo k-means en el vector indGrupos recibe los indices de los grupos entre los cuales puede mover documentos en agrup recibe un agrupamiento que ya tiene calculados los centroides de sus grupos el parametro iteracionesFijas indica si el algoritmo debe ejecutarse hasta un numero mximo de iteraciones. en caso de que sea verdadero, el parametro cantIteraciones indica este nmero mximo
184
APNDICE 4 - PROGRAMACION
Eugenio Yolis
la funcin itera hasta que no se producen cambios en los grupos o hasta alcanzar el mximo nmero de iteraciones (si corresponde) en el parametro cantIteraciones se devuelve la cantidad de iteraciones que se realizaron */ uent iIteraciones,iElem,iGrupos,cantCambios, indGrupoOrig; uent cantElementos, nroElem, nroGrupoElem, indGrupoGanador; uent *ordenProceso; real valorActual, valorAux, incGanador; uent codRet; bool bParar; cantElementos = agrup.cantElementos; iIteraciones = 0; cantCambiosTotal = 0; bParar = false;
while (!bParar) { cantCambios = 0; /* buscamos un orden al azar para procesar los elementos */ ordenProceso = kNumerosRandom(cantElementos,0,cantElementos-1,false); if (ordenProceso == NULL) return ERROR_MEMORIA; /* vamos iterando por todos los elementos pero procesamos solamente los de los grupos que nos interesan */ for (iElem=0; iElem<cantElementos; iElem++) { /* tomamos el elemento */ nroElem = ordenProceso[iElem]; ///xxxdebug //printf("KMRefinar:Proc.Elem=%d\n",nroElem); nroGrupoElem = agrup.vecElementos[nroElem]; /* veamos si esta en uno de los grupos que nos interesan */ if (NroGrupoEstaEnVectorIndices(nroGrupoElem,indGrupos,k,agrup,indGrupoOrig)) { ///xxxdebug //printf(" nos interesa(grupo=%d)\n",nroGrupoElem); /* calculamos el valor actual, y decimos que el ganador es el grupo actual */ indGrupoGanador = indGrupoOrig; valorActual = ValorCriterioActual(agrup,vVecArchivos,nroElem,indGrupoOrig); incGanador = 0.0; /* evaluamos el movimiento a cada uno de los otros grupos */ //xxxdebug //printf(" increm:[%f];;;",valorActual); for (iGrupos=0; iGrupos < k; iGrupos++) { if (iGrupos != indGrupoGanador) /* no evaluamos 2 veces el grupo original */
Eugenio Yolis
APNDICE 4 - PROGRAMACION
185
{ valorAux = ValorCriterioAlternativa(agrup,vVecArchivos,nroElem,iGrupos,valorActual); if ((valorAux - valorActual) > incGanador) { /* este incremento va ganando por ahora */ indGrupoGanador = iGrupos; incGanador = (valorAux - valorActual); } //xxxdebug //printf("%f;;;",valorAux - valorActual); } } //xxxdebug //printf("\n"); /* veamos si hubo un ganador */ if (indGrupoGanador != indGrupoOrig) { /* hay que mover el elemento */ codRet = MoverElementoyRecalcular(agrup,vVecArchivos,nroElem,indGrupoOrig,indGrupoGanador,true) ; if (codRet != OK) return codRet; cantCambios++; /* sumamos un cambio esta vuelta */ //xxxdebug //printf("KMRefinar::Cambio.Iter=%d Elem=%d;Orig=%d;Dest=%d\n",iIteraciones,nroElem,indGrupoOrig,indGrupoGanador); } } } cantCambiosTotal += cantCambios; //xxxdebug //printf("KMRefinar::FinIter=%d Cambios=%d\n",iIteraciones,cantCambios); /* liberamos el vector de orden aleatorio */ free((void*)ordenProceso); /* si no hubo ningun cambio tenemos que parar */ if (cantCambios == 0) bParar = true; /* sumamos una iteracion mas y vemos si ya tenemos que parar */ iIteraciones++; if (iIteraciones >= cantIteraciones) bParar = true; } /* devolvemos la cantidad de iteraciones */ cantIteraciones = iIteraciones; //xxxdebug printf("KMRefinar::Fin TotalIter=%d TotalCambios=%d\n",iIteraciones,cantCambiosTotal);
return OK;
186
APNDICE 4 - PROGRAMACION
Eugenio Yolis
} uent c_KMeans::FaseRefinarLite(c_Agrupamiento &agrup, c_VecArchivo *vVecArchivos[], uent *indGrupos,bool iteracionesFijas, uent &cantIteraciones, uent &cantCambiosTotal) { /* Igual que la fase inicial pero version "Lite" */ uent iIteraciones,iElem,iGrupos,cantCambios, indGrupoOrig; uent cantElementos, nroElem, nroGrupoElem, indGrupoGanador; uent *ordenProceso; real valorActual, valorAux, incGanador; uent codRet; bool bParar; uent cantGruposMuestra; uent *vecIndGruposMuestra; uent h; cantElementos = agrup.cantElementos; iIteraciones = 0; cantCambiosTotal = 0; bParar = false; /* la cantidad de grupos muestra es del orden de log k */ cantGruposMuestra = (uent)(log(k)/log(2))*2; while (!bParar) { cantCambios = 0; /* buscamos un orden al azar para procesar los elementos */ ordenProceso = kNumerosRandom(cantElementos,0,cantElementos-1,false); if (ordenProceso == NULL) return ERROR_MEMORIA; /* vamos iterando por todos los elementos pero procesamos solamente los de los grupos que nos interesan */ for (iElem=0; iElem<cantElementos; iElem++) { /* tomamos el elemento */ nroElem = ordenProceso[iElem]; ///xxxdebug //printf("KMRefinar:Proc.Elem=%d\n",nroElem); nroGrupoElem = agrup.vecElementos[nroElem]; /* veamos si esta en uno de los grupos que nos interesan */ if (NroGrupoEstaEnVectorIndices(nroGrupoElem,indGrupos,k,agrup,indGrupoOrig)) { ///xxxdebug //printf(" nos interesa(grupo=%d)\n",nroGrupoElem); /* armamos el vector de muestra de grupos */ vecIndGruposMuestra = kNumerosRandom(cantGruposMuestra,0,k-1,true); if (vecIndGruposMuestra == NULL) { //xxxdebug perror("Null vecIndGruposMuestra...");
Eugenio Yolis
APNDICE 4 - PROGRAMACION
187
getchar(); getchar(); return ERROR_MEMORIA; } /* calculamos el valor actual, y decimos que el ganador es el grupo actual */ indGrupoGanador = indGrupoOrig; valorActual = ValorCriterioActual(agrup,vVecArchivos,nroElem,indGrupoOrig); incGanador = 0.0; /* evaluamos el movimiento a cada uno de los otros grupos */ //xxxdebug //printf(" increm:[%f];;;",valorActual); for (h=0; h < cantGruposMuestra; h++) { iGrupos = vecIndGruposMuestra[h]; if (iGrupos != indGrupoGanador) /* no evaluamos 2 veces el grupo original */ { valorAux = ValorCriterioAlternativa(agrup,vVecArchivos,nroElem,iGrupos,valorActual); if ((valorAux - valorActual) > incGanador) { /* este incremento va ganando por ahora */ indGrupoGanador = iGrupos; incGanador = (valorAux - valorActual); } //xxxdebug //printf("%f;;;",valorAux - valorActual); } } free((void*)vecIndGruposMuestra); //xxxdebug //printf("\n"); /* veamos si hubo un ganador */ if (indGrupoGanador != indGrupoOrig) { /* hay que mover el elemento */ codRet = MoverElementoyRecalcular(agrup,vVecArchivos,nroElem,indGrupoOrig,indGrupoGanador,true) ; if (codRet != OK) return codRet; cantCambios++; /* sumamos un cambio esta vuelta */ //xxxdebug //printf("KMRefinar::Cambio.Iter=%d Elem=%d;Orig=%d;Dest=%d\n",iIteraciones,nroElem,indGrupoOrig,indGrupoGanador); } } } cantCambiosTotal += cantCambios; //xxxdebug //printf("KMRefinar::FinIter=%d Cambios=%d\n",iIteraciones,cantCambios);
188
APNDICE 4 - PROGRAMACION
Eugenio Yolis
/* liberamos el vector de orden aleatorio */ free((void*)ordenProceso); /* si no hubo ningun cambio tenemos que parar */ if (cantCambios == 0) bParar = true; /* sumamos una iteracion mas y vemos si ya tenemos que parar */ iIteraciones++; if (iIteraciones >= cantIteraciones) bParar = true; } /* devolvemos la cantidad de iteraciones */ cantIteraciones = iIteraciones; //xxxdebug printf("KMRefinarLite::Fin TotalIter=%d TotalCambios=%d\n",iIteraciones,cantCambiosTotal);
return OK; } bool c_KMeans::NroGrupoEstaEnVectorIndices(uent nro, uent *vector,uent cantEntradas, c_Agrupamiento &agrup, uent &indGrupo) { /* busca si el numero de grupo "nro" tiene un indice que est dentro del vector "vector", que tiene "cantEntradas" entradas si est, en el parametro "indGrupo" devuelve el indice del grupo */ uent i; for (i=0; i < cantEntradas; i++) if (agrup.vecGrupos[vector[i]].nroGrupo == nro) { indGrupo = vector[i]; return true; } return false; } real c_KMeans::ValorCriterioActual(c_Agrupamiento &agrup, c_VecArchivo *vVecArchivos[], uent nroElemAnalisis, uent indGrupoAnalisis) { /* calcula el valor actual del criterio que se optimiza con el algoritmo en "nroElemAnalisis" recibe el nro de elemento que est siendo analizado para ver si se mueve a otro grupo (para algunos criterios va a hacer falta) en "indGrupoAnalisis" recibe el indice del grupo al cual pertenece el elemento que se est analizando (para algunos criterios va a hacer falta) */ /* antes que nada, veamos si el elemento es el ultimo que queda en el grupo. En ese caso, devolvemos el maximo valor, ya que no se deben eliminar grupos */
Eugenio Yolis
APNDICE 4 - PROGRAMACION
189
if (agrup.vecGrupos[indGrupoAnalisis].cantElementos <= 1) return MAX_VALOR_CRITERIO; real valorCriterio; real normaCent; switch (codCriterio) { case 1 : { c_VecArchivo *vecCent, *vecElem; real simil; /* este criterio es igual a la similitud entre el centroide del grupo y el elemento */ vecCent = agrup.vecGrupos[indGrupoAnalisis].vecCentroide; vecElem = vVecArchivos[nroElemAnalisis+1]; simil = vecCent->Multiplicar(*vecElem,false); normaCent = vecCent->CalcularNorma(false); valorCriterio = simil / normaCent; break; } default : { /* error : no estaba definido el criterio */ valorCriterio = 0.0; } } /* siempre tenemos que devolver algo menor que el maximo */ if (valorCriterio >= MAX_VALOR_CRITERIO) valorCriterio = MAX_VALOR_CRITERIO - MARGEN_CRITERIO; return valorCriterio; }
real c_KMeans::ValorCriterioAlternativa(c_Agrupamiento &agrup, c_VecArchivo *vVecArchivos[], uent nroElemAnalisis, uent indGrupoCandidato, real valCriterioActual) { /* calcula el valor del criterio para la alternativa de mover el elemento "nroElem" al grupo de indice "indGrupoCandidato" en "nroElemAnalisis" recibe el nro de elemento que est siendo analizado en "indGrupoCandidato" recibe el indice del grupo al cual se est evaluando mover el elemento en "valCriterioActual" recibe el valor actual del criterio (para algunos criterios puede hacer falta) */ real valorCriterio; real normaCent; switch (codCriterio) { case 1 : { c_VecArchivo *vecCent, *vecElem; real simil; /* este criterio es igual a la similitud entre
190
APNDICE 4 - PROGRAMACION
Eugenio Yolis
el centroide del grupo y el elemento */ vecCent = agrup.vecGrupos[indGrupoCandidato].vecCentroide; vecElem = vVecArchivos[nroElemAnalisis+1]; simil = vecCent->Multiplicar(*vecElem,false); normaCent = vecCent->CalcularNorma(false); valorCriterio = simil / normaCent; break; } default : { /* error : no estaba definido el criterio */ valorCriterio = 0.0; } } /* siempre tenemos que devolver algo menor que el maximo */ if (valorCriterio >= MAX_VALOR_CRITERIO) valorCriterio = MAX_VALOR_CRITERIO - MARGEN_CRITERIO; return valorCriterio; } uent c_KMeans::MoverElementoyRecalcular(c_Agrupamiento &agrup,c_VecArchivo *vVecArchivos[],uent nroElem,uent indGrupoOrig,uent indGrupoGanador, bool restarACentroide) { /* mueve el elemento "nroElem" del grupo con indice "indGrupoOrig" al grupo con indice "indGrupoGanador" recalcula todo lo que haga falta dentro del agrupamiento (ej : centroides) que sea necesario de acuerdo a cada criterio */ uent codRet; contMoverYRecalcular++; switch (codCriterio) { case 1 : { c_VecArchivo *vecCentOrig, *vecCentGanador, *vecElem; real unoSobre; uent cantElemOrig, cantElemGanador; /* recalculamos los centroides de los 2 grupos */ vecCentOrig = agrup.vecGrupos[indGrupoOrig].vecCentroide; vecCentGanador = agrup.vecGrupos[indGrupoGanador].vecCentroide; vecElem = vVecArchivos[nroElem+1]; cantElemOrig = agrup.vecGrupos[indGrupoOrig].cantElementos; cantElemGanador = agrup.vecGrupos[indGrupoGanador].cantElementos; /* al original le restamos el elemento que le sacamos */ /* primero lo multiplicamos por la cantidad de elementos anterior */ if (restarACentroide == true) { vecCentOrig->MultiplicarPorReal((real)cantElemOrig); codRet = vecCentOrig->Restar(*vecElem); if (codRet != OK)
Eugenio Yolis
APNDICE 4 - PROGRAMACION
191
return codRet; unoSobre = (real)1.0 / (real)(cantElemOrig - 1); vecCentOrig->MultiplicarPorReal(unoSobre); } /* al ganador le sumamos el elemento que le agregamos */ /* primero lo multiplicamos por la cantidad de elementos anterior */ vecCentGanador->MultiplicarPorReal((real)cantElemGanador); codRet = vecCentGanador->Sumar(*vecElem); if (codRet != OK) return codRet; unoSobre = (real)1.0 / (real)(cantElemGanador + 1); vecCentGanador->MultiplicarPorReal(unoSobre); /* movemos el elemento de un grupo al otro */ agrup.MoverElemento(nroElem,indGrupoGanador,indGrupoOrig); break; } default : { /* error : no estaba definido el criterio */ } }
return OK; } uent c_KMeans::BisectingKMeans(c_Agrupamiento* &agrup, uent nroGrupo, c_VecArchivo *vVecArchivos[], uent kBisect, bool refinar) /* Divide al grupo "nroGrupo" en k grupos usando el algoritmo bisecting kmeans (Steinbach et al, 2000) Se divide el grupo en "kBisect" grupos usando el algoritmo kmeans basico, luego se toma el grupo mas grande y se lo vuelve a dividir en "kBisect", etc Para que esto funcione, debe cumplirse que k = 1 + (n * (kBisect-1)) con "n" cualquier entero mayor a 0 Si refinar es "true", cuando termina, corre la fase de refinacion sobre el agrupamiento Devuelve OK o el error que corresponda */ { uent codRet; uent *vec2Ind, *vecIndices, indiceAux; uent kOriginal, cantCambiosTotal = 0; uent iCantGrupos, i, cantIter; uent nroADividir, cantElemMax; uent j, cantCandidatosKMeans = 5; /* cantidad de veces que se hace el KMeans basico */ real normaCent, simProm, maxSimProm; uent indMejor; c_Agrupamiento **vecAgrups; /* creamos un vector de punteros a los agrupamientos candidatos */ vecAgrups = (c_Agrupamiento**)malloc(cantCandidatosKMeans * sizeof(c_Agrupamiento*));
192
APNDICE 4 - PROGRAMACION
Eugenio Yolis
if (vecAgrups == NULL) return ERROR_MEMORIA; kOriginal = k; /* guardamos la variable de clase k */ k = kBisect; /* seteamos k = kBisect */ /* este vector va a contener los kBisect indices de los grupos que vamos a ir refinando */ vec2Ind = (uent*)malloc(k * SINT); if (vec2Ind == NULL) return ERROR_MEMORIA; /* en este vector vamos a tener los indices de los grupos que vamos generando */ vecIndices = (uent*)malloc(kOriginal * SINT); if (vecIndices == NULL) return ERROR_MEMORIA; iCantGrupos = 1; /* ahora tenemos 1 solo grupo */ vecIndices[0] = agrup->IndiceDeGrupo(nroGrupo,false); /* es el grupo original */ while (iCantGrupos < kOriginal) /* hasta que no tengamos la cantidad de grupos que queremos */ { /* buscamos el grupo que tenga la mayor cantidad de elementos */ cantElemMax = 0; for (i=0; i < agrup->cantGrupos; i++) { if (NroGrupoEstaEnVectorIndices(agrup>vecGrupos[i].nroGrupo,vecIndices,iCantGrupos,*agrup,indiceAux)) { if (agrup->vecGrupos[i].cantElementos > cantElemMax) { nroADividir = agrup->vecGrupos[i].nroGrupo; cantElemMax = agrup->vecGrupos[i].cantElementos; } } } /* vamos a buscar candidatos usando el kmeans basico */ /* creamos los candidatos */ maxSimProm = -1; /* inicializamos el maximo como negativo */ for (i=0; i < cantCandidatosKMeans; i++) { /* creamos un agrupamiento y lo hacemos igual al que tenemos hasta ahora */ vecAgrups[i] = new c_Agrupamiento(); if (vecAgrups[i] == NULL) return ERROR_MEMORIA; codRet = vecAgrups[i]->Duplicar(*agrup); if (codRet != OK) return codRet; /* dividimos el nro de grupo que tenia mas elementos */ codRet = FaseInicial(*(vecAgrups[i]),nroADividir,vVecArchivos,vec2Ind,false,0); if (codRet != OK) return codRet;
Eugenio Yolis
APNDICE 4 - PROGRAMACION
193
/* calculamos los centroides */ codRet = CalcularCentroides(*(vecAgrups[i]),vVecArchivos,k,vec2Ind); if (codRet != OK) return codRet; /* refinamos */ cantIter = 100; codRet = FaseRefinar(*(vecAgrups[i]),vVecArchivos,vec2Ind,true,cantIter,cantCambiosTotal); if (codRet != OK) return codRet; /* calculamos la similitud promedio de los nuevos grupos */ simProm = 0; for (j = 0; j < k; j++) { /* buscamos la norma del centroide */ normaCent = ((vecAgrups[i]>vecGrupos[vec2Ind[j]]).vecCentroide)->CalcularNorma(false); simProm += normaCent * normaCent; //xxxdebug printf("BisKM:NormaCent[%d,%d] = %f\n",i,j,normaCent * normaCent); } if (simProm > maxSimProm) { /* este es el mejor que tenemos hasta el momento */ maxSimProm = simProm; indMejor = i; } //xxxdebug printf("BisKM:SimProm[%d] = %f\n",i,simProm / k); //c_Agrup_Imprime::salidaCompacta = false; //c_Agrup_Imprime::ImprimirTodo(stdout,agrup,vVecArchivos,lLex,lTxt); //printf ("Otra Iter \n"); } //xxxdebug printf("BisKM:SimPromGanador[%d] = %f\n",indMejor,maxSimProm / k); /* nos quedamos con el mejor candidato y destruimos el resto */ for (i=0; i < cantCandidatosKMeans; i++) { if (i!=indMejor) delete(vecAgrups[i]); } delete agrup; agrup = vecAgrups[indMejor]; /* ingresamos los nuevos grupos en el vector */ for (i=1; i < k; i++) vecIndices[iCantGrupos + i - 1] = vec2Ind[i]; iCantGrupos += k - 1; } /* restauramos el valor de k */ k = kOriginal;
194
APNDICE 4 - PROGRAMACION
Eugenio Yolis
/* veamos si hay que refinar */ if (refinar) { cantIter = 100; FaseRefinar(*agrup,vVecArchivos,vecIndices,true,cantIter,cantCambiosTotal); } /* liberamos los vectores que creamos */ free((void*)vecIndices); free((void*)vec2Ind); free((void*)vecAgrups); return OK; }
Eugenio Yolis
APNDICE 4 - PROGRAMACION
195
A4.2.11 ClsGenetico.h
/* Clase que implementa las funciones del algoritmo genetico */ #ifndef __clsGenetico__ #define __clsGenetico__ #include <malloc.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include "def.h" #include "sis.h" #include "vecArchivos.h" #include "clsAgrupamiento.h" #include "clsKMeans.h" //xxxdebug #include "skipl.h" #include "clsAgrupImprime.h" typedef struct _t_RegConfigGenetico { FILE *fpSalidaDebug; /* puntero a un archivo al que se enva la salida de depuracion */ uent generacionesMaximo; /* maximo numero de generaciones */ uent poblacionTamanio; /* tamao de la poblacion */ uent poblacionTamanioDeseado; /* el tamao de la poblacion tiene que llegar a ser este */ uent torneoTamanio; /* tamao del torneo */ real torneoProbMejor; /* probabilidad que tiene de ser elegido el mejor del torneo */ uent fitnessCriterio; /* criterio para calcular el fitness 1 : similitud promedio de los elementos de cada grupo 2 : promedio de las normas de los centroides 3 : .. (no definido todavia) */ uent cruzaOperador; /* operador de cruza a utilizar 1 : pasar un grupo del padre al hijo 2 : ... (no definido todavia) */ real cruzaPasaGrupoProbMejor; /* probabilidad de que la cruza que pasa grupos pase el de mayor similitud promedio */ real cruzaPasaGrupoProbMasElemComun; /* probabilidad de que el grupo destino sea el que tiene mas elementos en comun */ real cruzaPasaGrupoProbMasSimilar; /* probabilidad de que el grupo destino sea el mas similar */ real cruzaPasaGrupoProbMenorSimilProm; /* probabilidad de que el grupo destino sea el que tiene menor similitud promedio */ real cruzaPasaGrupoProbAzar; /* probabilidad de que el grupo destino se elija por azar */
196
APNDICE 4 - PROGRAMACION
Eugenio Yolis
real cruzaPasaGrupoProbMejorDestino; /* probabilidad de el elemento que se saca del grupo destino pase al grupo mas similar */ uent k; /* cantidad de grupos */ uent mutacionRefinarKMCantIter; /* cantidad de iteraciones de refinamiento en la mutacion que refina */ real mutacionRefinarKMProb; /* probabilidad de que se aplique la mutacion que refina */ uent generacionInicialModo; /* forma de generar la poblacion inicial : 1 : al azar 2 : con la fase inicial (lite) del kmeans 3 : fase inicial del kmeans pero solo log k grupos */ real mutacionJoinProb; /* probabilidad de que se aplique la mutacion que junta 2 grupos */ real mutacionJoinProbMasSimilar; /* probabilidad de que el grupo destino sea el mas similar */ real mutacionJoinProbMenorSimilProm; /* probabilidad de que el grupo origen sea el que tiene menor similitud promedio */ real mutacionJoinProbMasChico; /* probabilidad de que el grupo origen sea el mas chico */ real mutacionJoinProbAzar; /* probabilidad de que los grupos se elijan por azar */ real mutacionSplitProb; /* probabilidad de que se aplique la mutacion que separa 1 grupo */ real mutacionSplitProbMasGrande; /* probabilidad de que el grupo sea el que tiene ms elementos */ real mutacionSplitProbMenorSimilProm; /* probabilidad de que el grupo origen sea el que tiene menor similitud promedio */ real mutacionSplitProbAzar; /* probabilidad de que los grupos se elijan por azar */ uent mutacionSplitCantMuestras; /* cantidad de muestras a tomar para buscar los elementos mas distantes del grupo */ real mutacionRefinarSelectivoProb; /* probabilidad de que se aplique la mutacion de refinacion selectiva */ } tRegConfigGenetico; typedef struct _t_Cromosoma { c_Agrupamiento *agrup; real fitness; bool disponible; ent ultimoJoin; //indice del ultimo grupo en el cual se hizo un join (o -1) } tCromosoma; class c_Genetico { private: uent AsignarFormaElegirGrupoDestino(); uent AsignarFormaElegirGrupoSplit(); tCromosoma **poblacion; real FitnessDeCromosoma(tCromosoma &cromosoma); uent privCruzaPasaGrupo(tCromosoma *padre1, tCromosoma *padre2, tCromosoma **hijo1, c_VecArchivo *vVecArchivos[]); void ActualizarParametros(uent genActual,uent genLimite); FILE *DebugFP(); public: uent ElegirPorTorneo(uent &indElegido, bool invertido); tRegConfigGenetico RegConfig; c_Genetico(); ~c_Genetico();
Eugenio Yolis
APNDICE 4 - PROGRAMACION
197
uent GenerarPoblacionInicial(uent cantElemAAgrupar, c_VecArchivo *vVecArchivos[]); uent Evolucionar(c_VecArchivo *vVecArchivos[],bool generacionesFijas, uent &cantGeneraciones); uent DevolverMejorSolucion(c_Agrupamiento **solucion); uent CruzaPasaGrupo(tCromosoma *padre1, tCromosoma *padre2, tCromosoma **hijo1, tCromosoma **hijo2, c_VecArchivo *vVecArchivos[]); uent OperadorCruza(c_VecArchivo *vVecArchivos[]); uent UbicarEnPoblacion(tCromosoma *hijo1, tCromosoma *hijo2); uent MutacionRefinarKM(tCromosoma *cromosoma, c_VecArchivo *vVecArchivos[]); uent MutacionJoin(tCromosoma *cromosoma, c_VecArchivo *vVecArchivos[]); uent MutacionSplit(tCromosoma *cromosoma, c_VecArchivo *vVecArchivos[]); uent MutacionRefinarSelectivo(tCromosoma *cromosoma, c_VecArchivo *vVecArchivos[]); };
#endif
198
APNDICE 4 - PROGRAMACION
Eugenio Yolis
A4.2.12 ClsGenetico.cpp
#include "clsGenetico.h" c_Genetico::c_Genetico() /* constructor */ { /* seteos por defecto */ RegConfig.generacionesMaximo = 200; RegConfig.k = 5; /* por defecto k=5 */ RegConfig.generacionInicialModo = 3; RegConfig.fitnessCriterio = 1; RegConfig.poblacionTamanio = 12; RegConfig.poblacionTamanioDeseado = RegConfig.poblacionTamanio; RegConfig.torneoTamanio = 2; RegConfig.torneoProbMejor = (real)0.7; RegConfig.cruzaOperador = 1; RegConfig.cruzaPasaGrupoProbMejor = (real)0.7; RegConfig.cruzaPasaGrupoProbMejorDestino = (real)0.95; /* las siguientes 4 probabilidades deben sumar 1 */ RegConfig.cruzaPasaGrupoProbMasElemComun = (real)0.4; RegConfig.cruzaPasaGrupoProbMasSimilar = (real)0.56; RegConfig.cruzaPasaGrupoProbMenorSimilProm = (real)0.02; RegConfig.cruzaPasaGrupoProbAzar = (real)0.02; /* */ RegConfig.mutacionRefinarKMCantIter = 1; RegConfig.mutacionRefinarKMProb = (real)0.3; RegConfig.fpSalidaDebug = NULL; RegConfig.mutacionJoinProb = (real)0.1; /* las siguientes 3 probabilidades deben sumar 1 */ RegConfig.mutacionJoinProbAzar = (real)0.00; RegConfig.mutacionJoinProbMenorSimilProm = (real)0.30; RegConfig.mutacionJoinProbMasChico = (real)0.70; /* */ RegConfig.mutacionJoinProbMasSimilar = (real)0.95; RegConfig.mutacionSplitProb = (real)0.1; /* las siguientes 3 probabilidades deben sumar 1 */ RegConfig.mutacionSplitProbAzar = (real)0.05; RegConfig.mutacionSplitProbMasGrande = (real)0.9; RegConfig.mutacionSplitProbMenorSimilProm = (real)0.05; RegConfig.mutacionSplitCantMuestras = 6; /* */ RegConfig.mutacionRefinarSelectivoProb = (real)0.0; } void c_Genetico::ActualizarParametros(uent genActual,uent genLimite) /* actualiza los parmetros de RegConfig de acuerdo a la fase del algoritmo en que nos encontramos genActual es el nmero de generacion actual genLimite es el lmite de generaciones */ { real pctCompleto; pctCompleto = (real)((real)genActual / (real)genLimite);
Eugenio Yolis
APNDICE 4 - PROGRAMACION
199
/* RegConfig.torneoProbMejor = (real)(0.6 + (0.2 * pctCompleto)); RegConfig.cruzaPasaGrupoProbMejor = (real)(0.60 + (0.3 * pctCompleto)); RegConfig.mutacionRefinarKMProb = (real)(0.4 - (0.35 * sin((PI/2)*pctCompleto))); */ if (pctCompleto == 0.0) { RegConfig.poblacionTamanioDeseado = RegConfig.poblacionTamanioDeseado; } if (pctCompleto < 0.2) /* 0 a 20% */ { RegConfig.torneoProbMejor = (real)(0.75); RegConfig.cruzaPasaGrupoProbMejor = (real)(0.8); RegConfig.mutacionRefinarKMProb = (real)(0.1); RegConfig.mutacionJoinProb = (real)0.1; RegConfig.mutacionSplitProb = (real)0.1; RegConfig.torneoTamanio = 2; } else if (pctCompleto < 0.4) /* 20 a 40% */ { RegConfig.torneoProbMejor = (real)(0.75); RegConfig.cruzaPasaGrupoProbMejor = (real)(0.8); RegConfig.mutacionRefinarKMProb = (real)(0.1); RegConfig.mutacionJoinProb = (real)0.1; RegConfig.mutacionSplitProb = (real)0.1; RegConfig.torneoTamanio = 3; } else if (pctCompleto < 0.8) /* 40 a 80% */ { RegConfig.poblacionTamanioDeseado = 10; RegConfig.torneoProbMejor = (real)(0.8); RegConfig.cruzaPasaGrupoProbMejor = (real)(0.8); RegConfig.mutacionRefinarKMProb = (real)(0.1); RegConfig.mutacionJoinProb = (real)0.15; RegConfig.mutacionSplitProb = (real)0.1; RegConfig.torneoTamanio = 3; RegConfig.mutacionRefinarSelectivoProb = (real)0.1; } else if (pctCompleto < 0.9) /* 80 a 90% */ { RegConfig.torneoProbMejor = (real)(0.85); RegConfig.cruzaPasaGrupoProbMejor = (real)(0.9); RegConfig.mutacionRefinarKMProb = (real)(0.25); RegConfig.torneoTamanio = 3; RegConfig.mutacionJoinProb = (real)0.05; RegConfig.mutacionSplitProb = (real)0.05; RegConfig.mutacionRefinarSelectivoProb = (real)0.3; } else /* 90 a 100% */ { RegConfig.mutacionRefinarSelectivoProb = (real)0.0; } } FILE* c_Genetico::DebugFP() { return (RegConfig.fpSalidaDebug ? RegConfig.fpSalidaDebug : stdout); } c_Genetico::~c_Genetico() /* destructor */ { uent i; for (i=0; i < RegConfig.poblacionTamanio; i++) { if (poblacion[i] != NULL) {
200
APNDICE 4 - PROGRAMACION
Eugenio Yolis
if (poblacion[i]->agrup != NULL) { delete (poblacion[i]->agrup); } free((void*)poblacion[i]); } } free((void*)poblacion); } real c_Genetico::FitnessDeCromosoma(tCromosoma &cromosoma) /* calcula el fitness del cromosoma "cromosoma" */ { c_Agrupamiento *agrup; uent iGrupos, cantGrupos, cantElemGrupo; real simSuma, normaCent, penalizacion; c_VecArchivo *vecCent; switch (RegConfig.fitnessCriterio) { case 1: /* este criterio evalua el promedio de similitudes entre los elementos de cada grupo */ simSuma = (real)0.0; /* tomamos el agrupamiento del cromosoma */ agrup = cromosoma.agrup; cantGrupos = agrup->cantGrupos; /* vamos recorriendo los grupos */ for (iGrupos = 0; iGrupos < cantGrupos; iGrupos++) { /* tomamos el centroide del grupo y la cantidad de elementos */ vecCent = agrup->vecGrupos[iGrupos].vecCentroide; cantElemGrupo = agrup->vecGrupos[iGrupos].cantElementos; /* calculamos la norma del centroide al cuadrado */ normaCent = vecCent->CalcularNorma(true); normaCent *= normaCent; /* sumamos la norma multiplicada por la cantidad de elementos del grupo */ simSuma += (real)(cantElemGrupo * normaCent); } /* penalizamos a los que se apartan de k grupos */ //penalizacion = (real)abs(RegConfig.k - agrup->cantGrupos)/(real)RegConfig.k; //penalizacion = (real)1.0 - penalizacion; penalizacion = (real)1.0; /* el criterio a devolver es la suma dividida la cantidad total de elementos */ return ((simSuma / agrup->cantElementos) * penalizacion); break; case 2: /* este criterio evalua el promedio de la norma de los centroides */ simSuma = (real)0.0; /* tomamos el agrupamiento del cromosoma */ agrup = cromosoma.agrup; cantGrupos = agrup->cantGrupos; /* vamos recorriendo los grupos */ for (iGrupos = 0; iGrupos < cantGrupos; iGrupos++) { /* tomamos el centroide del grupo */
Eugenio Yolis
APNDICE 4 - PROGRAMACION
201
vecCent = agrup->vecGrupos[iGrupos].vecCentroide; /* calculamos la norma del centroide al cuadrado */ normaCent = vecCent->CalcularNorma(true); normaCent *= normaCent; /* sumamos la norma */ simSuma += (real)(normaCent); } /* el criterio a devolver es la suma dividida la cantidad total de grupos */ return ((simSuma / cantGrupos)); break; default: /* criterio desconocido ... */ return((real)0.0); break; } }
uent c_Genetico::GenerarPoblacionInicial(uent cantElemAAgrupar, c_VecArchivo *vVecArchivos[]) /* inicializa la poblacion del algoritmo genetico eso incluye alocar memoria para los cromosomas, agrupar al azar los elementos en el agrupamiento de cada cromosoma, calcular los centroides para el agrupamiento de cada cromosoma y calcular el fitness de cada cromosoma */ { uent i, j, codRet; uent *vecIndGruposAux; /* inicializamos el vector de grupos auxiliar (lo necesita la funcion que calcula los centroides */ vecIndGruposAux = (uent*)malloc(RegConfig.k * SINT); if (vecIndGruposAux == NULL) return ERROR_MEMORIA; /* creamos el vector de punteros a cromosomas */ poblacion = (tCromosoma**)malloc(RegConfig.poblacionTamanio * sizeof(tCromosoma*)); if (poblacion == NULL) return ERROR_MEMORIA; /* inicializamos cada puntero a cromosoma */ for (i = 0; i < RegConfig.poblacionTamanio; i++) { /* creamos un cromosoma */ poblacion[i] = (tCromosoma*)malloc(sizeof(tCromosoma)); if (poblacion[i] == NULL) return ERROR_MEMORIA; /* creamos el agrupamiento del cromosoma */ poblacion[i]->agrup = new c_Agrupamiento; if (poblacion[i]->agrup == NULL) return ERROR_MEMORIA; /* inicializamos el agrupamiento */ codRet = poblacion[i]->agrup->Inicializar(cantElemAAgrupar); if (codRet != OK) return codRet; switch (RegConfig.generacionInicialModo) {
202
APNDICE 4 - PROGRAMACION
Eugenio Yolis
case 1: /* lo agrupamos al azar */ codRet = poblacion[i]->agrup>AgruparAlAzar(RegConfig.k,RegConfig.k); if (codRet != OK) return codRet; break; case 2: /* lo inicializamos con la fase inicial (lite) del kmeans */ codRet = poblacion[i]->agrup->AgruparAlAzar(1,1); if (codRet != OK) return codRet; c_KMeans::k = RegConfig.k; codRet = c_KMeans::FaseInicialLite(*(poblacion[i]>agrup),1,vVecArchivos,vecIndGruposAux,false,0); if (codRet != OK) return codRet; break; case 3: /* fase inicial, pero solamente log k grupos */ codRet = poblacion[i]->agrup->AgruparAlAzar(1,1); if (codRet != OK) return codRet; c_KMeans::k = (uent)(log(RegConfig.k)/log(2)); codRet = c_KMeans::FaseInicial(*(poblacion[i]>agrup),1,vVecArchivos,vecIndGruposAux,false,0); if (codRet != OK) return codRet; break; } /* calculamos los centroides */ for (j=0; j<RegConfig.k; j++) vecIndGruposAux[j] = j; codRet = c_KMeans::CalcularCentroides(*(poblacion[i]>agrup),vVecArchivos,RegConfig.k,vecIndGruposAux); if (codRet != OK) return codRet; /* le asociamos el fitness */ poblacion[i]->fitness = FitnessDeCromosoma(*(poblacion[i])); /* esta disponible para ser seleccionado */ poblacion[i]->disponible = true; /* no hubo un join */ poblacion[i]->ultimoJoin = -1; fprintf(DebugFP(),"GenInic : %d; Fitness : %f \n",i,poblacion[i]->fitness); } free((void*)vecIndGruposAux); return OK; }
uent c_Genetico::DevolverMejorSolucion(c_Agrupamiento **solucion) /* devuelve un puntero al agrupamiento del cromosoma que tiene fitness mas alto */ { uent iPob, iMax; real fitMax;
Eugenio Yolis
APNDICE 4 - PROGRAMACION
203
iMax = 0; fitMax = (real)-1.0; for (iPob = 0; iPob < RegConfig.poblacionTamanio; iPob++) { if (poblacion[iPob]->fitness > fitMax) { fitMax = poblacion[iPob]->fitness; iMax = iPob; } } *solucion = poblacion[iMax]->agrup; return OK; } uent c_Genetico::ElegirPorTorneo(uent &indElegido, bool invertido) /* elige un cromosoma mediante el mtodo del torneo los parametros son las variables de configuracion: - torneoTamanio : cantidad de cromosomas que se examinan - torneoProbMejor : probabilidad de que se seleccione al mejor si "invertido" es true, se busca al reves (intentando elegir al peor), esto se usa para elegir a quien se reemplaza en "indElegido", devuelve el numero del cromosoma seleccionado */ { uent *elemAzar; uent *ordenTorneo; uent iElemTorneo,iElem,j; bool bSalir; if (invertido == false) fprintf(DebugFP(),"Torneo : "); else fprintf(DebugFP(),"Torneo invertido : "); /* "ordenTorneo" es un vector de tamao "torneoTamanio" */ ordenTorneo = (uent*)malloc(RegConfig.torneoTamanio * SINT); /* en "elemAzar" generamos un vector de numeros de cromosoma ordenados al azar. Lo hacemos un poco mas grande que el tamao del torneo por las dudas de que alguno est marcado como no disponible */ elemAzar = kNumerosRandom(RegConfig.torneoTamanio + 3,0,RegConfig.poblacionTamanio - 1,false); if (elemAzar == NULL) return ERROR_MEMORIA; /* iElem avanza mas rapido que iElemTorneo cuando hay cromosomas no disponibles */ iElem = 0; for (iElemTorneo=0;iElemTorneo<RegConfig.torneoTamanio;iElemTorneo++) { /* iElem saltea los cromosomas no disponibles */ while(poblacion[elemAzar[iElem]]->disponible == false) iElem++;
204
APNDICE 4 - PROGRAMACION
Eugenio Yolis
fprintf(DebugFP(),"(%d) %f ; ",elemAzar[iElem],poblacion[elemAzar[iElem]]>fitness); /* ahora veamos en que posicion del vector "ordenTorneo" tiene que ir */ /* empezamos a evaluar por el ultimo del vector (el de mas fitness) */ j = iElemTorneo; while (j > 0) { /* veamos si el que acabamos de elegir tiene mas fitness */ if (poblacion[elemAzar[iElem]]->fitness < poblacion[ordenTorneo[j-1]]>fitness) { /* movemos el elemento del vector hacia arriba */ ordenTorneo[j] = ordenTorneo[j-1]; } else { break; /* salimos del while */ } j--; } /* el elemento va en la posicion j */ ordenTorneo[j] = elemAzar[iElem]; iElem++; } fprintf(DebugFP()," --> "); /* ya tenemos los elementos en el vector "ordenTorneo" ordenados por fitness (primero el de menor fitness) */ /* ahora elegimos al elemento con la probabilidad que corresponde */ bSalir = false; j = 0; while ((j < RegConfig.torneoTamanio) && (bSalir == false)) { if (TirarMonedaCargada(RegConfig.torneoProbMejor)) { bSalir = true; } else { fprintf(DebugFP()," salteo - "); j++; } } if (bSalir == false) /* j se pas 1 */ j--; /* de acuerdo al valor de "invertido" devolvemos el que corresponde */ if (invertido == true) indElegido = ordenTorneo[j]; else indElegido = ordenTorneo[RegConfig.torneoTamanio - 1 - j]; fprintf(DebugFP(),"[%f]\n",poblacion[indElegido]->fitness); free((void*)elemAzar); free((void*)ordenTorneo); return (0); }
Eugenio Yolis
APNDICE 4 - PROGRAMACION
205
uent c_Genetico::CruzaPasaGrupo(tCromosoma *padre1, tCromosoma *padre2, tCromosoma **hijo1, tCromosoma **hijo2, c_VecArchivo *vVecArchivos[]) /* Operador de cruza. Recibe punteros a los 2 padres. Crea 2 cromosomas nuevos (que devuelve en los 2 punteros a los hijos) Para generar el hijo 1 hace lo siguiente : - crea el agrupamiento para el hijo 1 igual al del padre 2 - busca en el padre 1 un grupo para pasar al hijo. Con cierta probabilidad el grupo a pasar es el que tiene mejor promedio de similitud entre sus elementos - busca en el hijo 1 (que por ahora es igual al padre 2), el grupo que tenga mas elementos en comun con el grupo que eligio para pasarle - saca de ese grupo los elementos que no estan en el grupo que le va a pasar, y agrega a ese grupo los elementos que le faltan - si algun grupo del hijo se queda sin elementos, lo borra Para generar el hijo 2 es el mismo procedimiento pero tomando los padres al revs */ { uent codRet; /* generamos el hijo 1 */ fprintf(DebugFP(),"Cruza PasaGrup 1 : fitness padre1(%d) = %f ; fitness padre2(%d) = %f\n",padre1->agrup->cantGrupos,padre1->fitness,padre2->agrup->cantGrupos,padre2>fitness); codRet = privCruzaPasaGrupo(padre1,padre2,hijo1,vVecArchivos); if (codRet != OK) return codRet; /* generamos el hijo 2 */ fprintf(DebugFP(),"Cruza PasaGrup 2 : fitness padre1 = %f ; fitness padre2 = %f\n",padre2->fitness,padre1->fitness); codRet = privCruzaPasaGrupo(padre2,padre1,hijo2,vVecArchivos); return codRet; return OK; } uent c_Genetico::AsignarFormaElegirGrupoDestino() /* calcula la forma de elegir el grupo destino de acuerdo a las probabilidades (usado por el operador de cruza) Devuelve : 1 = Mas elementos en comun 2 = Mas similar 3 = Menor similitud promedio 4 = Al Azar */ { real totalProbRestante; totalProbRestante = (real)1.0; if (TirarMonedaCargada(RegConfig.cruzaPasaGrupoProbMasElemComun * (real)(1.0 / totalProbRestante))) { return 1; } totalProbRestante -= RegConfig.cruzaPasaGrupoProbMasElemComun; if (TirarMonedaCargada(RegConfig.cruzaPasaGrupoProbMasSimilar * (real)(1.0 / totalProbRestante))) { return 2;
206
APNDICE 4 - PROGRAMACION
Eugenio Yolis
} totalProbRestante -= RegConfig.cruzaPasaGrupoProbMasSimilar; if (TirarMonedaCargada(RegConfig.cruzaPasaGrupoProbMenorSimilProm * (real)(1.0 / totalProbRestante))) { return 3; } /* si llegamos hasta aca, es al azar */ return 4; } uent c_Genetico::privCruzaPasaGrupo(tCromosoma *padre1, tCromosoma *padre2, tCromosoma **hijo1, c_VecArchivo *vVecArchivos[]) /* implementa el operador de cruza "CruzaPasaGrupo", para generar uno de los dos hijos. Para generar el otro, se deben pasar los padres en orden inverso */ { uent codRet; c_Agrupamiento *agrupHijo, *agrupPadre; uent indGrupoPasar, indGrupoDestino, i, nroGrupoPasar, nroGrupoDestino; uent nroGrupoElemHijo, maxElemComun, cantGruposHijo, indGrupoAux; real maxSimProm, simProm, maxSimPromDest; uent *vecNroElemComun, j; real valorActual, valorAlternativa; uent formaElegirGrupoDestino, h; c_VecArchivo *vecCent1,*vecCent2; real vMaxSimProm[3]; /* para buscar los 2 grupos mas similares en el segundo padre */ uent vIndGrupoDestino[3], vNroGrupoDestino[3]; /* creamos el cromosoma */ *hijo1 = (tCromosoma*)malloc(sizeof(tCromosoma)); if (*hijo1 == NULL) return ERROR_MEMORIA; /* creamos el agrupamiento del cromosoma */ (*hijo1)->agrup = new c_Agrupamiento(); if ((*hijo1)->agrup == NULL) return ERROR_MEMORIA; agrupHijo = (*hijo1)->agrup; /* hacemos el agrupamiento del hijo igual al del padre 2 */ codRet = agrupHijo->Duplicar(*(padre2->agrup)); if (codRet != OK) return codRet; /* le tenemos que pasar un grupo del padre 1 */ agrupPadre = padre1->agrup; /* veamos si tenemos que pasar el mejor grupo */ if (TirarMonedaCargada(RegConfig.cruzaPasaGrupoProbMejor)) { /* buscamos el grupo del padre con mejor similitud promedio */ maxSimProm = (real)-1.0; for (i=0; i < agrupPadre->cantGrupos; i++) { simProm = agrupPadre->vecGrupos[i].vecCentroide>CalcularNorma(false); if (simProm > maxSimProm) { indGrupoPasar = i; maxSimProm = simProm;
Eugenio Yolis
APNDICE 4 - PROGRAMACION
207
} } } else { /* el grupo a pasar se elige al azar */ indGrupoPasar = RANDOM(agrupPadre->cantGrupos); maxSimProm = 0; } nroGrupoPasar = agrupPadre->vecGrupos[indGrupoPasar].nroGrupo; /* buscamos los 2 grupos mas similares del otro padre */ for (i=0; i < 2; i++) { vMaxSimProm[i] = (real)-1.0; vIndGrupoDestino[i] = 0; } vecCent1 = agrupPadre->vecGrupos[indGrupoPasar].vecCentroide; for (i=0; i < agrupHijo->cantGrupos; i++) { vecCent2 = agrupHijo->vecGrupos[i].vecCentroide; simProm = vecCent1->Multiplicar(*vecCent2,false); j=0; while ((j<2) && (simProm > vMaxSimProm[j])) { vMaxSimProm[j] = vMaxSimProm[j+1]; vIndGrupoDestino[j] = vIndGrupoDestino[j+1]; j++; } if (j > 0) /* entra en el vector, en la posicion j-1 */ { vMaxSimProm[j-1] = simProm; vIndGrupoDestino[j-1] = i; } } for (i=0; i<2; i++) { vNroGrupoDestino[i] = agrupHijo->vecGrupos[vIndGrupoDestino[i]].nroGrupo; } /* ahora elegimos el grupo destino */ formaElegirGrupoDestino = AsignarFormaElegirGrupoDestino(); switch (formaElegirGrupoDestino) { case 1: /* mas elementos en comun */ /* creamos un vector para contar los elementos en comun de cada grupo */ vecNroElemComun = (uent*)malloc(agrupHijo->cantGrupos * SINT); if (vecNroElemComun == NULL) return ERROR_MEMORIA; for (i=0; i < agrupHijo->cantGrupos; i++) { vecNroElemComun[i] = 0; } /* buscamos en el hijo el grupo con mas elementos en comun */ for (i=0; i < agrupPadre->cantElementos; i++) { /* si el elemento es del grupo a pasar */ if (agrupPadre->vecElementos[i] == nroGrupoPasar)
208
APNDICE 4 - PROGRAMACION
Eugenio Yolis
{ /* sumamos uno al grupo del hijo que tiene ese elemento */ nroGrupoElemHijo = agrupHijo->vecElementos[i]; vecNroElemComun[agrupHijo>IndiceDeGrupo(nroGrupoElemHijo,false)]++; } } /* buscamos la mayor entrada en el vector */ maxElemComun = 0; for (i=0; i < agrupHijo->cantGrupos; i++) { if (vecNroElemComun[i] > maxElemComun) { maxElemComun = vecNroElemComun[i]; indGrupoDestino = i; } } free((void*)vecNroElemComun); maxSimPromDest = (real)maxElemComun; break; case 2: /* mas similar */ maxSimPromDest = vMaxSimProm[1]; indGrupoDestino = vIndGrupoDestino[1]; break; case 3: /* menor similitud promedio */ maxSimPromDest = (real)-10000.0; for (i=0; i < agrupHijo->cantGrupos; i++) { vecCent2 = agrupHijo->vecGrupos[i].vecCentroide; simProm = (real)-1.0 * vecCent2->CalcularNorma(false); if (simProm > maxSimPromDest) { maxSimPromDest = simProm; indGrupoDestino = i; } } break; case 4: /* al azar */ maxSimPromDest = (real)0.0; indGrupoDestino = RANDOM(agrupHijo->cantGrupos); break; } nroGrupoDestino = agrupHijo->vecGrupos[indGrupoDestino].nroGrupo; fprintf(DebugFP()," Grupos : fuente=(%d) [%d] %f, destino=(%d) [%d] Sim : %f\n",nroGrupoPasar,agrupPadre>vecGrupos[indGrupoPasar].cantElementos,maxSimProm,nroGrupoDestino,agrupHijo>vecGrupos[indGrupoDestino].cantElementos,maxSimPromDest); /* ahora reacomodamos los elementos para que el grupo pase al hijo */ for (i=0; i < agrupPadre->cantElementos; i++) { if (agrupPadre->vecElementos[i] == nroGrupoPasar) { /* si en el hijo el elemento no est en el grupo destino, hay que agregarlo */ if (agrupHijo->vecElementos[i] != nroGrupoDestino) {
Eugenio Yolis
APNDICE 4 - PROGRAMACION
209
/* guardamos la cantidad actual de grupos del hijo para saber si cambia */ cantGruposHijo = agrupHijo->cantGrupos; /* pasamos el elemento al grupo destino */ indGrupoAux = agrupHijo->IndiceDeGrupo(agrupHijo>vecElementos[i],false); codRet = c_KMeans::MoverElementoyRecalcular(*agrupHijo,vVecArchivos,i,indGrupoAux,indGrupoDesti no,true); if (codRet != OK) return codRet; /* veamos si cambio la cantidad de grupos */ if (cantGruposHijo != agrupHijo->cantGrupos) { /* tomamos el nuevo indice del grupo */ indGrupoDestino = agrupHijo>IndiceDeGrupo(nroGrupoDestino,true); for (h=0; h<2; h++) vIndGrupoDestino[h] = agrupHijo>IndiceDeGrupo(vNroGrupoDestino[h],true); } } } else { /* si en el hijo el elemento est en el grupo destino, hay que sacarlo */ if (agrupHijo->vecElementos[i] == nroGrupoDestino) { /* veamos si tenemos que buscar el mejor grupo */ if (TirarMonedaCargada(RegConfig.cruzaPasaGrupoProbMejorDestino)) { /* hay que buscar el mejor grupo (solo entre los 2 mas similares) */ valorActual = c_KMeans::ValorCriterioActual(*agrupHijo,vVecArchivos,i,indGrupoDestino); indGrupoAux = indGrupoDestino; for (h=0; h < 2; h++) { j = vIndGrupoDestino[h]; if (j != indGrupoDestino) /* no evaluamos 2 veces el mismo */ { valorAlternativa = c_KMeans::ValorCriterioAlternativa(*agrupHijo,vVecArchivos,i,j,valorActual); if (valorAlternativa > valorActual) { valorActual = valorAlternativa; indGrupoAux = j; } } } } else { indGrupoAux = RANDOM(agrupHijo->cantGrupos); }
210
APNDICE 4 - PROGRAMACION
Eugenio Yolis
/* lo pasamos al otro grupo */ if (indGrupoAux != indGrupoDestino) { cantGruposHijo = agrupHijo->cantGrupos; /* para ver si cambia la cantidad de grupos */ codRet = c_KMeans::MoverElementoyRecalcular(*agrupHijo,vVecArchivos,i,indGrupoDestino,indGrupoA ux,true); if (codRet != OK) return (codRet); if (cantGruposHijo != agrupHijo->cantGrupos) { /* buscamos los nuevos indices */ indGrupoDestino = agrupHijo>IndiceDeGrupo(nroGrupoDestino,true); for (h=0; h<2; h++) vIndGrupoDestino[h] = agrupHijo>IndiceDeGrupo(vNroGrupoDestino[h],true); } } } } } return OK; } uent c_Genetico::OperadorCruza(c_VecArchivo *vVecArchivos[]) /* elige 2 cromosomas mediante el metodo del torneo los cruza generando 2 hijos elige 2 cromosomas mediante el metodo del torneo para ser reemplazados los reemplaza por los 2 hijos generados */ { tCromosoma *hijo1, *hijo2; uent indPadre1, indPadre2; uent codRet; /* elegimos los padres */ codRet = ElegirPorTorneo(indPadre1,false); if (codRet != OK) return (codRet); poblacion[indPadre1]->disponible = false; /* lo marcamos para no elegirlo de nuevo */ codRet = ElegirPorTorneo(indPadre2,false); if (codRet != OK) return (codRet); /* desmarcamos el padre 1 */ poblacion[indPadre1]->disponible = true; if (RegConfig.cruzaOperador == 1) { codRet = CruzaPasaGrupo(poblacion[indPadre1],poblacion[indPadre2],&hijo1,&hijo2,vVecArchivos); if (codRet != OK) return (codRet); } else { /* ... no definido aun */
Eugenio Yolis
APNDICE 4 - PROGRAMACION
211
} hijo1->ultimoJoin = -1; hijo2->ultimoJoin = -1; /* ahora calculamos el fitness del hijo 1 */ hijo1->fitness = FitnessDeCromosoma(*hijo1); /* ahora calculamos el fitness del hijo 2 */ hijo2->fitness = FitnessDeCromosoma(*hijo2); fprintf(DebugFP(),"Hijo 1 = %f ; Hijo 2 = %f\n",hijo1->fitness,hijo2->fitness); /* veamos si tenemos que mutar (operador split) al hijo 1 */ if ((hijo1->agrup->cantGrupos < RegConfig.k) || (TirarMonedaCargada(RegConfig.mutacionSplitProb))) { fprintf(DebugFP(),"MutarSplit 1 : "); codRet = MutacionSplit(hijo1,vVecArchivos); if (codRet != OK) return (codRet); } /* veamos si tenemos que mutar (operador split) al hijo 2 */ if ((hijo2->agrup->cantGrupos < RegConfig.k) || (TirarMonedaCargada(RegConfig.mutacionSplitProb))) { fprintf(DebugFP(),"MutarSplit 2 : "); codRet = MutacionSplit(hijo2,vVecArchivos); if (codRet != OK) return (codRet); } /* veamos si tenemos que mutar (operador join) al hijo 1 */ if ((hijo1->agrup->cantGrupos > RegConfig.k) || (TirarMonedaCargada(RegConfig.mutacionJoinProb))) { fprintf(DebugFP(),"MutarJoin 1 : "); codRet = MutacionJoin(hijo1,vVecArchivos); if (codRet != OK) return (codRet); } /* veamos si tenemos que mutar (operador join) al hijo 2 */ if ((hijo2->agrup->cantGrupos > RegConfig.k) || (TirarMonedaCargada(RegConfig.mutacionJoinProb))) { fprintf(DebugFP(),"MutarJoin 2 : "); codRet = MutacionJoin(hijo2,vVecArchivos); if (codRet != OK) return (codRet); } /* veamos si tenemos que mutar (operador refinar) al hijo 1 */ if (TirarMonedaCargada(RegConfig.mutacionRefinarKMProb)) { fprintf(DebugFP(),"MutarRef 1 : "); codRet = MutacionRefinarKM(hijo1,vVecArchivos); if (codRet != OK) return (codRet); }
212
APNDICE 4 - PROGRAMACION
Eugenio Yolis
/* veamos si tenemos que mutar (operador refinar) al hijo 2 */ if (TirarMonedaCargada(RegConfig.mutacionRefinarKMProb)) { fprintf(DebugFP(),"MutarRef 2 : "); codRet = MutacionRefinarKM(hijo2,vVecArchivos); if (codRet != OK) return (codRet); } /* veamos si tenemos que mutar (operador refinar selectivo) al hijo 1 */ if (TirarMonedaCargada(RegConfig.mutacionRefinarSelectivoProb)) { fprintf(DebugFP(),"MutarRefSelectivo 1 : "); codRet = MutacionRefinarSelectivo(hijo1,vVecArchivos); if (codRet != OK) return (codRet); } /* veamos si tenemos que mutar (operador refinar) al hijo 2 */ if (TirarMonedaCargada(RegConfig.mutacionRefinarSelectivoProb)) { fprintf(DebugFP(),"MutarRefSelectivo 2 : "); codRet = MutacionRefinarSelectivo(hijo2,vVecArchivos); if (codRet != OK) return (codRet); } hijo1->ultimoJoin = -1; hijo2->ultimoJoin = -1; /* ahora calculamos el fitness del hijo 1 */ hijo1->fitness = FitnessDeCromosoma(*hijo1); hijo1->disponible = true; /* ahora calculamos el fitness del hijo 2 */ hijo2->fitness = FitnessDeCromosoma(*hijo2); hijo2->disponible = true; fprintf(DebugFP(),"Hijo 1 = %f ; Hijo 2 = %f\n",hijo1->fitness,hijo2->fitness); /* los insertamos en la poblacion */ codRet = UbicarEnPoblacion(hijo1,hijo2); if (codRet != OK) return (codRet); return OK; } uent c_Genetico::UbicarEnPoblacion(tCromosoma *hijo1, tCromosoma *hijo2) /* Ubica los dos hijos en la poblacion */ { uent codRet; uent indReemp1, indReemp2; uent i; tCromosoma **pobAux; tCromosoma *hijoAux; /* seleccionamos 2 para ser reemplazados */ codRet = ElegirPorTorneo(indReemp1,true); if (codRet != OK) return (codRet);
Eugenio Yolis
APNDICE 4 - PROGRAMACION
213
poblacion[indReemp1]->disponible = false; /* lo marcamos */ codRet = ElegirPorTorneo(indReemp2,true); if (codRet != OK) return (codRet); poblacion[indReemp1]->disponible = true; /* desmarcamos al primero */ /* veamos si la poblacion tiene que crecer o disminuir */ if (RegConfig.poblacionTamanio < RegConfig.poblacionTamanioDeseado) { /* la poblacion tiene que crecer */ /* alocamos lugar para uno mas */ pobAux = (tCromosoma**)malloc((RegConfig.poblacionTamanio + 1) * sizeof(tCromosoma*)); /* pasamos la poblacion al nuevo vector */ for (i=0; i < RegConfig.poblacionTamanio; i++) pobAux[i] = poblacion[i]; /* el ultimo lo ponemos en null */ pobAux[RegConfig.poblacionTamanio] = NULL; /* cambiamos los vectores */ free((void*)poblacion); poblacion = pobAux; RegConfig.poblacionTamanio++; /* solamente vamos a reemplazar al peor de los 2 elegidos */ if (poblacion[indReemp1]->fitness < poblacion[indReemp2]->fitness) indReemp2 = RegConfig.poblacionTamanio; else indReemp1 = RegConfig.poblacionTamanio; } else if (RegConfig.poblacionTamanio > RegConfig.poblacionTamanioDeseado) { /* la poblacion tiene que disminuir */ /* nos quedamos solamente con el mejor hijo */ /* ponemos el mejor hijo en hijo1 y el otro en hijo2 */ if (hijo1->fitness < hijo2->fitness) { hijoAux = hijo2; hijo2 = hijo1; hijo1 = hijoAux; } /* eliminamos el hijo2 */ if (hijo2->agrup != NULL) delete(hijo2->agrup); free((void*)hijo2); hijo2 = NULL; /* sacamos uno de los elegidos y disminuimos el tamao de la poblacion */ if (indReemp1 > indReemp2) { i = indReemp1; indReemp1 = indReemp2; } else { i = indReemp2; indReemp2 = indReemp1; } if (poblacion[i]->agrup != NULL) delete(poblacion[i]->agrup); free((void*)poblacion[i]);
214
APNDICE 4 - PROGRAMACION
Eugenio Yolis
for (; i < (RegConfig.poblacionTamanio - 1); i++) poblacion[i] = poblacion[i+1]; RegConfig.poblacionTamanio--; } /* los reemplazamos */ if (poblacion[indReemp1] != NULL) { delete (poblacion[indReemp1]->agrup); free((void*)poblacion[indReemp1]); poblacion[indReemp1] = NULL; } if (poblacion[indReemp2] != NULL) { delete (poblacion[indReemp2]->agrup); free((void*)poblacion[indReemp2]); poblacion[indReemp2] = NULL; } if (hijo1 != NULL) poblacion[indReemp1] = hijo1; if (hijo2 != NULL) poblacion[indReemp2] = hijo2; return OK; } uent c_Genetico::Evolucionar(c_VecArchivo *vVecArchivos[],bool generacionesFijas, uent &cantGeneraciones) /* Implementa el ciclo de evolucion del algoritmo genetico Antes de llamarse a esta funcion debe llamarse a "GenerarPoblacionInicial" Despues de esta funcion, puede llamarse a "DevolverMejorSolucion" */ { uent codRet, iGeneraciones, limiteGeneraciones; if (generacionesFijas == true) limiteGeneraciones = cantGeneraciones; else limiteGeneraciones = RegConfig.generacionesMaximo; iGeneraciones = 0; while (iGeneraciones < limiteGeneraciones) { //xxxdebug printf("Gcion : %d\n",iGeneraciones); fprintf(DebugFP(),"Gcion : %d\n",iGeneraciones); ActualizarParametros(iGeneraciones,limiteGeneraciones); codRet = OperadorCruza(vVecArchivos); if (codRet != OK) return (codRet); iGeneraciones++; } cantGeneraciones = iGeneraciones;
Eugenio Yolis
APNDICE 4 - PROGRAMACION
215
return OK; } uent c_Genetico::MutacionRefinarKM(tCromosoma *cromosoma, c_VecArchivo *vVecArchivos[]) /* operador de mutacion que consiste en realizar una iteracion de la refinacion KMeans sobre el agrupamiento del cromosoma */ { uent codRet,i; uent *indGrupos; uent cantIteraciones, cantCambiosTotal = 0; /* creamos un vector para poner los indices de los grupos */ indGrupos = (uent*)malloc(cromosoma->agrup->cantGrupos * SINT); if (indGrupos == NULL) return ERROR_MEMORIA; for (i=0; i < cromosoma->agrup->cantGrupos; i++) indGrupos[i] = i; cantIteraciones = RegConfig.mutacionRefinarKMCantIter; c_KMeans::k = cromosoma->agrup->cantGrupos; codRet = c_KMeans::FaseRefinarLite(*(cromosoma>agrup),vVecArchivos,indGrupos,true,cantIteraciones,cantCambiosTotal); if (codRet != OK) return codRet; fprintf(DebugFP()," %d\n",cantCambiosTotal); free((void*)indGrupos); return OK; }
uent c_Genetico::MutacionRefinarSelectivo(tCromosoma *cromosoma, c_VecArchivo *vVecArchivos[]) /* operador de mutacion que consiste en refinar solamente los mejores grupos, con la esperanza de aislar los elementos "ruidosos" en 1 o 2 grupos de baja similitud promedio */ { uent i,j,h; c_Agrupamiento *agrup; uent *vecOrdenTamano, *vecOrdenSimilProm, *vecPuntaje; real *vecSimilPromAux; uent *vecPeores, *vecMejores; uent cantMejores; uent cantPeores; real desvioSim, simProm, simDestino, simDestinoAux; uent indGrupoOrigen, indGrupoDestino; uent cantCambios; real pctMejores = (real)0.25; real pctPeores = (real)0.25; real factorDesvioTolerado = (real)0.8; agrup = cromosoma->agrup; cantMejores = (int)(agrup->cantGrupos * pctMejores);
216
APNDICE 4 - PROGRAMACION
Eugenio Yolis
cantPeores = (int)(agrup->cantGrupos * pctPeores); /* creamos los vectores que vamos a usar */ vecMejores = (uent*)malloc(cantMejores * sizeof(uent)); if (vecMejores == NULL) return ERROR_MEMORIA; vecPeores = (uent*)malloc(cantPeores * sizeof(uent)); if (vecPeores == NULL) return ERROR_MEMORIA; vecOrdenTamano = (uent*)malloc(agrup->cantGrupos * sizeof(uent)); if (vecOrdenTamano == NULL) return ERROR_MEMORIA; vecOrdenSimilProm = (uent*)malloc(agrup->cantGrupos * sizeof(uent)); if (vecOrdenSimilProm == NULL) return ERROR_MEMORIA; vecPuntaje = (uent*)malloc(agrup->cantGrupos * sizeof(uent)); if (vecPuntaje == NULL) return ERROR_MEMORIA; vecSimilPromAux = (real*)malloc(agrup->cantGrupos * sizeof(real)); if (vecSimilPromAux == NULL) return ERROR_MEMORIA; /* vamos a armar 2 vectores en uno vamos a ordenar los grupos por tamao (descendentemente) en el otro, por similitud promedio (descendentemente) */ for (i=0; i<agrup->cantGrupos; i++) { /* calculamos la similitud promedio del grupo y lo ubicamos en el vector */ vecSimilPromAux[i] = agrup->vecGrupos[i].vecCentroide>CalcularNorma(false); vecSimilPromAux[i] *= vecSimilPromAux[i]; // al cuadrado //fprintf(DebugFP(),"Grupo : %d, Sim : %f, Tam : %d\n",i,vecSimilPromAux[i],agrup->vecGrupos[i].cantElementos); j = 0; while ((j < i) && (vecSimilPromAux[i] < vecSimilPromAux[vecOrdenSimilProm[j]])) j++; /* va en la posicion j, hay que correr al resto */ for (h = (agrup->cantGrupos - 1); h > j; h--) vecOrdenSimilProm[h] = vecOrdenSimilProm[h-1]; vecOrdenSimilProm[j] = i; /* ahora hacemos lo mismo pero con el tamao del grupo */ j = 0; while ((j < i) && (agrup->vecGrupos[i].cantElementos < agrup>vecGrupos[vecOrdenTamano[j]].cantElementos)) j++; /* va en la posicion j, hay que correr al resto */ for (h = (agrup->cantGrupos - 1); h > j; h--) vecOrdenTamano[h] = vecOrdenTamano[h-1]; vecOrdenTamano[j] = i; } /* ahora calculamos un puntaje para cada grupo mayor el puntaje -> peor el grupo */ /* primero inicializamos el vector de puntajes en 0 */ for (i=0; i < agrup->cantGrupos; i++) vecPuntaje[i] = 0; for (i=0; i < agrup->cantGrupos; i++) {
Eugenio Yolis
APNDICE 4 - PROGRAMACION
217
h = vecOrdenTamano[i]; if (vecPuntaje[h] == 0) { vecPuntaje[h] = i + 1; } else { if (vecPuntaje[h] < (i+1)) { vecPuntaje[h] *= 2; vecPuntaje[h] += i + 1; } else { vecPuntaje[h] += 2 * (i+1); } // fprintf(DebugFP(),"Grupo : %d, Puntaje : %d\n",h,vecPuntaje[h]); } h = vecOrdenSimilProm[i]; if (vecPuntaje[h] == 0) { vecPuntaje[h] = i + 1; } else { if (vecPuntaje[h] < (i+1)) { vecPuntaje[h] *= 2; vecPuntaje[h] += i + 1; } else { vecPuntaje[h] += 2 * (i+1); } // fprintf(DebugFP(),"Grupo : %d, Puntaje : %d\n",h,vecPuntaje[h]); } } /* armamos los vectores de mejores y peores */ for (i=0; i<cantMejores; i++) vecMejores[i] = agrup->cantGrupos; for (i=0; i<cantPeores; i++) vecPeores[i] = agrup->cantGrupos; for (i=0; i < agrup->cantGrupos; i++) { /* veamos si este grupo entra en el vector de mejores */ j = 0; while (j < cantMejores) { if (vecMejores[j] == agrup->cantGrupos) j++; else if (vecPuntaje[i] < vecPuntaje[vecMejores[j]]) j++; else break; }
218
APNDICE 4 - PROGRAMACION
Eugenio Yolis
if (j > 0) { /* va en la posicion j - 1 */ /* hay que correr los demas */ j--; for (h=0; h < j; h++) vecMejores[h] = vecMejores[h+1]; vecMejores[j] = i; } /* ahora en el de peores */ j = 0; while (j < cantPeores) { if (vecPeores[j] == agrup->cantGrupos) j++; else if (vecPuntaje[i] > vecPuntaje[vecPeores[j]]) j++; else break; } if (j > 0) { /* va en la posicion j - 1 */ /* hay que correr los demas */ j--; for (h=0; h < j; h++) vecPeores[h] = vecPeores[h+1]; vecPeores[j] = i; } } /* ahora vamos a buscar en los mejores grupos los elementos que tengan baja similitud con el centroide y los vamos a pasar a los peores grupos */ cantCambios = 0; for (i=0; i < agrup->cantElementos; i++) { if (c_KMeans::NroGrupoEstaEnVectorIndices(agrup>vecElementos[i],vecMejores,cantMejores,*agrup,indGrupoOrigen)) { /* veamos si la similitud de este elemento con el centroide es peor que el promedio */ simProm = agrup->vecGrupos[indGrupoOrigen].vecCentroide>Multiplicar(*(vVecArchivos[i+1]),false); //fprintf(DebugFP(),"Elemento : %d, Grupo : %d, Sim : %f\n",i,indGrupoOrigen,simProm); if (simProm < vecSimilPromAux[indGrupoOrigen]) { /* es menos similar que el promedio */ desvioSim = vecSimilPromAux[indGrupoOrigen] - simProm; /* buscamos entre los peores grupos al mas similar */ simDestino = (real)0.0; for (h=0; h < cantPeores; h++) { simDestinoAux = agrup>vecGrupos[vecPeores[h]].vecCentroide->Multiplicar(*(vVecArchivos[i+1]),false); if (simDestinoAux > simDestino) {
Eugenio Yolis
APNDICE 4 - PROGRAMACION
219
indGrupoDestino = vecPeores[h]; simDestino = simDestinoAux; } } /* veamos si la mejor similitud esta dentro de lo tolerado */ //fprintf(DebugFP()," Mejor Sim Alternativa : %f, Grupo : %d, Desvio : %f\n",simDestino,indGrupoDestino,desvioSim); if (simDestino > (simProm - (desvioSim * factorDesvioTolerado))) { cantCambios++; c_KMeans::MoverElementoyRecalcular(*agrup,vVecArchivos,i,indGrupoOrigen,indGrup oDestino,true); } } } } fprintf(DebugFP()," %d\n",cantCambios); free((void*)vecMejores); free((void*)vecPeores); free((void*)vecOrdenSimilProm); free((void*)vecOrdenTamano); free((void*)vecPuntaje); free((void*)vecSimilPromAux); return OK; }
uent c_Genetico::MutacionJoin(tCromosoma *cromosoma, c_VecArchivo *vVecArchivos[]) /* operador de mutacion que consiste en juntar 2 grupos */ { uent codRet,i; uent formaElegirGrupoOrigen, formaElegirGrupoDestino; c_Agrupamiento *agrup; real probAux, probRestante; uent indGrupoOrigen, indGrupoDestino, nroGrupoOrigen, nroGrupoDestino; real maxSimProm, simProm, simPromDest, maxSimPromDest; uent cantElem, minCantElem; c_VecArchivo *vecCent2, *vecCent1; uent cantGrupos; agrup = cromosoma->agrup; /* veamos de que forma elegimos al grupo origen */ probRestante = (real)1.0; probAux = (real)(RegConfig.mutacionJoinProbAzar / probRestante); if (TirarMonedaCargada(probAux)) formaElegirGrupoOrigen = 4; /* al azar */ else { probRestante -= probAux; probAux = (real)(RegConfig.mutacionJoinProbMasChico / probRestante); if (TirarMonedaCargada(probAux)) formaElegirGrupoOrigen = 2; /* el mas chico */
220
APNDICE 4 - PROGRAMACION
Eugenio Yolis
switch (formaElegirGrupoOrigen) { case 2: /* mas chico */ minCantElem = MAX_UENT; for (i=0; i < agrup->cantGrupos; i++) { cantElem = agrup->vecGrupos[i].cantElementos; if (cantElem < minCantElem) { minCantElem = cantElem; indGrupoOrigen = i; } } maxSimProm = (real)(0 - minCantElem); break; case 3: /* menor similitud promedio */ maxSimProm = (real)-10000.0; for (i=0; i < agrup->cantGrupos; i++) { vecCent2 = agrup->vecGrupos[i].vecCentroide; simProm = (real)-1.0 * vecCent2->CalcularNorma(false); if (simProm > maxSimProm) { maxSimProm = simProm; indGrupoOrigen = i; } } break; case 4: /* al azar */ maxSimProm = (real)0.0; indGrupoOrigen = RANDOM(agrup->cantGrupos); break; } nroGrupoOrigen = agrup->vecGrupos[indGrupoOrigen].nroGrupo; /* veamos de que forma elegimos al grupo destino */ probAux = (real)(RegConfig.mutacionJoinProbAzar / (RegConfig.mutacionJoinProbAzar + RegConfig.mutacionJoinProbMasSimilar)); if (TirarMonedaCargada(probAux)) formaElegirGrupoDestino = 4; else formaElegirGrupoDestino = 2; switch (formaElegirGrupoDestino) { case 2: /* mas similar */ maxSimPromDest = (real)-1.0; vecCent1 = agrup->vecGrupos[indGrupoOrigen].vecCentroide; for (i=0; i < agrup->cantGrupos; i++) { if (i != indGrupoOrigen) { vecCent2 = agrup->vecGrupos[i].vecCentroide;
Eugenio Yolis
APNDICE 4 - PROGRAMACION
221
simPromDest = vecCent1->Multiplicar(*vecCent2,false); if (simPromDest > maxSimPromDest) { maxSimPromDest = simPromDest; indGrupoDestino = i; } } } break; case 4: /* al azar */ maxSimPromDest = (real)0.0; indGrupoDestino = RANDOM(agrup->cantGrupos); break; } nroGrupoDestino = agrup->vecGrupos[indGrupoDestino].nroGrupo; cromosoma->ultimoJoin = indGrupoDestino; fprintf(DebugFP(),"Join Grupos : fuente=(%d) [%d] %f, destino=(%d) [%d] Sim : %f\n",nroGrupoOrigen,agrup>vecGrupos[indGrupoOrigen].cantElementos,maxSimProm,nroGrupoDestino,agrup>vecGrupos[indGrupoDestino].cantElementos,maxSimPromDest); if (indGrupoDestino != indGrupoOrigen) /* puede pasar que sean iguales cuando se elige al azar */ { /* juntamos los 2 grupos */ for (i=0; i < agrup->cantElementos; i++) { if (agrup->vecElementos[i] == nroGrupoOrigen) { /* lo pasamos al otro */ cantGrupos = agrup->cantGrupos; /* para ver si cambia */ codRet = c_KMeans::MoverElementoyRecalcular(*agrup,vVecArchivos,i,indGrupoOrigen,indGrupoDestin o,true); if (codRet != OK) return codRet; if (cantGrupos != agrup->cantGrupos) { indGrupoOrigen = agrup>IndiceDeGrupo(nroGrupoOrigen,false); indGrupoDestino = agrup>IndiceDeGrupo(nroGrupoDestino,true); } } } } return OK; } uent c_Genetico::AsignarFormaElegirGrupoSplit() /* calcula la forma de elegir el grupo a partir de acuerdo a las probabilidades (usado por el operador de mutacion split) Devuelve : 1 = (... no definido) 2 = Mas grande 3 = Menor similitud promedio
222
APNDICE 4 - PROGRAMACION
Eugenio Yolis
4 = Al Azar */ { real totalProbRestante; totalProbRestante = (real)1.0; if (TirarMonedaCargada(RegConfig.mutacionSplitProbMasGrande * (real)(1.0 / totalProbRestante))) { return 2; } totalProbRestante -= RegConfig.mutacionSplitProbMasGrande; if (TirarMonedaCargada(RegConfig.mutacionSplitProbMenorSimilProm * (real)(1.0 / totalProbRestante))) { return 3; } /* si llegamos hasta aca, es al azar */ return 4; } uent c_Genetico::MutacionSplit(tCromosoma *cromosoma, c_VecArchivo *vVecArchivos[]) /* operador de mutacion que consiste en tomar un grupo y separarlo en 2 */ { uent codRet,i; uent formaElegirGrupoOrigen; c_Agrupamiento *agrup; uent indGrupoOrigen, nroGrupoOrigen; real maxSimProm, simProm; c_VecArchivo *vecCent2; uent cantElem, maxCantElem; uent kAux; uent *vec2Ind; agrup = cromosoma->agrup; if (cromosoma->ultimoJoin == -1) { /* veamos de que forma elegimos al grupo a partir */ formaElegirGrupoOrigen = AsignarFormaElegirGrupoSplit(); switch (formaElegirGrupoOrigen) { case 2: /* mas grande */ maxCantElem = 0; for (i=0; i < agrup->cantGrupos; i++) { cantElem = agrup->vecGrupos[i].cantElementos; if (cantElem > maxCantElem) { maxCantElem = cantElem; indGrupoOrigen = i; } } maxSimProm = (real)maxCantElem; break; case 3: /* menor similitud promedio */
Eugenio Yolis
APNDICE 4 - PROGRAMACION
223
maxSimProm = (real)-10000.0; for (i=0; i < agrup->cantGrupos; i++) { vecCent2 = agrup->vecGrupos[i].vecCentroide; simProm = (real)-1.0 * vecCent2->CalcularNorma(false); if (simProm > maxSimProm) { maxSimProm = simProm; indGrupoOrigen = i; } } break; case 4: /* al azar */ maxSimProm = (real)0.0; indGrupoOrigen = RANDOM(agrup->cantGrupos); break; } } else //tomamos el grupo donde se hizo el ultimo join { indGrupoOrigen = cromosoma->ultimoJoin; maxSimProm = (real)-1.0; } nroGrupoOrigen = agrup->vecGrupos[indGrupoOrigen].nroGrupo; fprintf(DebugFP(),"Split Grupos : fuente=(%d) [%d] %f\n",nroGrupoOrigen,agrup>vecGrupos[indGrupoOrigen].cantElementos,maxSimProm); /* lo partimos */ /* guardamos el valor actual de k de la clase kmeans */ kAux = c_KMeans::k; /* seteamos el k del kmeans igual a 2 */ c_KMeans::k = 2; /* creamos un vector para contener el indice del nuevo grupo */ vec2Ind = (uent*)malloc(SINT * 2); if (vec2Ind == NULL) return ERROR_MEMORIA; /* separamos el grupo en 2 usando la fase inicial del kmeans */ codRet = c_KMeans::FaseInicial(*agrup,nroGrupoOrigen,vVecArchivos,vec2Ind,true,RegConfig.mutacion SplitCantMuestras); if (codRet != OK) return codRet; /* calculamos los centroides */ codRet = c_KMeans::CalcularCentroides(*agrup,vVecArchivos,2,vec2Ind); if (codRet != OK) return codRet; /* reponemos el valor de k de la clase kmeans */ c_KMeans::k = kAux; free((void*)vec2Ind); return OK; }
224
APNDICE 4 - PROGRAMACION
Eugenio Yolis
A4.2.13 Def.h
/* En este archivo se hacen las definiciones generales que se utilizaran en el resto del programa */ #ifndef __NuestraDefH__ /* si no esta definido todo esto... */ /* lo definimos ahora */ #define __NuestraDefH__ #include "limits.h" /* estamos en windows */ #define midefDOS typedef char byte; typedef unsigned char ubyte; #define SBYTE sizeof(char) #define MAX_UBYTE UCHAR_MAX /* 8 bits, 1 byte */ typedef short int ent; typedef unsigned short int uent; #define SINT sizeof(short int) #define MAX_UENT USHRT_MAX /* 16 bits, 2 bytes */ typedef long int word; typedef unsigned long int uword; #define SWORD sizeof(long int) #define MAX_UWORD ULONG_MAX /* 32 bits, 4 bytes */ typedef float real; #define SREAL sizeof(float); #define BITS_A_BYTES(b) ((b & 7) ? ((b>>3)+1) : (b>>3)) /* devuelve la cantidad de bytes necesarias para almacenar b bits */ /* si b es divisible por 8, devuelve b/8, sino, (b/8)+1 */ #define TRUE 1 #define FALSE 0 #define MAX_LONG_PALABRA 250 /* cantidad maxima de caracteres que puede tener el nombre de un archivo */ #define MAX_LONG_NOMARCH 350 /* definimos el tamanio de los buffers */ #define TBUFFTXT 1000 #define OK 0 #define ERROR 1 #define ERROR_MEMORIA 2 #define ERROR_ARCHIVO 3 #define ERROR_DIRECTORIO 4
Eugenio Yolis
APNDICE 4 - PROGRAMACION
225
226
APNDICE 4 - PROGRAMACION
Eugenio Yolis
A4.2.14 Sis.h
/* En vez de incluir sisdos o sislinux debe incluirse este archivo para poder tener definidas las funciones de sistema */ #include "def.h" #ifdef midefDOS /* dos */ #ifndef __SisDosH__ #include "sisdos.h" #endif #endif #ifndef midefDOS /* linux */ #ifndef __SisLinuxH__ #include "sislinux.h" #endif #endif
Eugenio Yolis
APNDICE 4 - PROGRAMACION
227
A4.2.15 SisDos.h
/* Va a contener las rutinas que dependen del sistema operativo en version DOS */ #include <io.h> #include <malloc.h> #include "def.h" #include <string.h> #include <stdlib.h> #define __SisDosH__ #define RANDOM(n) (random(n)) /* esta macro devuelve un nro random entre 0 y n-1 */ #define PI (real)3.14159 /* para hora y fecha voy a usar el formato DOS */ /* el puntero a directorio lo presento como puntero a unsigned, total...*/ typedef long t_dir; t_dir PrimeroDir(char *path, char *nomarch); /* Abre el directorio "path" y devuelve en dir un puntero a la estructura de directorio Si devuelve NULL, el directorio no se pudo abrir o esta vacio En nomarch devuelve el nombre del primer archivo del directorio En f y h, fecha y hora de ultima modificacion */ t_dir SiguienteDir(t_dir d, char *nomarch); /* Obtiene el siguiente archivo del directorio Si devuelve NULL, el directorio no tiene mas archivos En nomarch devuelve el nombre del siguiente archivo del directorio En f y h, fecha y hora de ultima modificacion */
ent random(int n); /* Devuelve un nro aleatorio entre 0 y n-1 */ uent *kNumerosRandom(uent k, uent minimo, uent maximo, bool ordenados); /* Devuelve k numeros al azar que esten entre minimo y maximo (incluyendo el minimo y el mximo */
bool TirarMonedaCargada(real probabilidadTrue); /* esta funcin devuelve "true" con probabilidad "probabilidadTrue" "probabilidadTrue" debe estar comprendida entre 0 y 1 */
228
APNDICE 4 - PROGRAMACION
Eugenio Yolis
A4.2.16 SisDos.cpp
/* Va a contener las rutinas que dependen del sistema operativo en version DOS */ #include "sisdos.h"
static struct _finddata_t blkarch; static char ruta[255]; /* necesitamos que esto sea global */
t_dir PrimeroDir(char *path, char *nomarch) /* Abre el directorio "path" y devuelve en dir un puntero a la estructura de directorio Si devuelve NULL, el directorio no se pudo abrir o esta vacio En nomarch devuelve el nombre del primer archivo del directorio En f y h, fecha y hora de ultima modificacion */ { char path2[256]; t_dir codRet; strcpy(ruta,path); strcpy(path2,path); strcat(path2,"\\*.*"); if ((codRet = _findfirst(path2,&blkarch)) == -1) /* no se pudo abrir */ return -1; strcpy(nomarch,ruta); strcat(nomarch,"\\"); strcat(nomarch,blkarch.name); /* devolvemos un puntero no nulo */ return codRet; } t_dir SiguienteDir(t_dir d, char *nomarch) /* Obtiene el siguiente archivo del directorio Si devuelve NULL, el directorio no tiene mas archivos En nomarch devuelve el nombre del siguiente archivo del directorio En f y h, fecha y hora de ultima modificacion */ { if (_findnext(d, &blkarch) == -1) return -1; strcpy(nomarch,ruta); strcat(nomarch,"\\"); strcat(nomarch,blkarch.name); /* devolvemos no nulo */ return d; }
ent random(int n)
Eugenio Yolis
APNDICE 4 - PROGRAMACION
229
{ /* float f; //conseguimos un nro entre 0 y 1 f = (float)(rand() - 1) / RAND_MAX; f = f * n; return (int)f; */ return (rand() % n); } uent *kNumerosRandom(uent k, uent minimo, uent maximo, bool ordenados) { uent *punt; uent i,j,h,nroAzar,nroAzar2; if (((maximo - minimo) + 1) < k) return NULL; /* creamos un vector de k numeros */ punt = (uent*)malloc(k * SINT); if (punt==NULL) return NULL; /* vamos generando los numeros */ /* los generamos siempre ordenados, y si se necesitan desordenados, los desordenamos despues */ if (((maximo - minimo) + 1) == k) { /* caso trivial */ for (i=0; i < k; i++) punt[i] = minimo + i; } else { for (i=0; i < k; i++) { /* generamos un numero al azar en el intervalo que corresponde */ /* la primera vez va entre el minimo y el maximo pero luego el intervalo se va achicando */ nroAzar = RANDOM(1 + (maximo - minimo) - i); nroAzar += minimo; /* veamos en que posicion del vector debe ingresarse */ j = 0; while ((punt[j] <= nroAzar) && (j < i)) { nroAzar++; j++; } /* corremos las posiciones del vector hacia arriba */ for (h = i; h > j; h--) { punt[h] = punt[h-1]; } /* lo insertamos */ punt[j] = nroAzar; }
230
APNDICE 4 - PROGRAMACION
Eugenio Yolis
} if (!ordenados) { /* los desordenamos */ for (i=0; i < k; i++) { nroAzar = RANDOM(k); nroAzar2 = RANDOM(k); j = punt[nroAzar]; punt[nroAzar] = punt[nroAzar2]; punt[nroAzar2] = j; } } return punt; } bool TirarMonedaCargada(real probabilidadTrue) { uent nroAzar; nroAzar = RANDOM(100); return (nroAzar < (probabilidadTrue * 100)); }
Eugenio Yolis
APNDICE 4 - PROGRAMACION
231
A4.2.17 Ppal.cpp
#include "def.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <conio.h> #include "skipl.h" #include "archtxt.h" #include "vecArchivos.h" #include "archivostexto.h" #include "filtrarpalabras.h" #include "clsAgrupamiento.h" #include "clsKMeans.h" #include "clsAgrupImprime.h" #include "clsGenetico.h" /* VARIABLES GLOBALES */ uent generacionesGenetico; char szSalida[300] = "salida\\salida_clustering.txt"; c_SkipList **lLexArchivos; c_SkipList lTxt; c_SkipList lLex; c_VecArchivo **vVectoresArchivos; time_t startTime, elapsedTime, endTime; uent codRet; uent kBisect; char szMat[300] = ""; uent cantGrupos; char szAlgoritmo[300]; uent iCorridas; void ImprimirAgrupamiento(c_Agrupamiento &agrup) /* imprime el agrupamiento en el archivo szSalida */ { FILE *fpSalida; fpSalida = fopen(szSalida,"wt"); fprintf(fpSalida,"CantMultip=%d\n",c_VecArchivo::contMultiplicaciones); fprintf(fpSalida,"CantCalcNorma=%d\n",c_VecArchivo::contCalculoNorma); fprintf(fpSalida,"CantMovimientos=%d\n",c_KMeans::contMoverYRecalcular); c_Agrup_Imprime::salidaCompacta = true; c_Agrup_Imprime::ImprimirTodo(fpSalida,agrup,vVectoresArchivos,lLex,lTxt); fclose(fpSalida); //xxxdebug fpSalida = fopen("salida_no_compacta.txt","wt"); c_Agrup_Imprime::salidaCompacta = false; c_Agrup_Imprime::ImprimirTodo(fpSalida,agrup,vVectoresArchivos,lLex,lTxt); fclose(fpSalida); } /* Las funciones "Agrupar...." realizan un agrupamiento y lo imprimen en szSalida */
232
APNDICE 4 - PROGRAMACION
Eugenio Yolis
uent AgruparRandom(uent k) /* Realiza un agrupamiento al azar de los documentos en k grupos */ { c_Agrupamiento agrup; uent codRet; startTime = time(NULL); codRet = agrup.Inicializar((uent)lTxt.ObtenerCantElementos()); if (codRet != OK) return codRet; codRet = agrup.AgruparAlAzar(k,k); if (codRet != OK) return codRet; codRet = c_KMeans::CalcularCentroides(agrup,vVectoresArchivos,0,NULL); if (codRet != OK) return codRet; endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin agrupar al azar : %d segundos\n",elapsedTime); ImprimirAgrupamiento(agrup); return OK; } uent AgruparKMeansComun(uent k) /* realiza un agrupamiento k-means en k grupos */ { c_Agrupamiento agrup; uent codRet; uent *vecIndGrupos; uent cantIteraciones = 100, cantCambiosTotal = 0; startTime = time(NULL); c_KMeans::k = k; vecIndGrupos = (uent *)malloc(k * SINT); if (vecIndGrupos == NULL) return ERROR_MEMORIA; codRet = agrup.Inicializar((uent)lTxt.ObtenerCantElementos()); if (codRet != OK) return codRet; codRet = agrup.AgruparAlAzar(1,1); if (codRet != OK) return codRet; codRet = c_KMeans::FaseInicial(agrup,1,vVectoresArchivos,vecIndGrupos,false,0); if (codRet != OK) return codRet;
Eugenio Yolis
APNDICE 4 - PROGRAMACION
233
endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin fase inicial : %d segundos\n",elapsedTime); startTime = time(NULL); c_KMeans::CalcularCentroides(agrup,vVectoresArchivos,0,NULL); //c_Agrup_Imprime::ImprimirTodo(stdout,agrup,vVectoresArchivos,lLex,lTxt); endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin calcular centroides : %d segundos\n",elapsedTime); startTime = time(NULL); printf("Vamos a refinar...\n"); c_KMeans::FaseRefinar(agrup,vVectoresArchivos,vecIndGrupos,true,cantIteraciones,c antCambiosTotal); printf("Refinar : %d iteraciones.\n",cantIteraciones); endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin refinar : %d segundos\n",elapsedTime); startTime = time(NULL); /* liberamos el vector de k indices */ free((void*)vecIndGrupos); ImprimirAgrupamiento(agrup); return OK; } uent AgruparBisectingKMeans(uent k, bool refinar) /* realiza un agrupamiento bisecting k-means en k grupos */ { c_Agrupamiento *agrup; uent codRet; agrup = new c_Agrupamiento(); startTime = time(NULL); printf("Empezando bisecting k-means ...\n"); c_KMeans::k = k; codRet = agrup->Inicializar((uent)lTxt.ObtenerCantElementos()); if (codRet != OK) return codRet; codRet = agrup->AgruparAlAzar(1,1); if (codRet != OK) return codRet; codRet = c_KMeans::BisectingKMeans(agrup,1,vVectoresArchivos,kBisect,refinar); if (codRet != OK) return codRet;
234
APNDICE 4 - PROGRAMACION
Eugenio Yolis
endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin bisecting k-means : %d segundos\n",elapsedTime); startTime = time(NULL); ImprimirAgrupamiento(*agrup); delete(agrup); return OK; } uent AgruparBisectingKMeansSinRef(uent k) { return AgruparBisectingKMeans(k,false); } uent AgruparBisectingKMeansConRef(uent k) { return AgruparBisectingKMeans(k,true); } uent AgruparGenetico(uent k) /* Realiza un agrupamiento de los documentos en k grupos usando el algoritmo genetico */ { c_Genetico objGenetico; uent codRet; c_Agrupamiento *agrup = NULL; uent cantGeneraciones, i, cantIteraciones, cantCambiosTotal; FILE *fp; uent *vecIndGrupos; char szDebug[255]; //fp = NULL; sprintf(szAlgoritmo,"Gen"); sprintf(szSalida,"salida\\salida_%s_%s_%d_%d.txt",szMat,szAlgoritmo,cantGrupos,iCor ridas); sprintf(szDebug,"%s_d.asc",szSalida); fp = fopen(szDebug,"wt"); objGenetico.RegConfig.fpSalidaDebug = fp; uent a = 0; startTime = time(NULL); objGenetico.RegConfig.k = k; codRet = objGenetico.GenerarPoblacionInicial((uent)lTxt.ObtenerCantElementos(),vVectoresArchivos); if (codRet != OK) return codRet; endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin generar poblacion inicial : %d segundos\n",elapsedTime); startTime = time(NULL);
Eugenio Yolis
APNDICE 4 - PROGRAMACION
235
cantGeneraciones = generacionesGenetico; codRet = objGenetico.Evolucionar(vVectoresArchivos,true,cantGeneraciones); if (codRet != OK) return codRet; endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin evolucion : %d segundos\n",elapsedTime); startTime = time(NULL); codRet = objGenetico.DevolverMejorSolucion(&agrup); if (codRet != OK) return codRet; if (fp != NULL) fclose(fp); /* lo imprimimos sin refinar */ ImprimirAgrupamiento(*agrup); /* ahora lo refinamos con el KMeans */ c_KMeans::k = agrup->cantGrupos; vecIndGrupos = (uent*)malloc(agrup->cantGrupos * SINT); for (i=0; i < agrup->cantGrupos; i++) vecIndGrupos[i] = i; cantIteraciones = 100; codRet = c_KMeans::FaseRefinar(*agrup,vVectoresArchivos,vecIndGrupos,true,cantIteraciones,cantCam biosTotal); endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin refinar : %d segundos\n",elapsedTime); startTime = time(NULL); /* lo imprimimos refinado */ sprintf(szAlgoritmo,"Gen(ref)"); sprintf(szSalida,"salida\\salida_%s_%s_%d_%d.txt",szMat,szAlgoritmo,cantGrupos,iCor ridas); ImprimirAgrupamiento(*agrup); return OK; } int main(void) { int i; //int j; //uent valEnt; //real valReal; char szDir[300] = "d:\\Tesis_Docs"; char szPathMat[300] = ""; uent cantLex; uent cantArchivos; char opcion; uent codRet; bool bCorrerAlgoritmo; uent (*funcionAgrupar)(uent); /* puntero a la funcion */
236
APNDICE 4 - PROGRAMACION
Eugenio Yolis
uent cantCorridas; uent cantGruposLoc; /* inicializamos la serie de numeros al azar */ srand( (unsigned)time( NULL ) ); /* preguntamos por el directorio de los archivos */ printf ("Directorio donde se encuentran los archivos (ej: 'd:\\Tesis_Docs') : "); scanf("%s",&szDir); getchar(); /* veamos si hay que leer archivos txt del disco o si se debe cargar un dataset .mat */ printf ("Nombre del .mat (ej : 're0_1') o 'txt' para leer archivos .txt : "); scanf("%s",&szMat); getchar(); if (strcmp((char*)&szMat,"txt") == 0) { /* ***************************************** */ /* LEEMOS LOS ARCHIVOS .TXT DEL DISCO */ /* Se leen los archivos y se arman las listas de palabras */ startTime = time(NULL); lTxt.SetearOrden(1); /* los ordenamos por numero */ cantArchivos = CargarListaArchivos(szDir,lTxt); /* creamos los vectores de listas y vectores de palabras */ lLexArchivos = (c_SkipList**)malloc((cantArchivos+1)*sizeof(c_SkipList*)); if (lLexArchivos == NULL) return ERROR_MEMORIA; vVectoresArchivos = (c_VecArchivo**)malloc((cantArchivos+1)*sizeof(c_VecArchivo*)); if (vVectoresArchivos == NULL) return ERROR_MEMORIA; codRet = ProcesarArchivosTexto(lTxt,lLex,TBUFFTXT,cantLex,lLexArchivos); if (codRet != OK) return codRet; endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin leer archivos : %d segundos\n",elapsedTime); startTime = time(NULL); /* FIN DE LEER LOS ARCHIVOS */ /*********************************************/ /* ******************************************** */ /* VAMOS A FILTRAR LAS LISTAS DE LEXICO */ codRet = FiltrarListasDeLexico(lLex,lLexArchivos,lTxt.ObtenerCantElementos()); if (codRet != OK) return codRet; /* al renumerar los valores, la lista de lexico queda ordenada tanto
Eugenio Yolis
APNDICE 4 - PROGRAMACION
237
por numero de palabra como por orden alfabtico */ lLex.RenumerarValores(); /* FIN FILTRAR LISTAS DE LEXICO */ /************************************/ } else { /* Leemos un dataset en formato .mat */ sprintf((char*)&szPathMat,"%s\\%s.mat",szDir,szMat); startTime = time(NULL); lTxt.SetearOrden(1); /* los ordenamos por numero */ cantArchivos = CargarListaArchivosMAT(szPathMat,lTxt); /* creamos los vectores de listas y vectores de palabras */ lLexArchivos = (c_SkipList**)malloc((cantArchivos+1)*sizeof(c_SkipList*)); if (lLexArchivos == NULL) return ERROR_MEMORIA; vVectoresArchivos = (c_VecArchivo**)malloc((cantArchivos+1)*sizeof(c_VecArchivo*)); if (vVectoresArchivos == NULL) return ERROR_MEMORIA; lLex.SetearOrden(1); /* lo ordenamos por numero */ codRet = ProcesarArchivosTextoMAT(szPathMat,lLex,cantLex,lLexArchivos); if (codRet != OK) return codRet; endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin leer .mat : %d segundos\n",elapsedTime); startTime = time(NULL); } /* ******************************************** */ /* VAMOS A CREAR LOS VECTORES DE ARCHIVOS */ codRet = ArmarVectoresArchivos(lLex,lTxt.ObtenerCantElementos(),lLexArchivos,vVectoresArchivos); if (codRet != OK) return codRet; /* a partir de aca no vamos a volver a buscar por orden alfabetico en la lista de lexico */ lLex.SetearOrden(1); /* no necesitamos ms las listas de palabras de los archivos */ for (i=1; i <= cantArchivos; i++) delete(lLexArchivos[i]); free((void*)lLexArchivos);
238
APNDICE 4 - PROGRAMACION
Eugenio Yolis
endTime = time(NULL); elapsedTime = endTime - startTime; printf("Fin inicializacion : %d segundos\n",elapsedTime); startTime = time(NULL); /* FIN DE ARMAR VECTORES DE ARCHIVOS */ /* ************************************************* */
/* Ahora vamos a mostrar un menu para que se pueda elegir que hacer */ opcion = 0; /* valores por default */ cantGrupos = 15; cantCorridas = 5; kBisect = 2; generacionesGenetico = 50; while (opcion != 'x') { bCorrerAlgoritmo = false; printf("(1) Cambiar cantidad grupos (%d)\n",cantGrupos); printf("(2) Cambiar cantidad corridas (%d)\n",cantCorridas); printf("(3) Cambiar generaciones del genetico (%d)\n",generacionesGenetico); printf("(4) Cambiar k de bisecting K-Means (%d)\n",kBisect); printf("(a) Bisecting K-Means (con refinamiento)\n"); printf("(b) Algoritmo Genetico (con y sin refinamiento)\n"); printf("(c) Al Azar\n"); printf("(d) K-Means Comun\n"); printf("(e) Bisecting K-Means (sin refinar)\n"); printf("(x) Salir\n"); printf("\n"); printf ("? "); opcion = (char)getchar(); getchar(); switch (opcion) { case 'a': funcionAgrupar = &AgruparBisectingKMeansConRef; sprintf(szAlgoritmo,"BisKM(ref)%d",kBisect); bCorrerAlgoritmo = true; break; case 'b': funcionAgrupar = &AgruparGenetico; sprintf(szAlgoritmo,"Gen"); bCorrerAlgoritmo = true; break; case 'c': funcionAgrupar = &AgruparRandom; sprintf(szAlgoritmo,"Azar"); bCorrerAlgoritmo = true; break; case 'd': funcionAgrupar = &AgruparKMeansComun; sprintf(szAlgoritmo,"KMCom"); bCorrerAlgoritmo = true; break;
//
// // //
Eugenio Yolis
APNDICE 4 - PROGRAMACION
239
case 'e': funcionAgrupar = &AgruparBisectingKMeansSinRef; sprintf(szAlgoritmo,"BisKM%d",kBisect); bCorrerAlgoritmo = true; break; case '1': printf("Grupos : "); scanf("%d",&cantGruposLoc); getchar(); cantGrupos = cantGruposLoc; break; case '2': printf("Corridas : "); scanf("%d",&cantCorridas); getchar(); break; case '3': printf("Generaciones : "); scanf("%d",&generacionesGenetico); getchar(); break; case '4': printf("K de bisecting k-means : "); scanf("%d",&kBisect); getchar(); break; } if (bCorrerAlgoritmo) { for (iCorridas = 0; iCorridas < cantCorridas; iCorridas++) { /* reseteamos los contadores de las clases */ c_KMeans::contMoverYRecalcular = 0; c_VecArchivo::contCalculoNorma = 0; c_VecArchivo::contMultiplicaciones = 0; sprintf(szSalida,"salida\\salida_%s_%s_%d_%d.txt",szMat,szAlgoritmo,cantGrupos,iCor ridas); codRet = (*funcionAgrupar)(cantGrupos); if (codRet != OK) return codRet; } } } /* liberamos los vectores de los archivos */ for (i=1; i <= cantArchivos; i++) delete(vVectoresArchivos[i]); free((void*)vVectoresArchivos); return 0; }
240
APNDICE 4 - PROGRAMACION
Eugenio Yolis