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


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


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


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/


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


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.


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) "


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.


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?


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.


é 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, ]

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


-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)
}

Adicione alguma explicação à sua resposta. Consulte como responder .
ejderuby
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.