En esta nota desarrollamos el tema de discretizaación de datos utilizando el paquete discretization el cual fue desarrollado por HyunJi Kim.

La discretización de datos es una técnica utilizada para la aplicación de muchos algoritmos de aprendizaje automático. En las bases de datos cuando se tienen atributos continuos puede complicar el aprendizaje. Al convertir una variable continua en una discreta, los algorítmos pueden trabajar con frecuencias. Existen muchos tipos de algoritmos de discretización, en esta nota hablaremos de tres métodos de discretización: chiMerge, entropía con mdlp y el método de CAIM. Estos métodos son basado en aprendizaje supervisado por lo que necesitan de una variable de clase para la realización del método.

ChiMerge

Este método de discretización utiliza el enfoque de juntar intervalos. Este método tiene dos características importantes, primero que las frecuencias relativas de clase deben ser bastante parecidas dentro de un intervalo (de lo contrario se debe dividir el intervalo). Dos intervalos adyacentes no deben tener similares frecuencias relativas de clase (de lo contrario se debe juntar). Este método utiliza la prueba de independencia \(\chi^{2}\) para saber si dos tributos \(F_{i}\) son independientes. Para dos intervalos adyacentes, si la prueba \(\chi^{2}\) concluye que la clase es independiente de los intervalos, los intervalos se deben juntar. Si la prueba \(\chi^{2}\) concluye que no son independientes y además la diferencia en frecuencia relativa de la clase es estadísticamente significativa, los dos intervalos deben continuar separados.

Para probar el algorítmo utilizaremos primero la base de iris incorporada a R.

data<-iris
head(data)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa

La base de iris contiene tres atributos continuos y tres clases de Species. Utilizamos para la discretización un alpha de 0.05 para el método de \(\chi^{2}\).

library(discretization)
data<-iris
data_dis<-chiM(data, alpha = 0.05)
data_dis$cutp #intervalos
## [[1]]
## [1] 5.45 5.75 7.05
## 
## [[2]]
## [1] 2.95 3.35
## 
## [[3]]
## [1] 2.45 4.75 5.15
## 
## [[4]]
## [1] 0.80 1.75
head(data_dis$Disc.data) #data
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1            1           3            1           1  setosa
## 2            1           2            1           1  setosa
## 3            1           2            1           1  setosa
## 4            1           2            1           1  setosa
## 5            1           3            1           1  setosa
## 6            1           3            1           1  setosa

Dentro de $cutp se encuentran los intervalos utilizados y dentro de $Disc.data se encuentra la data discretizada. Este método de discretización suele dar más intervalos por aitributo que otros métodos como los basado en entropía o CAIM. Ahora discretizaremos una base externa. La base de datos utilizada muestra tres tipos distintos de vino y sus dintitntas características. Fue desarrollada por Forina, M. et al (1988) "PARVUS - An Extendible Package for Data Exploration, Classification and Correlation".

wine <- read.csv("https://raw.githubusercontent.com/IranNash/datasets/master/wine.csv")
head(wine)
##   Alcohol Malic_acid  Ash Alcalinity_of_ash Magnesium Total_phenols Flavanoids
## 1   14.23       1.71 2.43              15.6       127          2.80       3.06
## 2   13.20       1.78 2.14              11.2       100          2.65       2.76
## 3   13.16       2.36 2.67              18.6       101          2.80       3.24
## 4   14.37       1.95 2.50              16.8       113          3.85       3.49
## 5   13.24       2.59 2.87              21.0       118          2.80       2.69
## 6   14.20       1.76 2.45              15.2       112          3.27       3.39
##   Nonflavanoid_phenols Proanthocyanins Color_intensity  Hue
## 1                 0.28            2.29            5.64 1.04
## 2                 0.26            1.28            4.38 1.05
## 3                 0.30            2.81            5.68 1.03
## 4                 0.24            2.18            7.80 0.86
## 5                 0.39            1.82            4.32 1.04
## 6                 0.34            1.97            6.75 1.05
##   OD280_OD315_of_diluted_wines Proline   Vino
## 1                         3.92    1065 Vino 1
## 2                         3.40    1050 Vino 1
## 3                         3.17    1185 Vino 1
## 4                         3.45    1480 Vino 1
## 5                         2.93     735 Vino 1
## 6                         2.85    1450 Vino 1

Pasamos a calcular la discretización con ChiMerge:

data_dis<-chiM(wine, alpha = 0.05)

Los intervalos calculados son un número relativamente grande como se puede observar:

data_dis$cutp 
## [[1]]
##  [1] 12.185 12.780 12.975 13.075 13.655 13.675 14.125 14.175 14.320 14.355
## 
## [[2]]
## [1] 1.225 1.475 1.635 1.980 2.235 2.395 2.455 3.945 4.070
## 
## [[3]]
## [1] 2.030 2.145 2.315 2.405 2.470 2.490 2.630 2.645
## 
## [[4]]
## [1] 17.45 18.30 18.55 18.95 19.05 20.60
## 
## [[5]]
## [1]  88.5 106.5 133.0
## 
## [[6]]
## [1] 1.840 2.265 2.335 2.580 2.730 2.745 2.815
## 
## [[7]]
## [1] 0.565 0.575 0.975 1.575 2.180 2.200 2.310 3.185 3.745
## 
## [[8]]
## [1] 0.395
## 
## [[9]]
## [1] 1.230 1.305 1.655 1.705 1.965 1.985 2.020 2.470
## 
## [[10]]
## [1] 3.460 3.975 4.425 4.850 7.550 8.680 8.955
## 
## [[11]]
## [1] 0.685 0.785 0.805 0.925 1.005 1.295
## 
## [[12]]
## [1] 2.190 2.475 3.040 3.305
## 
## [[13]]
## [1] 468.0 719.0 987.5

Los datos discretizados son:

head(data_dis$Disc.data) #data
##   Alcohol Malic_acid Ash Alcalinity_of_ash Magnesium Total_phenols Flavanoids
## 1       9          4   5                 1         3             7          8
## 2       5          4   2                 1         2             5          8
## 3       5          6   9                 4         2             7          9
## 4      11          4   7                 1         3             8          9
## 5       5          8   9                 7         3             7          8
## 6       9          4   5                 1         3             8          9
##   Nonflavanoid_phenols Proanthocyanins Color_intensity Hue
## 1                    1               8               5   6
## 2                    1               2               3   6
## 3                    1               9               5   6
## 4                    1               8               6   4
## 5                    1               5               3   6
## 6                    1               6               5   6
##   OD280_OD315_of_diluted_wines Proline   Vino
## 1                            5       4 Vino 1
## 2                            5       4 Vino 1
## 3                            4       4 Vino 1
## 4                            5       4 Vino 1
## 5                            3       3 Vino 1
## 6                            3       4 Vino 1

Método de Entropía con el MDLP

Los métodos basados en entropía utilizan la información existente en la clasificación de los datos, es decir, es un algoritmo supervisado. Este método busca encontrar una partición que mantenga la máxima ganancia de información. Para un atributo \(F_{i}\) con clases \(C_{j}\) la entropía para \(F_{i}\) se define como:

\[ \text{Entropia}(F_{i},C_{j}) = - \sum_{j = 1}^{n} p_{j}*\log_{2}(p_{j}), \]

donde \(p_{i}\) es la proporción de las unidades que pertenecen a la clase \(C_{j}\) en el atributo \(F_{i}\). El algoritmo desea que los conjuntos no estén tan ``mezclados'' así que premia valores bajos de entropía. El método dado una partición de clases \(C_{j}\) busca una partición de intervalos \(D = \{d_{0},d_{n}\}\) tal que \(\text{Entropia} (F_{i},D) - \text{Entropia} (F_{i},\hat{D}) < \delta\), donde delta es un criterio de parada del algoritmo. Para el caso particular de este método el criterio de parada será:

\[ \delta > \frac{\log(N-1)}{N} - \log_{2}(3^{c} - 2) - \sum_{i = 1}^{n}c_{i}\text{Entropia}(d_{i}), \] aquí \(c\) es el número de clases en \(F\), \(c_{i}\) es el número de clases en \(F_{i}\). Esto es llamado el Principio de Longitud de Descripción Mínima (MDLP).

Para realizar la implemetación utilizamos mdlp(). Nuevamente empezaremos con la discretización en iris.

data<-iris
data_dis<-mdlp(data)
data_dis$cutp #Intervalos
## [[1]]
## [1] 5.55 6.15
## 
## [[2]]
## [1] 2.95 3.35
## 
## [[3]]
## [1] 2.45 4.75
## 
## [[4]]
## [1] 0.80 1.75
head(data_dis$Disc.data) #Data discretizada
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1            1           3            1           1  setosa
## 2            1           2            1           1  setosa
## 3            1           2            1           1  setosa
## 4            1           2            1           1  setosa
## 5            1           3            1           1  setosa
## 6            1           3            1           1  setosa

Ahora discretizaremos una base externa denominada haberman que es un conjunto de datos que contiene los casos de un estudio que se llevó a cabo entre 1958 y 1970 en el Hospital Billings de la Universidad de Chicago sobre la supervivencia de pacientes que se habían sometido a una cirugía por cáncer de mama. Contiene tres atributos (edad del paciente,año de operación, número de ganglios detectados) y una clase que muestra si el paciente sobrevivió 5 años más o si murió antes de los cinco años.

haberman <- read.csv("https://raw.githubusercontent.com/IranNash/datasets/master/haberman.csv")
head(haberman)
##   edad ganglios año_operaion vive
## 1   30        1           64  yes
## 2   30        3           62  yes
## 3   30        0           65  yes
## 4   31        2           59  yes
## 5   31        4           65  yes
## 6   33       10           58  yes

Realizamos la discretización:

data_dis<-mdlp(haberman)
head(data_dis$Disc.data)
##   edad ganglios año_operaion vive
## 1    1        1            1  yes
## 2    1        1            1  yes
## 3    1        1            1  yes
## 4    1        1            1  yes
## 5    1        1            1  yes
## 6    1        2            1  yes

Este método al igual que CAIM suelen discretizar en pocos intevalos, a diferencia de ChiMerge.

Class-Attribute Interdependency Maximization (CAIM)

El modelo CAIM (Class-Attribute Interdependency Maximization) es un algoritmo de descristización el cual genera rangos óptimos que maximizan el grado de interdependencia entre la clase a la que pertenece la unidad de análisis y su correspondiente atributo. El grado de interdependencia que maximiza el algoritmo es el denominado criterio CAIM: \[ CAIM(C,D|F) = \frac{\sum_{r=1}^{n}\frac{\text{max}^{2}_{r}}{M_{+r}}}{n} \] Sea \(F_{i}\) un atributo dentro de una base de datos con \(M\) observaciones por atributo. Sea \(C_{i}\) la clase a la que pertenecen los datos dentro del atributo \(F_{i}\) donde existen un total de \(S\) clases. Sea \(D\) el número de rangos (pares ordenados) donde el limite inferior del primer rango \(d_{0}\) es el dato menor dentro del atributo \(F_{i}\) y \(d_{n}\) es el dato mayor, se entiende que para este caso existen \(n\) rangos. Finalmente \(M_{+r}\) es la suma del total de datos dentro del atributo \(F_{i}\) y \(\max_{r}\) es el número máximo de elementos de un atributo \(F_{i}\) dentro de la clase \(C_{i}\). Como podemos observar el criterio crece a medida que \(\max_{r}\) crece, es decir, a medida que el numero de elementos dentro de una clase en particular aumenta. De igual manera disminuye a medida que aumenta el número de rangos \(n\). Entonces el algoritmo CAIM busca encontrar el mínimo número de rangos que maximizan la interdependencia entre las clases a la que pertenecen las unidades observaciones y sus respectivos atributos. CAIM tendría teóricamente un valor máximo donde todos los elementos de un atributo pertenecen a una única clase.

Planteado de esta manera el algoritmo sería costoso computacionalmente ya que se debería realizar una búsqueda de todas las combinaciones posibles de rangos dentro del intervalo \(D = \{d_{0},d_{n}\}\) tal que se logré maximizar el criterio CAIM. Para lograr esto se ha desarrollado un algoritmo que es económico en términos computacionales.

Implementamos el método con la base iris. Para implementar CAIM se utilizala función disc.Topdown(), esta admite tres métodos: 1: CAIM, 2: CACC y 3: Ameva. Para nuestro caso utilizaremos el 1. Como en los otros métodos, utilizando datos$cutp permite ver los intervalos y con datos$Disc.data permite ver la base.

data <- iris
data_dis <-disc.Topdown(data, method = 1) 
data_dis$cutp #Intervalos
## [[1]]
## [1] 4.30 5.55 6.25 7.90
## 
## [[2]]
## [1] 2.00 2.95 3.05 4.40
## 
## [[3]]
## [1] 1.00 2.45 4.75 6.90
## 
## [[4]]
## [1] 0.10 0.80 1.75 2.50
head(data_dis$Disc.data)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1            1           3            1           1  setosa
## 2            1           2            1           1  setosa
## 3            1           3            1           1  setosa
## 4            1           3            1           1  setosa
## 5            1           3            1           1  setosa
## 6            1           3            1           1  setosa

Hay que recordar que CAIM al utilizar un proceso de búsqueda puede caer en un optimo local, por tanto se recomienda repetir el proceso más de una vez y verificar resultados. Discretizaremos ahora una base externa. Esta es una base de datos ficticia de la web: https://stats.idre.ucla.edu/r/dae/logit-regression/ que contiene tres atributos continuos (Resultado de examen GRE, las puntuaciones calificaciones previas y el prestigio de la institución de procedencia) y una clase (admitido o no admitido).

data <- read.csv("https://raw.githubusercontent.com/IranNash/datasets/master/ucla.csv")
head(data)
##   gre  gpa rank adm
## 1 380 3.61    3  no
## 2 660 3.67    3  si
## 3 800 4.00    1  si
## 4 640 3.19    4  si
## 5 520 2.93    4  no
## 6 760 3.00    2  si

Realizamos la discretización:

data_dis <-disc.Topdown(data, method = 1) #data
data_dis$cutp #Intervalos
## [[1]]
## [1] 220 750 800
## 
## [[2]]
## [1] 2.260 3.415 4.000
## 
## [[3]]
## [1] 1.0 1.5 4.0
head(data_dis$Disc.data)
##   gre gpa rank adm
## 1   1   2    2  no
## 2   1   2    2  si
## 3   2   2    1  si
## 4   1   1    2  si
## 5   1   1    2  no
## 6   2   1    2  si

Hay que recordar que para exportar los datos utilizamos write.cvs() espesificando la ruta de la PC en file =:

nueva_data <- data_dis$Disc.data
write.csv(nueva_data, file = "nueva_data.csv")

Hay que recordar que una vez exportada la base se recomienda revizar la base y editarla de ser necesario en caso que pudiera tener algún error en la exportación.

Bibliografía

Forina, M. et al (1988) “PARVUS - An Extendible Package for Data Exploration, Classification and Correlation.” Institute of Pharmaceutical and Food Analysis and Technologies, Via Brigata Salerno, 16147 Genoa, Italy.