02/05/24
Abstract
En Rpubs:: toc se pueden ver otros documentos de posible interés.
library(aplore3) #Base de datos para los ejemplos
library(lsm) #Base de datos para ejemplos y estimaciones del Log-verosimilitud
library(tidyverse) #Incluye a dplyr y ggplot2
library(stringr) #Reemplazar caracteres en un data frame
library(outliers) #outliers::grubbs.test
library(EnvStats) #EnvStats::rosnerTest
library(DMwR2) #LOF (Local Outlier Factor)
library(rgl) #rgl::plot3d
La detección de valores atípicos (outliers) en datos es un área importante en estadísticas y análisis de datos. Hay varios métodos para identificar valores atípicos. Un valor se considera atípico si está significativamente por encima o por debajo de ciertos umbrales basados en medidas estadísticas.
En general, los valores atípicos pueden clasificarse en tres categorías:
Valor atípico global: el objeto se desvía significativamente del resto del conjunto de datos.
Valor atípico contextual: el objeto se desvía significativamente en función de un contexto seleccionado. Por ejemplo, 28⁰C es un valor atípico para un invierno en Rusia, pero no lo es en otro contexto. Además, 28⁰C no es un valor atípico para un verano rusoa.
Valor atípico multivariado o colectivo: un subconjunto de objetos de datos se desvía colectivamente de forma significativa del conjunto de datos, aunque los objetos de datos individuales no sean valores atípicos. Son puntos de datos atípicos cuando se consideran simultáneamente varios atributos o dimensiones. Por ejemplo, un gran conjunto de transacciones de la misma acción entre un pequeño grupo en un periodo corto puede considerarse una prueba de manipulación del mercado.
datosCompleto <- lsm::survey
dat <- datosCompleto[,3:10]
attach(dat)
En las siguientes secciones se van a explicar varios métodos.
ggplot(dat) +
aes(x =Age) +
geom_histogram(bins = 30L, color = "red", fill = "#0c4c8a") +
facet_wrap(~"Diagrama de caja y bigotes para la edad") +
theme(legend.position="none") +
theme_bw(base_size = 11) + # Tamaño de las fuentes
theme(axis.text.x = element_text(angle = 0#, vjust = 1.0, hjust=1
)
) #+
Según el histograma, parece que hay observaciones con valores muy grande en comparación con el resto (véase la barra de la derecha del gráfico).
Además de los histogramas, los gráficos de caja también son útiles para detectar posibles valores atípicos.
ggplot(dat) +
aes(x = Age, y = "") +
geom_boxplot(fill = "blue") +
xlim(10,32)+
facet_wrap(~"Diagrama de caja y bigotes para la edad") +
theme(legend.position="none") +
theme_bw(base_size = 11) + # Tamaño de las fuentes
theme(axis.text.x = element_text(angle = 0#, vjust = 1.0, hjust=1
)
) #+
Un boxplot ayuda a visualizar una variable cuantitativa mostrando cinco resumen de localización comunes (mínimo, mediana, primer y tercer cuartil y máximo) y cualquier observación que se haya clasificado como presunto valor atípico utilizando el criterio del rango intercuartílico (IQR).
Las observaciones consideradas como posibles valores atípicos por el criterio IQR se muestran como puntos en el boxplot. Según este criterio, hay 4 valores atípicos potenciales (véanse los 4 puntos al lado derecho de la línea horizontal).
Recuerde que el hecho de que una observación se considere un valor atípico potencial según el criterio IQR no significa que deba eliminarla.
Eliminar o mantener un valor atípico depende de:
El contexto de su análisis.
Si las pruebas que va a realizar en el conjunto de datos son robustas o no a los valores atípicos.
Y la distancia entre el valor atípico y las demás observaciones.
También es posible extraer los valores de los posibles valores atípicos basándose en el criterio IQR gracias a la siguiente función:
boxplot.stats(Age)$out
## [1] 24.91 27.88 29.85 28.76
Como se puede ver, hay 3 puntos considerados como valores atípicos potenciales.
###Extraer filas de los valores atípicos
Gracias a la función which()
es posible extraer el número de fila correspondiente a estos valores atípicos:
out_box <- boxplot.stats(Age)$out
out_ind_box <- which(Age %in% c(out_box))
out_ind_box
## [1] 19 37 141 383
Con esta información, ahora puede volver fácilmente a las filas específicas del conjunto de datos para verificarlas, o imprimir todas las variables de estos valores atípicos:
dat[out_ind_box, ]
Gender | Like | Age | Smoke | Height | Weight | BMI | School |
---|---|---|---|---|---|---|---|
Male | TV | 24.91 | No | 1.65 | 90 | 33.05785 | Private |
Female | Network | 27.88 | Yes | 1.63 | 55 | 20.70082 | Private |
Female | TV | 29.85 | No | 1.65 | 88 | 32.32323 | Private |
Male | Network | 28.76 | Yes | 1.65 | 54 | 19.83471 | Private |
También es posible imprimir los valores de los valores atípicos directamente en boxplot con la función mtext()
:
boxplot(Age, col = "blue",
xlab = "Age",
main = "Boxplot of Age", horizontal=TRUE)
mtext(paste("Outliers: ", paste(out_box, collapse = ", ")))
Este método de detección de valores atípicos se basa en los percentiles. Con el método de los percentiles, todas las observaciones que se encuentren fuera del intervalo formado por los percentiles 2,5 y 97,5 se considerarán valores atípicos potenciales.
También pueden considerarse otros percentiles, como el 1 y el 99, o el 5 y el 95, para construir el intervalo.
Los valores de los percentiles inferior y superior (y, por tanto, los límites inferior y superior del intervalo) pueden calcularse con la función quantile()
:
low_perc <- quantile(Age, 0.025, na.rm=TRUE)
low_perc
## 2.5%
## 12.87925
up_perc <- quantile(Age, 0.975, na.rm=TRUE)
up_perc
## 97.5%
## 21.6545
Según este método, todas las observaciones por debajo de 12.87925 y por encima de 21.6545 se considerarán valores atípicos potenciales.
A continuación, los números de fila de las observaciones fuera del intervalo pueden extraerse con la función which()
:
out_ind_perc <- which(Age < low_perc | Age > up_perc)
out_ind_perc
## [1] 19 30 32 37 55 81 90 109 141 150 151 165 213 233 242 309 331 367 376
## [20] 380 383 416 462 478 484 485 493 503 507 564 580 601 637 653 676 731 750 784
## [39] 788 793
A continuación, se pueden imprimir los valores de la edad:
dat[out_ind_perc, "Age"]
Age |
---|
24.91 |
21.85 |
21.78 |
27.88 |
21.82 |
21.74 |
21.89 |
21.87 |
29.85 |
21.75 |
21.84 |
21.71 |
21.89 |
21.73 |
21.80 |
12.04 |
21.83 |
21.72 |
21.76 |
21.72 |
28.76 |
12.50 |
12.80 |
12.64 |
12.78 |
12.84 |
12.66 |
12.76 |
12.80 |
12.79 |
12.68 |
12.71 |
12.76 |
12.52 |
12.79 |
12.51 |
12.87 |
12.59 |
12.58 |
12.63 |
Alternativamente, se pueden imprimir todas las variables de estos valores atípicos:
dat[out_ind_perc, ]
Gender | Like | Age | Smoke | Height | Weight | BMI | School |
---|---|---|---|---|---|---|---|
Male | TV | 24.91 | No | 1.65 | 90 | 33.05785 | Private |
Female | Network | 21.85 | Yes | 1.53 | 59 | 25.20398 | Public |
Male | Network | 21.78 | Yes | 1.65 | 59 | 21.67126 | Public |
Female | Network | 27.88 | Yes | 1.63 | 55 | 20.70082 | Private |
Female | Network | 21.82 | Yes | 1.62 | 82 | 31.24524 | Private |
Male | TV | 21.74 | No | 1.88 | 80 | 22.63468 | Private |
Male | TV | 21.89 | No | 1.64 | 87 | 32.34682 | Public |
Male | TV | 21.87 | Yes | 1.80 | 50 | 15.43210 | Private |
Female | TV | 29.85 | No | 1.65 | 88 | 32.32323 | Private |
Male | Network | 21.75 | Yes | 1.69 | 80 | 28.01022 | Public |
Female | Network | 21.84 | No | 1.58 | 75 | 30.04326 | Private |
Female | Network | 21.71 | No | 1.72 | 86 | 29.06977 | Private |
Male | Network | 21.89 | Yes | 1.81 | 74 | 22.58783 | Private |
Male | Network | 21.73 | Yes | 1.62 | 54 | 20.57613 | Private |
Female | Network | 21.80 | Yes | 1.71 | 80 | 27.35885 | Public |
Male | Network | 12.04 | Yes | 1.60 | 50 | 19.53125 | Private |
Male | TV | 21.83 | No | 1.82 | 80 | 24.15167 | Private |
Male | TV | 21.72 | No | 1.78 | 75 | 23.67125 | Private |
Male | Network | 21.76 | No | 1.87 | 84 | 24.02128 | Public |
Female | Network | 21.72 | Yes | 1.50 | 59 | 26.22222 | Public |
Male | Network | 28.76 | Yes | 1.65 | 54 | 19.83471 | Private |
Male | TV | 12.50 | Yes | 1.76 | 72 | 23.24380 | Private |
Female | TV | 12.80 | Yes | 1.78 | 65 | 20.51509 | Private |
Female | TV | 12.64 | No | 1.62 | 56 | 21.33821 | Public |
Female | Network | 12.78 | No | 1.70 | 55 | 19.03114 | Public |
Female | Network | 12.84 | No | 1.64 | 51 | 18.96193 | Private |
Male | Network | 12.66 | No | 1.64 | 92 | 34.20583 | Private |
Male | Network | 12.76 | Yes | 1.80 | 77 | 23.76543 | Public |
Male | Network | 12.80 | No | 1.66 | 71 | 25.76571 | Private |
Male | Network | 12.79 | No | 1.79 | 73 | 22.78331 | Private |
Female | Network | 12.68 | No | 1.66 | 83 | 30.12048 | Public |
Female | Network | 12.71 | No | 1.72 | 100 | 33.80206 | Public |
Male | TV | 12.76 | No | 1.68 | 56 | 19.84127 | Public |
Male | TV | 12.52 | No | 1.75 | 82 | 26.77551 | Public |
Male | Network | 12.79 | Yes | 1.76 | 71 | 22.92097 | Public |
Male | Network | 12.51 | Yes | 1.62 | 59 | 22.48133 | Private |
Female | Network | 12.87 | Yes | 1.67 | 59 | 21.15529 | Private |
Female | TV | 12.59 | Yes | 1.62 | 75 | 28.57796 | Private |
Male | Network | 12.58 | Yes | 1.77 | 74 | 23.62029 | Public |
Male | Network | 12.63 | Yes | 1.75 | 51 | 16.65306 | Private |
Hay 40 valores atípicos potenciales según el método de los percentiles.
Para reducir este número, puede establecer los percentiles en 0.5% y 99.5%:
low_perc <- quantile(Age, 0.005, na.rm=TRUE)
up_perc <- quantile(Age, 0.995, na.rm=TRUE)
out_ind_perc <- which(Age < low_perc | Age > up_perc)
dat[out_ind_perc, ]
Gender | Like | Age | Smoke | Height | Weight | BMI | School |
---|---|---|---|---|---|---|---|
Male | TV | 24.91 | No | 1.65 | 90 | 33.05785 | Private |
Female | Network | 27.88 | Yes | 1.63 | 55 | 20.70082 | Private |
Female | TV | 29.85 | No | 1.65 | 88 | 32.32323 | Private |
Male | Network | 12.04 | Yes | 1.60 | 50 | 19.53125 | Private |
Male | Network | 28.76 | Yes | 1.65 | 54 | 19.83471 | Private |
Male | TV | 12.50 | Yes | 1.76 | 72 | 23.24380 | Private |
Male | TV | 12.52 | No | 1.75 | 82 | 26.77551 | Public |
Male | Network | 12.51 | Yes | 1.62 | 59 | 22.48133 | Private |
Si se fijan los percentiles en 0.5% y 99.5%, además de los valores atípicos potenciales obtenidos con el criterio QR, se obtienen otros.
Si sus datos proceden de una distribución normal, puede utilizar las puntuaciones \(z\), lo que puede hacerse con la función scale()
de R. Según este método, cualquier puntuación \(z\) inferior a -2 o superior a 2 se considera rara inferior a -3 o superior a 3 se considera extremadamente rara.
Otros también utilizan una puntuación z inferior a -3.29 o superior a 3.29 para detectar valores atípicos. Este valor de 3.29 proviene del hecho de que 1 observación de cada 1000 está fuera de este intervalo si los datos siguen una distribución normal.
En nuestro caso,
dat$Z_age <- scale(Age)
Z_age <-dat$Z_age
hist(Z_age, col = "blue")
library(ggplot2)
ggplot(dat) +
aes(x = Z_age) +
geom_histogram(bins = 30L, color = "red", fill = "#0c4c8a") +
theme_minimal()
summary(Z_age)
## V1
## Min. :-2.21441
## 1st Qu.:-0.60608
## Median : 0.06339
## Mean : 0.00000
## 3rd Qu.: 0.67757
## Max. : 4.94669
## NA's :2
Vemos que hay algunas observaciones por encima de 3.29, pero ninguna por debajo de -3.29.
Identificar la fila en el conjunto de datos de estas observaciones:
which(Z_age < -3.29 | Z_age > 3.29)
## [1] 37 141 383
Vemos que las observaciones 37, 141 y 383 pueden considerarse valores atípicos según este método.
Otro método, conocido como filtro de Hampel, consiste en considerar como valores atípicos los valores situados fuera del intervalo formado por la mediana, más o menos 3 desviaciones absolutas de la mediana.
Para este método fijamos primero los límites del intervalo gracias a las funciones median()
y mad()
:
low_hampel <- median(Age, na.rm=TRUE) - 3 * mad(Age, constant = 1, na.rm=TRUE)
low_hampel
## [1] 12.89
up_hampel <- median(Age, na.rm=TRUE) + 3 * mad(Age, constant = 1, na.rm=TRUE)
up_hampel
## [1] 22.52
Según este método, todas las observaciones inferiores a 12.89 y superiores a 22.52 se considerarán valores atípicos potenciales.
A continuación, los números de fila de las observaciones fuera del intervalo pueden extraerse con la función which()
:
out_ind_hampel <- which(Age < low_hampel | Age > up_hampel)
out_ind_hampel
## [1] 19 37 141 309 383 416 462 478 484 485 493 503 507 520 564 580 601 637 653
## [20] 676 731 750 784 788 793
De acuerdo al filtro de Hampel, hay 25 valores atípicos para la variable Age
.
En esta sección, se presentarán 3 técnicas más formales para detectar valores atípicos:
Prueba de Grubbs.
Prueba de Dixon.
Prueba de Rosner.
Estas 3 pruebas estadísticas forman parte de técnicas más formales de detección de valores atípicos, ya que todas implican el cálculo de un estadístico de prueba que se compara con valores críticos tabulados (que se basan en el tamaño de la muestra y el nivel de confianza deseado).
Debe tenerse en cuenta que las 3 pruebas sólo son adecuadas cuando los datos (sin valores atípicos) tienen una distribución aproximadamente normal. Por lo tanto, debe verificarse el supuesto de normalidad antes de aplicar estas pruebas de valores atípicos (consulte cómo probar el supuesto de normalidad en R).
La prueba de Grubbs permite detectar si el valor más alto o más bajo de un conjunto de datos es un valor atípico. Las hipótesis nula y alternativa son las siguientes:
Si queremos comprobar el valor más alto:
Hipótesis nula: El valor más alto no es un valor atípico.
Hipótesis alternativa: El valor más alto es un valor atípico.
Si queremos probar el valor más bajo:
Hipótesis nula: El valor más bajo no es un valor atípico.
Hipótesis alternativa: El valor más bajo es un valor atípico.
Como en cualquier prueba estadística, si el valor p es inferior al umbral de significación elegido (generalmente \(\alpha\) = 0.05), se rechaza la hipótesis nula y se concluye que el valor más bajo/más alto es un valor atípico.
Por el contrario, si el valor p es mayor o igual que el nivel de significación, no se rechaza la hipótesis nula y concluiremos que, basándonos en los datos, no rechazamos la hipótesis de que el valor más bajo/más alto no es un valor atípico.
Debe tener en cuenta que la prueba de Grubbs no es adecuada para muestras de 6 o menos (n≤6).
Para realizar la prueba de Grubbs en R, utilizamos la función grubbs.test()
del paquete outliers
:
#install.packages("outliers")
#library(outliers)
test <- grubbs.test(Age)
test
##
## Grubbs test for one outlier
##
## data: Age
## G = 4.94669, U = 0.96926, p-value = 0.0002488
## alternative hypothesis: highest value 29.85 is an outlier
El valor p es 0.0002488. Al nivel de significación del 5%, rechazamos la hipótesis de que el valor 29.85 más alto es un valor atípico.
Por defecto, la prueba se realiza en el valor más alto (como se muestra en la última línea de la salida de R).
max(dat$Age)
## [1] NA
Si desea realizar la prueba para el valor más bajo, simplemente se añade el argumento opposite = TRUE
en la función grubbs.test()
:
test <- grubbs.test(Age, opposite = TRUE)
test
##
## Grubbs test for one outlier
##
## data: Age
## G = 2.21441, U = 0.99384, p-value = 1
## alternative hypothesis: lowest value 12.04 is an outlier
La salida de R indica que la prueba se realiza ahora sobre el valor más bajo (véase la hipótesis alternativa: el valor más bajo 12.04 es un valor atípico).
El valor p es 1. Al nivel de significación del 5%, no rechazamos la hipótesis de que el valor más bajo 12.04 no sea un valor atípico.
De forma similar a la prueba de Grubbs, la prueba de Dixon se utiliza para comprobar si un único valor bajo o alto es un valor atípico. Por lo tanto, si se sospecha que hay más de un valor atípico, la prueba debe realizarse individualmente para cada uno de ellos.
Tenga en cuenta que la prueba de Dixon es más útil para muestras pequeñas (normalmente \(n \leq 25\)).
Para realizar la prueba de Dixon en R, utilizamos la función dixon.test()
del paquete outliers
. Sin embargo, restringimos nuestro conjunto de datos a las 30 primeras observaciones, ya que la prueba de Dixon sólo puede realizarse en muestras de pequeño tamaño (R arrojará un error y sólo acepta conjuntos de datos de 3 a 30 observaciones):
subdat <- dat[1:30, ]
test <- dixon.test(subdat$Age)
test
##
## Dixon test for outliers
##
## data: subdat$Age
## Q = 0.38443, p-value = 0.08647
## alternative hypothesis: highest value 24.91 is an outlier
Los resultados muestran que el valor más alto, 24.91, no es un valor atípico (valor p >0.05).
Para comprobar el valor más bajo, basta con añadir el argumento opposite = TRUE
a la función dixon.test()
:
test <- dixon.test(subdat$Age, opposite = TRUE)
test
##
## Dixon test for outliers
##
## data: subdat$Age
## Q = 0.072824, p-value = 0.2327
## alternative hypothesis: lowest value 16.02 is an outlier
Los resultados muestran que el valor más bajo, 16.02, no es un valor atípico (valor p >0.05).
Es una buena práctica comprobar siempre los resultados de la prueba estadística de valores atípicos con el diagrama de caja para asegurarse de que hemos comprobado todos los valores atípicos potenciales:
out_dixon <- boxplot.stats(subdat$Age)$out
boxplot(subdat$Age,col = "blue",
ylab = "Age"
)
mtext(paste("Outliers: ", paste(out_dixon, collapse = ", ")))
A partir del diagrama de caja, podríamos aplicar la prueba de Dixon sobre el segundo valor menor no atípico, quitando el menor valor (en este caso, no sucederá nada porqu eno hay valore atípicos). Esto se puede hacer encontrando el número de fila del valor mínimo, excluyendo este número de fila del conjunto de datos y, por último, aplicando la prueba de Dixon a este nuevo conjunto de datos:
# find and exclude lowest value
remove_ind <- which.min(subdat$Age)
subsubdat <- subdat[-remove_ind, ]
# Dixon test on dataset without the minimum
test <- dixon.test(subsubdat$Age)
test
##
## Dixon test for outliers
##
## data: subsubdat$Age
## Q = 0.3942, p-value = 0.07922
## alternative hypothesis: highest value 24.91 is an outlier
La prueba de Rosner para detectar valores atípicos tiene las ventajas de que:
1. Se utiliza para detectar varios valores atípicos a la vez (a diferencia de la prueba de Grubbs y Dixon, que debe realizarse de forma iterativa para detectar múltiples valores atípicos).
2. Está diseñada para evitar el problema del enmascaramiento, en el que un valor atípico cercano a otro valor atípico puede pasar desapercibido.
A diferencia de la prueba de Dixon, la prueba de Rosner es más adecuada cuando el tamaño de la muestra es grande (\(n \geq 20\)). Por lo tanto, volvemos a utilizar el conjunto de datos inicial dat
, que incluye todas las observaciones.
Para realizar la prueba de Rosner utilizamos la función rosnerTest()
del paquete EnvStats
. Esta función requiere al menos 2 argumentos: los datos y el número de presuntos valores atípicos \(k\) (con \(k = 3\) como número predeterminado de presuntos valores atípicos).
Para este ejemplo, fijamos el número de presuntos valores atípicos en \(4\), tal y como sugiere el número de posibles valores atípicos esbozados en el diagrama de caja al principio del documento.
#install.packages("EnvStats")
#library(EnvStats)
test <- rosnerTest(dat$Age, k = 4)
test
##
## Results of Outlier Test
## -------------------------
##
## Test Method: Rosner's Test for Outliers
##
## Hypothesized Distribution: Normal
##
## Data: dat$Age
##
## Number NA/NaN/Inf's Removed: 2
##
## Sample Size: 798
##
## Test Statistics: R.1 = 4.946687
## R.2 = 4.582779
## R.3 = 4.283665
## R.4 = 3.095325
##
## Test Statistic Parameter: k = 4
##
## Alternative Hypothesis: Up to 4 observations are not
## from the same Distribution.
##
## Type I Error: 5%
##
## Number of Outliers Detected: 3
##
## i Mean.i SD.i Value Obs.Num R.i+1 lambda.i+1 Outlier
## 1 0 17.54734 2.487050 29.85 141 4.946687 3.983760 TRUE
## 2 1 17.53191 2.450062 28.76 383 4.582779 3.983444 TRUE
## 3 2 17.51780 2.419003 27.88 37 4.283665 3.983128 TRUE
## 4 3 17.50477 2.392393 24.91 19 3.095325 3.982811 FALSE
Los resultados interesantes se ofrecen en la tabla $all.stats
:
test$all.stats
i | Mean.i | SD.i | Value | Obs.Num | R.i+1 | lambda.i+1 | Outlier |
---|---|---|---|---|---|---|---|
0 | 17.54734 | 2.487050 | 29.85 | 141 | 4.946687 | 3.983760 | TRUE |
1 | 17.53191 | 2.450062 | 28.76 | 383 | 4.582779 | 3.983444 | TRUE |
2 | 17.51780 | 2.419003 | 27.88 | 37 | 4.283665 | 3.983128 | TRUE |
3 | 17.50477 | 2.392393 | 24.91 | 19 | 3.095325 | 3.982811 | FALSE |
Basándonos en la prueba de Rosner, vemos que sólo hay 3 valores atípicos porque sale TRUE
en la última columna Outlier
de la tabla. En este caso, se tratan de las observaciones 37, 383 y 141 (véase Obs.Num
) con valores de 27.88, 28.76 y 29.85 (véase Value
), respectivamente.
El algoritmo Local Outlier Factor (LOF) es un método no supervisado de detección de anomalías que calcula la desviación de la densidad local de un punto de datos dado con respecto a sus vecinos. Considera como valores atípicos las muestras que tienen una densidad sustancialmente inferior a la de sus vecinos.
Las técnicas de detección de valores atípicos basadas en la proximidad se dividen en dos categorías principales:
Detección de valores atípicos basada en la densidad.
Detección de valores atípicos basada en la distancia.
En general, en la técnica de detección de valores atípicos basada en la proximidad, se considera que un objeto es un valor atípico si está alejado de la mayoría de los demás puntos.
Este enfoque es más general y sencillo que los enfoques estadísticos, ya que es más fácil determinar una medida de proximidad significativa para un conjunto de datos que determinar su distribución estadística.
En esta sección nos centraremos únicamente en la técnica de detección de valores atípicos basada en la densidad. La forma más sencilla de medir si un objeto está alejado de la mayoría de los demás puntos del conjunto de datos es utilizar la distancia al \(k\)-próximo más cercano o el LOF (Local Outlier Factor).
El método LOF se basa en puntuar los valores atípicos en función de la densidad en el vecindario. Esta técnica se basa en un parámetro conocido como puntuación de valores atípicos (outlier score
). La puntuación de un objeto atípico es el recíproco de la densidad en el vecindario del objeto (la densidad es la distancia media a los vecinos más cercanos).
En la técnica LOF, la densidad local de un punto se compara con la de sus vecinos. Si la primera es significativamente menor que la segunda, es decir, si LOF es mayor que uno, el punto se encuentra en una región más dispersa que sus vecinos, lo que sugiere que se trata de un valor atípico.
La única limitación de LOF es que sólo funciona con datos numéricos.
En R, en el paquete DMwR
hay una función lofactor()
que calcula los factores atípicos locales utilizando el algoritmo LOF.
#remotes::install_github("cran/DMwR")
library(DMwR2)
Los datos se recogieron aplicando una encuesta a una muestra de estudiantes universitarios.
datosCompleto <- lsm::survey
attach(datosCompleto)
Es un data frame con 800 observaciones y 66 variables:
names(datosCompleto)
## [1] "Observation" "ID" "Gender" "Like" "Age"
## [6] "Smoke" "Height" "Weight" "BMI" "School"
## [11] "SES" "Enrollment" "Score" "MotherHeight" "MotherAge"
## [16] "MotherCHD" "FatherHeight" "FatherAge" "FatherCHD" "Status"
## [21] "SemAcum" "Exam1" "Exam2" "Exam3" "Exam4"
## [26] "ExamAcum" "Definitive" "Expense" "Income" "Gas"
## [31] "Course" "Law" "Economic" "Race" "Region"
## [36] "EMO1" "EMO2" "EMO3" "EMO4" "EMO5"
## [41] "GOAL1" "GOAL2" "GOAL3" "Pre_STAT1" "Pre_STAT2"
## [46] "Pre_STAT3" "Pre_STAT4" "Post_STAT1" "Post_STAT2" "Post_STAT3"
## [51] "Post_STAT4" "Pre_IDARE1" "Pre_IDARE2" "Pre_IDARE3" "Pre_IDARE4"
## [56] "Pre_IDARE5" "Post_IDARE1" "Post_IDARE2" "Post_IDARE3" "Post_IDARE4"
## [61] "Post_IDARE5" "PSICO1" "PSICO2" "PSICO3" "PSICO4"
## [66] "PSICO5"
Con estos datos, trataremos de identificar los valores atípicos en el conjunto de datos mencionado utilizando el algoritmo LOF. Para ello, necesitamos obtener algunos datos numéricos de este conjunto de datos:
# get numeric columns using dplyr() function
dat <- select_if(datosCompleto, is.numeric)
names(dat)
## [1] "Observation" "Age" "Height" "Weight" "BMI"
## [6] "Score" "MotherAge" "MotherCHD" "FatherAge" "FatherCHD"
## [11] "SemAcum" "Exam1" "Exam2" "Exam3" "Exam4"
## [16] "ExamAcum" "Definitive" "Expense" "Income" "Gas"
## [21] "EMO1" "EMO2" "EMO3" "EMO4" "EMO5"
## [26] "Pre_STAT1" "Pre_STAT2" "Pre_STAT3" "Pre_STAT4" "Post_STAT1"
## [31] "Post_STAT2" "Post_STAT3" "Post_STAT4"
#dat_num <-dat[,c(2,3,6,12,19)]
dat_num <- na.omit(dat[,c(2,3,6,12,19)])
attach(dat_num)
names(dat_num)
## [1] "Age" "Height" "Score" "Exam1" "Income"
Ahora obtendremos la puntuación de los valores atípicos con \(k= 7\) (se puede “jugar” cambiando este número).
## [1] 1.4026230 1.0619596 1.0316504 1.0056654 0.9953993 0.9823177 0.9898877
## [8] 0.9918855 0.9984843 1.0061247 1.0590509 1.0248310 1.0275860 0.9665033
## [15] 0.9787895 0.9793029 1.0071739 1.1118235 2.3878823 0.9834475 0.9925646
## [22] 0.9898602 0.9944061 1.0829753 1.0321800 1.0606849 1.0303762 1.0059530
## [29] 1.1654133 1.0167858 1.2924968 1.1548130 1.1020300 1.0212932 1.0242093
## [36] 0.9705743 2.9104686 1.1376481 1.0495141 0.9944060 1.1087530 1.0128771
## [43] 1.0635620 1.0050146 0.9982726 0.9473382 0.9960751 1.0015551 1.0087514
## [50] 1.0223266 1.0101924 1.0133967 1.0234448 1.0333744 1.0918950 1.0198649
## [57] 0.9994641 1.0049608 0.9980829 1.0983885 1.0955723 0.9809427 1.0222187
## [64] 0.9765732 1.0072988 1.0868215 0.9478462 1.0318391 0.9666088 1.1416123
## [71] 1.0088030 1.1048294 1.1846529 0.9649793 0.9913576 1.0386493 0.9989650
## [78] 1.0821781 1.0061429 1.0616892 1.1727934 1.0173856 0.9811507 1.0217221
## [85] 1.0002308 1.0642125 1.0065970 1.0767250 0.9684638 1.2464851 1.0179074
## [92] 0.9686664 1.2903373 1.0646654 0.9838721 1.0099556 1.0638540 1.1505956
## [99] 0.9516724 1.0150176 1.2577339 1.0794116 1.0081777 0.9594014 1.0288116
## [106] 1.0066864 1.0052537 0.9991451 1.0414449 0.9908985 0.9980186 1.1461109
## [113] 1.0077373 1.1325761 0.9633165 0.9816842 1.2591742 1.0055665 1.1847754
## [120] 1.0215987 0.9857177 0.9832192 1.0477870 1.1296951 1.0508046 1.0162942
## [127] 0.9851260 0.9764242 0.9800485 0.9948392 1.0179174 1.0432785 0.9513276
## [134] 0.9653916 0.9856247 1.2911322 0.9527877 0.9777723 1.0954625 1.0253957
## [141] 3.8512180 1.0172217 1.0235467 0.9890704 1.0270199 1.0499001 0.9892276
## [148] 1.0370951 1.0075576 1.0941093 0.9958176 0.9957885 1.0180032 0.9868883
## [155] 0.9804026 0.9781390 1.0299175 1.1983281 0.9680299 0.9586617 1.0860450
## [162] 1.0093496 1.0459585 1.0347848 1.4630536 1.0710260 1.0020347 0.9889634
## [169] 1.2178421 1.1534945 0.9593807 1.0955034 0.9354596 1.0148837 1.0140448
## [176] 1.0779627 1.2721217 0.9889741 1.0008796 0.9720254 1.0497547 0.9851066
## [183] 1.1569688 1.0061985 0.9864084 0.9961062 1.0086997 1.0045567 1.0669498
## [190] 1.1552061 1.0688751 0.9648927 1.0696422 1.1159710 0.9925560 1.1208508
## [197] 0.9485097 1.0523715 1.0533085 1.0863404 0.9633985 1.1528576 1.0332994
## [204] 0.9666771 1.0849465 1.0046256 1.0600730 1.0077441 1.0016680 0.9657894
## [211] 1.1142667 1.0101283 1.2157554 0.9997833 1.0158917 0.9836085 1.0147705
## [218] 0.9770646 1.0619206 1.0534748 1.0107139 0.9954589 1.2185043 1.0263619
## [225] 1.0402427 1.1293837 0.9883427 1.1097477 1.0723298 1.0365153 1.0108074
## [232] 1.1429447 1.1567431 1.0044618 1.0000381 0.9755145 0.9814793 0.9888630
## [239] 0.9779175 1.2252034 0.9726094 1.4221783 1.3179644 1.0006366 1.2079902
## [246] 1.1502429 0.9863692 0.9983116 1.0483158 1.1648788 0.9978443 0.9787310
## [253] 1.0353671 0.9974131 1.0409729 0.9890875 1.0100892 1.0118005 1.0367602
## [260] 1.0651623 0.9845056 1.1778566 1.0367300 1.0175075 1.0658369 1.0416235
## [267] 0.9493710 1.0226488 1.0440164 1.0421078 1.0040911 1.0342798 1.0459064
## [274] 1.0030143 0.9955931 0.9659278 1.0456524 1.1974954 0.9470577 1.1170641
## [281] 1.0248774 0.9912545 1.0752818 1.0248011 0.9640223 1.1287609 1.0011066
## [288] 1.1729367 0.9376976 1.0048093 0.9957369 1.0618855 1.2537667 0.9924252
## [295] 1.0953991 1.0026622 1.0320831 1.0109453 0.9962359 1.0384624 0.9907687
## [302] 1.0160522 0.9413869 1.0028396 0.9992171 1.0273497 1.1920514 0.9953429
## [309] 1.3349608 1.0244356 1.0012517 1.0470195 1.0545229 1.0293404 1.0025591
## [316] 0.9700601 1.0093291 1.0017025 1.0953383 1.0251374 1.1438950 0.9882199
## [323] 1.2445794 1.1962482 1.0174794 0.9971341 0.9892574 1.3908174 0.9902291
## [330] 0.9546039 1.0661800 1.0071211 0.9836296 1.0080651 0.9710849 1.0461167
## [337] 1.0106497 0.9501875 1.0108688 1.0257266 1.0916877 0.9768981 0.9966830
## [344] 0.9522847 0.9680673 0.9700874 1.0058954 0.9790320 0.9817682 0.9556836
## [351] 0.9544986 1.0354461 0.9843651 1.0948079 1.0345736 0.9577759 1.0365673
## [358] 1.0109472 0.9977611 1.0635773 1.0660916 1.0266231 0.9964029 0.9715991
## [365] 0.9994907 1.0829627 1.0049583 0.9989715 0.9863707 1.0012103 0.9543856
## [372] 0.9818725 0.9929811 1.0261677 0.9768110 1.0487521 0.9772802 0.9993587
## [379] 1.0213422 1.0207513 1.0057383 0.9816345 3.3382646 1.0243640 1.0172329
## [386] 1.0044354 1.0163987 1.0258365 1.0051209 1.0241427 1.0018646 0.9903671
## [393] 1.0317103 0.9550695 1.0145954 1.1703997 1.0081685 1.1425166 1.0323980
## [400] 0.9881991 0.9690609 1.1407888 0.9930251 1.1192735 0.9480838 1.0153014
## [407] 1.0435463 1.0312993 0.9692083 1.1802180 1.0490959 1.0391855 0.9946505
## [414] 1.0184282 1.0318696 1.1660042 1.0801900 1.1370402 1.0141774 1.0201376
## [421] 0.9914951 1.0389611 1.0015919 0.9534384 1.0215780 1.0444365 0.9890530
## [428] 1.0587447 1.0845374 0.9605421 1.0153465 1.2227086 0.9776239 0.9993794
## [435] 1.0410165 0.9963123 1.4447991 1.0281165 0.9998328 0.9758324 0.9653247
## [442] 0.9850855 1.0406799 0.9722626 1.0668592 0.9924719 0.9470380 1.0427028
## [449] 0.9660365 1.0863503 1.0465290 1.0171202 1.0628123 1.0953044 0.9925704
## [456] 0.9812946 1.0047628 1.0034055 1.0028010 1.1164749 1.1119459 1.0468546
## [463] 1.0635434 1.0772076 1.0167472 1.0217359 0.9963084 1.0149292 1.1329096
## [470] 0.9984818 0.9797474 1.0941116 1.0169026 1.0072484 1.0110031 1.0011106
## [477] 1.0433650 1.1133612 0.9882243 1.0117282 1.0004027 1.0626346 1.1459655
## [484] 1.0015634 0.9880445 1.0128858 0.9948389 1.2498047 1.2869326 1.1399327
## [491] 1.0249878 1.0654323 1.2617938 1.0423947 1.0120343 1.0058536 1.0558582
## [498] 1.0011536 0.9878626 1.0904977 1.0595779 1.0497301 1.1409866 1.0084134
## [505] 1.0340165 0.9916131 1.0645925 1.1497868 0.9970446 1.0481412 1.0596220
## [512] 1.0252055 0.9701523 1.1678775 1.0858131 1.1019319 0.9875698 1.1804939
## [519] 1.1310272 1.1574534 1.0073103 1.0338155 1.0499535 1.0206629 0.9703335
## [526] 1.0941500 0.9917080 1.1310087 1.0321024 1.1103095 1.0862437 0.9761956
## [533] 1.0330583 1.0491563 1.2048782 1.0299143 1.1951320 1.0264469 1.2203593
## [540] 1.1133234 0.9675178 1.0206242 1.0677766 1.0858337 1.0271078 1.0128762
## [547] 1.0099020 1.0351955 1.0713099 1.0155020 1.3899521 1.0105374 1.0320481
## [554] 1.0001863 1.0586568 0.9649813 0.9813870 0.9834187 1.1117350 1.1117007
## [561] 1.0190378 0.9748324 0.9821826 1.1762409 1.0050723 0.9588067 1.0136077
## [568] 1.3985471 1.0079192 1.0755431 1.1284642 0.9856295 1.0413141 0.9917961
## [575] 0.9851828 1.1860542 1.0322817 1.0040960 0.9791677 1.1394441 1.0402248
## [582] 1.0003591 1.0303873 1.1931992 1.3608937 1.0411869 1.0157150 1.1729108
## [589] 1.2154448 0.9952440 1.3956017 1.2782088 0.9883668 1.0153890 0.9742676
## [596] 1.0028662 1.0388652 1.0264601 0.9885018 1.0698662 1.0524828 1.1117141
## [603] 0.9767319 1.0132716 1.0140089 1.3175474 0.9813986 1.0254096 0.9873907
## [610] 1.0511987 1.0686573 1.0135989 0.9634352 1.2525199 1.2017720 1.0276117
## [617] 1.0651185 1.1301634 0.9492676 0.9766296 1.0238985 1.1017031 1.0259446
## [624] 1.2430092 0.9616928 0.9684346 1.0223111 1.0451356 0.9878121 0.9588882
## [631] 1.2922454 1.0240104 1.0190668 0.9715186 1.0470281 1.0796316 1.0126342
## [638] 0.9907706 1.0651081 1.0972059 1.0207975 1.0242904 1.0856529 1.1706114
## [645] 1.0907976 1.1166518 1.0587905 0.9924200 1.0100030 1.0381987 1.0272740
## [652] 0.9992377 1.3299229 1.0864210 1.0066766 1.0979978 1.0810569 1.0717432
## [659] 1.1485254 1.0483646 1.3345620 0.9727599 1.0104054 0.9827025 1.0602388
## [666] 1.0978071 1.1232673 1.1269827 1.0213793 1.0763902 0.9922212 1.0780800
## [673] 1.0682818 1.2464630 1.0468552 1.0795465 0.9933231 1.0250768 1.0419155
## [680] 0.9869611 1.0485321 0.9583299 0.9608311 1.0017685 1.1129757 0.9967308
## [687] 1.0084346 1.2115309 0.9850309 0.9748513 0.9682318 1.3420435 0.9968575
## [694] 1.0417798 1.0763365 1.1527903 1.0248408 0.9558751 1.0182796 1.1027949
## [701] 1.0435491 1.0294341 0.9978981 1.0413287 1.0275325 1.0301633 1.0757710
## [708] 0.9492173 1.1555319 1.0306536 1.2113724 1.0373228 0.9850309 1.0106790
## [715] 0.9880916 0.9923417 0.9761060 1.0282128 1.0622007 1.0772350 1.0625492
## [722] 1.0637855 0.9882830 1.1639481 1.0429310 1.0082870 1.0930119 1.0551276
## [729] 1.1134884 0.9781440 1.4216746 1.1606871 1.0324760 1.0718101 1.0391602
## [736] 1.0051612 1.2544124 0.9892557 1.0831610 1.0850532 0.9919572 0.9693656
## [743] 1.2922139 1.0655693 1.0144074 0.9777445 1.0121160 1.0708887 1.0717932
## [750] 1.0331827 1.0242835 1.2723913 0.9490011 0.9753878 1.2935234 1.0113695
## [757] 1.0128266 1.0123082 1.1147694 0.9870937 1.1258679 1.0352350 0.9920637
## [764] 1.0101964 1.0288492 1.2479085 1.0067836 1.0334061 1.0680200 1.0193919
## [771] 1.0118896 1.0896854 1.0671322 0.9533642 1.0167539 1.1460145 1.0458404
## [778] 1.0805208 0.9865439 1.2724749 1.0261517 1.0434932 1.0220798 1.2883967
## [785] 0.9845553 1.0745388 0.9581787 1.0641679 1.2061298 1.0282701 1.0405894
## [792] 1.0486125 1.2818770 1.0578507
Ahora que se han calculado las puntuaciones de los valores atípicos, se puede trazar un gráfico de densidad como se muestra abajo:
A continuación, se obtienen las filas de los 7 valores atípicos que hay en los datos dat_num
. Con esta información, se podrían identificar los valores atípicos correspondientes.
## [1] 141 383 37 19 165 437 242
Ahora podemos utilizar el gráfico de pares para visualizar los valores atípicos que están marcados con un signo “+” en rojo:
En el espacio se pueden visualizar algunos outliers.
#install.packages("rgl")
#library(rgl)
plot3d(Age, Height, Score, type="s", col=col)
#install.packages("rgl")
#library(rgl)
plot3d(Age, Exam1, Income, type="s", col=col)
Como repaso personal, realizar algunos de los ejercicios que se encuentran en las siguientes notas de clase:
Estadística y distribuciones de probabilidad: Hacer click derecho.
Estadística inferencial: Hacer click derecho.
Consultar el documento RPubs :: Análisis multivariado (bibliografía).
If you found any ERRORS or have SUGGESTIONS, please report them to my email. Thanks.