Como remover outliers de um conjunto de dados

98

Eu tenho alguns dados multivariados de beleza versus idades. As idades variam de 20 a 40 anos em intervalos de 2 (20, 22, 24 ... 40) e, para cada registro de dados, recebem uma idade e uma classificação de beleza de 1 a 5. Quando faço boxplots desses dados (idades no eixo X, classificações de beleza no eixo Y), há alguns valores discrepantes plotados fora dos bigodes de cada caixa.

Quero remover esses outliers do próprio quadro de dados, mas não tenho certeza de como R calcula outliers para seus gráficos de caixa. Abaixo está um exemplo de como meus dados podem ser. insira a descrição da imagem aqui

Dan Q
fonte
2
A boxplotfunção retorna os outliers (entre outras estatísticas) de forma invisível. Tente foo <- boxplot(...); fooler ?boxplotpara entender a saída.
Joshua Ulrich
Você deve editar sua pergunta de acordo com o comentário que você deu na resposta de @Prasad!
aL3xa
@ aL3xa: está na primeira frase do segundo parágrafo.
Joshua Ulrich
24
Relevante: davidmlane.com/ben/outlier.gif
eyjo
Você pode enviar um link para os dados?
wordsforthewise

Respostas:

119

OK, você deve aplicar algo assim ao seu conjunto de dados. Não substitua e salve ou você destruirá seus dados! E, aliás, você (quase) nunca deve remover outliers de seus dados:

remove_outliers <- function(x, na.rm = TRUE, ...) {
  qnt <- quantile(x, probs=c(.25, .75), na.rm = na.rm, ...)
  H <- 1.5 * IQR(x, na.rm = na.rm)
  y <- x
  y[x < (qnt[1] - H)] <- NA
  y[x > (qnt[2] + H)] <- NA
  y
}

Para vê-lo em ação:

set.seed(1)
x <- rnorm(100)
x <- c(-10, x, 10)
y <- remove_outliers(x)
## png()
par(mfrow = c(1, 2))
boxplot(x)
boxplot(y)
## dev.off()

E, mais uma vez, você nunca deve fazer isso sozinho, os outliers foram feitos para ser! =)

EDIT: Eu adicionei na.rm = TRUEcomo padrão.

EDIT2:quantile Função removida , adição de subscritos, tornando a função mais rápida! =)

insira a descrição da imagem aqui

aL3xa
fonte
Obrigado pela ajuda! Eu acho que se R é capaz de gerar valores discrepantes no boxplot, eu não deveria ter que fazer esses cálculos intermediários. Quanto à exclusão de outliers, trata-se apenas de uma atribuição.
Dan Q de
3
OK, estou perdendo algo aqui. Você deseja remover outliers dos dados, para que possa traçá-los com boxplot. Isso é administrável e você deve marcar a resposta de @Prasad então, pois respondeu à sua pergunta. Se você deseja excluir outliers usando "regra de outlier" q +/- (1.5 * H), portanto, execute algumas análises, então use esta função. Aliás, eu fiz isso do zero, sem pesquisar no Google, então há uma chance de eu ter reinventado a roda com essa minha função ...
aL3xa
10
Você não deveria fazer perguntas de atribuição no stackoverflow!
hadley
7
Isso significa que também não devemos responder? =)
aL3xa
5
"outliers são apenas para ser"? Não necessariamente. Eles podem vir de erros de medida e devem ser cuidadosamente revisados. Quando o outlier é muito grande, pode significar alguma coisa, ou não tanto. É por isso que (pelo menos em biologia) a mediana geralmente diz mais sobre uma população do que a média.
Rodrigo
133

Ninguém postou a resposta mais simples:

x[!x %in% boxplot.stats(x)$out]

Veja também: http://www.r-statistics.com/2011/01/how-to-label-all-the-outliers-in-a-boxplot/

J. Win.
fonte
4
Muito elegante. Obrigado. Mas é preciso ter cuidado se a distribuição tiver mais de um modo e os valores discrepantes forem realmente poucos e dispersos.
KarthikS
Teria sido ótimo se você pudesse obter o índice deles em um conjunto de dados. A maneira como você fez irá filtrar com base no valor dos dados. Se o gráfico de caixa também estiver agrupando, não necessariamente o mesmo valor de dados será discrepante em cada grupo
adam
2
Também é importante mencionar que isso não altera o conjunto de dados. Este é apenas um método de filtragem. Portanto, se você pretende usar o conjunto de dados sem outliers, atribua-o a uma variável. por exemploresult = x[!x %in% boxplot.stats(x)$out]
Victor Augusto
Ter apenas uma linha de código não significa necessariamente que seja simples! Nem sempre é fácil entender um código de uma linha, especialmente para iniciantes, e sem comentários.
PeyM87 de
29

Use outline = FALSEcomo uma opção ao fazer o boxplot (leia a ajuda!).

> m <- c(rnorm(10),5,10)
> bp <- boxplot(m, outline = FALSE)

insira a descrição da imagem aqui

Prasad Chalasani
fonte
4
na verdade, isso removerá os outliers do próprio boxplot, mas desejo remover os outliers do quadro de dados.
Dan Q de
2
Vejo, então, como @Joshua disse, você precisa olhar os dados retornados pela função boxplot (em particular os itens oute groupna lista).
Prasad Chalasani
16

A função boxplot retorna os valores usados ​​para fazer a plotagem (que na verdade é feita por bxp ():

bstats <- boxplot(count ~ spray, data = InsectSprays, col = "lightgray") 
#need to "waste" this plot
bstats$out <- NULL
bstats$group <- NULL
bxp(bstats)  # this will plot without any outlier points

De propósito, não respondi à pergunta específica porque considero uma má prática estatística remover "outliers". Eu considero uma prática aceitável não representá-los em um boxplot, mas removê-los apenas porque excedem algum número de desvios-padrão ou algum número de larguras interquartis é uma mutilação sistemática e não científica do registro observacional.

IRTFM
fonte
4
Bem, evitar a pergunta sem saber por que a pergunta foi feita também não é uma boa prática. Sim, não é bom remover 'outliers' dos dados, mas às vezes você precisa dos dados sem outliers para tarefas específicas. Em uma atribuição de estatística que fiz recentemente, tivemos que visualizar um conjunto sem seus outliers para determinar o melhor modelo de regressão a ser usado para os dados. Então aí!
Alex Essilfie
4
Não estou considerando o conselho que você pode ter recebido a esse respeito de "determinar o melhor modelo de regressão" para ser particularmente persuasivo. Em vez disso, se você precisava remover outliers para esse propósito vagamente declarado, então acho que isso reflete mal nas pessoas que o aconselharam, em vez de ser uma evidência da invalidade da minha posição.
IRTFM
Eu acho que é legítimo quando você sabe que está removendo "ruído". especialmente em dados fisiológicos.
roscoe1895
Sim. Se você tiver bons motivos para acreditar que um processo separado cria o sinal, é uma justificativa para a remoção dos dados.
IRTFM
9

Pesquisei pacotes relacionados à remoção de outliers e encontrei este pacote (surpreendentemente chamado de "outliers"!): Https://cran.r-project.org/web/packages/outliers/outliers.pdf
se você ler, veja diferentes formas de remoção de outliers e entre elas achei a rm.outliermais conveniente de usar e como diz no link acima: "Se o outlier for detectado e confirmado por testes estatísticos, esta função pode removê-lo ou substituí-lo pela média ou mediana da amostra" e também aqui está a parte de uso da mesma fonte:
" Uso

rm.outlier(x, fill = FALSE, median = FALSE, opposite = FALSE)

Argumentos
x um conjunto de dados, mais frequentemente um vetor. Se o argumento for um dataframe, o outlier será removido de cada coluna por sapply. O mesmo comportamento é aplicado por apply quando a matriz é fornecida.
preencher Se definido como TRUE, a mediana ou média é colocada em vez de outlier. Caso contrário, o (s) outlier (s) é / são simplesmente removidos.
mediana Se definido como TRUE, a mediana é usada em vez da média na substituição de outlier. oposto se definido como TRUE, dá o valor oposto (se o maior valor tem diferença máxima da média, ele dá o menor e vice-versa) "

Peyman
fonte
Isso parece ótimo, mas se você tiver uma coluna de série temporal em seu quadro de dados, ela mudará a série temporal.
PeyM87 de
7
x<-quantile(retentiondata$sum_dec_incr,c(0.01,0.99))
data_clean <- data[data$attribute >=x[1] & data$attribute<=x[2],]

Acho muito fácil remover outliers. No exemplo acima, estou apenas extraindo 2 percentis a 98 percentis dos valores de atributo.

Gaurav Khare
fonte
5

Não:

z <- df[df$x > quantile(df$x, .25) - 1.5*IQR(df$x) & 
        df$x < quantile(df$x, .75) + 1.5*IQR(df$x), ] #rows

realizar essa tarefa com bastante facilidade?

d8aninja
fonte
4

Somando-se a sugestão de @sefarkas e usando quantis como pontos de corte, pode-se explorar a seguinte opção:

newdata <- subset(mydata,!(mydata$var > quantile(mydata$var, probs=c(.01, .99))[2] | mydata$var < quantile(mydata$var, probs=c(.01, .99))[1]) ) 

Isso removerá os pontos pontos além do 99º quantil. Cuidado deve ser tomado como o que aL3Xa estava dizendo sobre como manter valores discrepantes. Deve ser removido apenas para obter uma visão conservadora alternativa dos dados.

KarthikS
fonte
é 0.91ou 0.99? como em mydata$var < quantile(mydata$var, probs=c(.01, .91))[1])oumydata$var < quantile(mydata$var, probs=c(.01, .99))[1])
Komal Rathi
Se você tiver um motivo específico para usar o percentil 91 em vez do percentil 99, poderá usá-lo. É apenas uma heurística
KarthikS
1

Uma maneira de fazer isso é

my.NEW.data.frame <- my.data.frame[-boxplot.stats(my.data.frame$my.column)$out, ]

ou

my.high.value <- which(my.data.frame$age > 200 | my.data.frame$age < 0) 
my.NEW.data.frame <- my.data.frame[-my.high.value, ]
Seyma Kalay
fonte
0

Os valores discrepantes são bastante semelhantes aos picos, então um detector de pico pode ser útil para identificar valores discrepantes. O método descrito aqui tem um desempenho muito bom usando z-scores. A animação na parte inferior da página ilustra o método de sinalização em outliers, ou picos.

Os picos nem sempre são iguais aos outliers, mas são semelhantes com frequência.

Um exemplo é mostrado aqui: Este conjunto de dados é lido de um sensor por meio de comunicações seriais. Erros ocasionais de comunicação serial, erro do sensor ou ambos levam a pontos de dados repetidos e claramente errados. Não há valor estatístico neste ponto. Eles são indiscutivelmente não outliers, são erros. O detector de pico de pontuação z foi capaz de sinalizar pontos de dados espúrios e gerou um conjunto de dados limpo resultante:insira a descrição da imagem aqui

Marc Compere
fonte
-1

Experimente isso. Alimente sua variável na função e salve o / p na variável que conteria os outliers removidos

outliers<-function(variable){
    iqr<-IQR(variable)
    q1<-as.numeric(quantile(variable,0.25))
    q3<-as.numeric(quantile(variable,0.75))
    mild_low<-q1-(1.5*iqr)
    mild_high<-q3+(1.5*iqr)
    new_variable<-variable[variable>mild_low & variable<mild_high]
    return(new_variable)
}
Adipta Biwas
fonte
Adicione alguma explicação à sua resposta. Consulte como responder .
ejderuby