Detección de outliers (valores anómalos)
Santiago Banchero
Leo Lucianna
Juan Manuel Fernandez
Minería de Datos - UBA
Busquemos outliers en el atributo Road_55db del dataset ruidoso:
ruidoso=read.csv('ruidoso.txt')
data = ruidoso$Road_55dB
plot(data)
Hay outliers? Cuales?
Observemos analíticamente la distribución de la variable:
Media:
mean(data)
[1] 159228.8
Mínimo:
min(data)
[1] 7600
Máximo:
max(data)
[1] 3108200
Mediante boxplot podemos observar gráficamente la distribución de la variable:
Un criterio de detección de outliers podría ser eliminar los datos que se encuentran por fuera (abajo/arriba) de los “bigotes”.
Observemos gráficamente la distribución de la variable mediante boxplot:
boxplot(data)
Claramente, la distribución de la variable no es “normal”, o si? Muchas veces los outliers “esconden” la distribución real de un feature.
data.riq<-IQR(data)
print(data.riq)
[1] 59950
Calculamos Q1 y Q3:
cuantiles<-quantile(data, c(0.25, 0.5, 0.75), type = 7)
print(cuantiles)
25% 50% 75%
18950 37550 78900
Multiplicamos el cuantil 1 por 1.5 para determinar la barrera MENOR para la detección de outliers:
outliers_min<-as.numeric(cuantiles[1])-1.5*data.riq
print(outliers_min)
[1] -70975
outliers_max<-as.numeric(cuantiles[3])+1.5*data.riq
print(outliers_max)
[1] 168825
Otra opción mas sencilla es utilizar el objeto boxplot:
bp = boxplot(data)
out_inf = bp$stats[1]
out_sup = bp$stats[5]
cat("Extremo inferior", out_inf)
Extremo inferior 7600
cat("Extremo superior", out_sup)
Extremo superior 166400
plot(sort(data[data>outliers_min & data<outliers_max]))
boxplot(data[data>outliers_min & data<outliers_max], decreasing = FALSE)
Otra alternativa es realizar detección de outliers utilizando alguna medida de tendencia central.
Detección por N desvíos de la media (En el ejemplo N=3):
N=3
data<-ruidoso$Road_55dB
desvio<-sd(data)
print(desvio)
[1] 484751.3
outliers_max<-mean(data)+N*desvio
print(outliers_max)
[1] 1613483
outliers_min<-mean(data)-N*desvio
print(outliers_min)
[1] -1295025
plot(sort(data[data>outliers_min & data<outliers_max], decreasing = FALSE))
boxplot(sort(data[data>outliers_min & data<outliers_max], decreasing = FALSE))
Otra variante es trabajar a través de la métrica de z-score:
Cálculo de Z-Score:
data<-ruidoso
data$zscore<-(data$Road_55dB-mean(data$Road_55dB))/sd(data$Road_55dB)
umbral<-2
max(data$zscore)
[1] 6.083473
min(data$zscore)
[1] -0.3127971
plot(sort(data$Road_55dB[data$zscore<umbral], decreasing = FALSE))
boxplot(sort(data$Road_55dB[data$zscore<umbral], decreasing = FALSE))
library(scatterplot3d)
library(readr)
data <- read_csv("forestfires.csv")
data <- data[,c(7,9,10)]
scatterplot3d(data$DC, data$temp, data$RH)
Ahora abordamos, Local Outlier Factor [1] que es una técnica multivariada, dado que tiene en cuenta varios atributos para la detección del outlier. La idea es calcular un score para cada instancia, el cual representa un “índice” de densidad con respecto a los K vecinos mas cercanos.
# Cargamos la librería
library(Rlof)
# Calculamos LOF para k=3 vecinos por instancia
data$score<-lof(data, k=3)
umbral<-4
data$outlier <- (data$score>umbral)
data <- na.omit(data)
data$color <- ifelse(data$outlier, "red", "black")
scatterplot3d(data$DC, data$temp, data$RH, color = data$color)
Por último, utilizamos la distancia de Mahalanobis. Se trata de una medida de distancia que, normalizando por la matriz de covarianza, toma en cuenta la correlación entre las variables.
data$mahalanobis <- mahalanobis(data[,1:3], colMeans(data[,1:3]), cov(data[,1:3]))
# Ordenamos de forma decreciente, según el score de Mahalanobis
data <- data[order(data$mahalanobis,decreasing = TRUE),]
# Descartamos los outliers según un umbral
umbral<-8
data$outlier <- (data$mahalanobis>umbral)
data$color <- ifelse(data$outlier, "red", "black")
scatterplot3d(data$DC, data$temp, data$RH, color = data$color)