使用ggplot以有效的方式显示异常值

时间:2017-12-11 08:09:44

标签: r ggplot2

我所拥有的实际数据(和目标)是不同的,但为了复制目的,我使用了泰坦尼克号数据集。我的目标是创建一个每个阶级和性别的年龄异常值(1次SD)的情节。

因此我做的第一件事是计算sd值和范围:

library(dplyr)
library(ggplot2)

#Load titanic set
titanic <- read.csv("titanic_total.csv")
group <- group_by(titanic, Pclass, Sex)

#Create outlier ranges
summarise <- summarise(group, mean=mean(Age), sd=sd(Age))
summarise <- as.data.frame(summarise)
summarise$outlier_max <- summarise$mean + summarise$sd
summarise$outlier_min <- summarise$mean - summarise$sd

#Create a key
summarise$key <- paste0(summarise$Pclass, summarise$Sex)

#Create a key for the base set
titanic$key <- paste0(titanic$Pclass, titanic$Sex)

total_data <- left_join(titanic, summarise, by = "key")
total_data$outlier <- 0

接下来,使用循环我确定年龄是在范围之内还是之外

for (row in 1:nrow(total_data)){
 if((total_data$Age[row]) > (total_data$outlier_max[row])){
  total_data$outlier[row] <- 1
 } else if ((total_data$Age[row]) < (total_data$outlier_min[row])){
  total_data$outlier[row] <- 1
 } else {
  total_data$outlier[row] <- 0
 }
}

做一些数据清理......

total_data$Pclass.x <- as.factor(total_data$Pclass.x)
total_data$outlier <- as.factor(total_data$outlier)

现在这段代码给了我正在寻找的情节。

ggplot(total_data, aes(x = Age, y = Pclass.x, colour = outlier)) + geom_point() +
 facet_grid(. ~Sex.x)

但是,这似乎不是解决此问题的最简单方法。关于如何包含最佳实践以提高效率的任何想法。

1 个答案:

答案 0 :(得分:2)

减少代码并减少重复性的一种方法是通过管道将其全部集成到一个过程中。不是使用值创建摘要,而是将其与数据重新连接,您基本上可以在mutate步骤中执行此操作:

titanic %>% 
  mutate(Pclass = as.factor(Pclass)) %>% 
  group_by(Pclass, Sex) %>% 
  mutate(Age.mean = mean(Age), 
         Age.sd = sd(Age), 
         outlier.max = Age.mean + Age.sd, 
         outlier.min = Age.mean - Age.sd, 
         outlier = as.factor(ifelse(Age > outlier.max, 1, 
                                    ifelse(Age < outlier.min, 1, 0)))) %>% 
  ggplot() +
    geom_point(aes(Age, Pclass, colour = outlier)) +
    facet_grid(.~Sex)

Pclass会提前变异为一个因素,因为它是一个分组因素。然后,步骤在原始数据帧内完成,而不是创建两个新的数据帧。但是,对原始数据集没有任何更改!如果您需要此功能,只需将结果重新分配给titanic或其他数据框,然后执行ggplot - 部分作为下一步。否则,您可以将数字的结果分配给您的数据。

为了识别异常值,一种方法是使用ifelse。或者,dplyr提供了很好的between功能,但是,为此,您需要添加rowwise,即在为异常值创建最小和最大阈值之后:

...
rowwise() %>% 
    mutate(outlier = as.factor(as.numeric(between(Age, outlier.min, outlier.max)))) %>% ...

<强>加: 此外,您甚至可以进一步减少代码,具体取决于您希望以哪种方式保留代码:

titanic %>% 
    group_by(Pclass, Sex) %>% 
    mutate(outlier = as.factor(ifelse(Age > (mean(Age) + sd(Age)), 1, 
                                      ifelse(Age < (mean(Age) - sd(Age)), 1, 0)))) %>% 
    ggplot() +
    geom_point(aes(Age, as.factor(Pclass), colour = outlier)) +
    facet_grid(.~Sex)