如何使用 geom_boxplot(stat = "identity") 模拟具有异常值的 geom_boxplot()
How to mimic geom_boxplot() with outliers using geom_boxplot(stat = "identity")
我想预先计算数据的变量摘要(使用 plyr
并传递 quantile
函数),然后使用 geom_boxplot(stat = "identity")
进行绘图。这很好用,除了它 (a) 不将异常值绘制为点并且 (b) 将 "whiskers" 扩展到正在绘制的数据的最大值和最小值。
示例:
library(plyr)
library(ggplot2)
set.seed(4)
df <- data.frame(fact = sample(letters[1:2], 12, replace = TRUE),
val = c(1:10, 100, 101))
df
# fact val
# 1 b 1
# 2 a 2
# 3 a 3
# 4 a 4
# 5 b 5
# 6 a 6
# 7 b 7
# 8 b 8
# 9 b 9
# 10 a 10
# 11 b 100
# 12 a 101
by.fact.df <- ddply(df, c("fact"), function(x) quantile(x$val))
by.fact.df
# fact 0% 25% 50% 75% 100%
# 1 a 2 3.25 5.0 9.00 101
# 2 b 1 5.50 7.5 8.75 100
# What I can do...with faults (a) and (b) above
ggplot(by.fact.df,
aes(x = fact, ymin = `0%`, lower = `25%`, middle = `50%`,
upper = `75%`, ymax = `100%`)) +
geom_boxplot(stat = "identity")
# What I want...
ggplot(df, aes(x = fact, y = val)) +
geom_boxplot()
我能做的...对于上面提到的错误 (a) 和 (b):
我想获得什么,但仍然通过plyr
(或其他方法)利用预计算:
初步想法:也许有一些方法可以预先计算出没有异常值的胡须的真实终点?然后,对异常值的数据进行子集化并将它们作为 geom_point()
?
传递
动机: 在处理较大的数据集时,我发现利用 plyr
、dplyr
、and/or 更快更实用data.table
预先计算统计数据然后绘制它们,而不是让 ggplot2
进行计算。
更新
我可以使用以下 dplyr
和 plyr
代码的组合来提取我需要的内容,但我不确定这是否是最有效的方法:
df %>%
group_by(fact) %>%
do(ldply(boxplot.stats(.$val), data.frame))
Source: local data frame [6 x 3]
Groups: fact
fact .id X..i..
1 a stats 2
2 a stats 4
3 a stats 10
4 a stats 13
5 a stats 16
6 a n 9
要获得正确的统计数据,您需要做更多的计算,而不仅仅是找到分位数。 geom_boxplot
函数与 stat = "identity"
不绘制离群值。所以你必须计算没有异常值的统计数据,然后使用 geom_point
单独绘制异常值。以下函数(基本上是 stat_boxplot
的简化版本)可能不是最有效的,但它给出了所需的结果:
box.df <- df %>% group_by(fact) %>% do({
stats <- as.numeric(quantile(.$val, c(0, 0.25, 0.5, 0.75, 1)))
iqr <- diff(stats[c(2, 4)])
coef <- 1.5
outliers <- .$val < (stats[2] - coef * iqr) | .$val > (stats[4] + coef * iqr)
if (any(outliers)) {
stats[c(1, 5)] <- range(c(stats[2:4], .$val[!outliers]), na.rm=TRUE)
}
outlier_values = .$val[outliers]
if (length(outlier_values) == 0) outlier_values <- NA_real_
res <- as.list(t(stats))
names(res) <- c("lower.whisker", "lower.hinge", "median", "upper.hinge", "upper.whisker")
res$out <- outlier_values
as.data.frame(res)
})
box.df
## Source: local data frame [2 x 7]
## Groups: fact
##
## fact lower.whisker lower.hinge median upper.hinge upper.whisker out
## 1 a 2 3.25 5.0 9.00 10 101
## 2 b 1 5.50 7.5 8.75 9 100
ggplot(box.df, aes(x = fact, y = out, middle = median,
ymin = lower.whisker, ymax = upper.whisker,
lower = lower.hinge, upper = upper.hinge)) +
geom_boxplot(stat = "identity") +
geom_point()
这是我的答案,使用内置函数 quantile
和 boxplot.stats
。
geom_boxplot
对箱线图的计算与 boxplot.stats
略有不同。阅读 ?geom_boxplot
和 ?boxplot.stats
以了解我在下面的实现
#Function to calculate boxplot stats to match ggplot's implemention as in geom_boxplot.
my_boxplot.stats <-function(x){
quantiles <-quantile(x, c(0, 0.25, 0.5, 0.75, 1))
labels <-names(quantile(x))
#replacing the upper whisker to geom_boxplot
quantiles[5] <-boxplot.stats(x)$stats[5]
res <-data.frame(rbind(quantiles))
names(res) <-labels
res$out <-boxplot.stats(x)$out
return(res)
}
计算统计数据并绘制它的代码
library(dplyr)
df %>% group_by(fact) %>% do(my_boxplot.stats(.$val)) %>%
ggplot(aes(x=fact, y=out, ymin = `0%`, lower = `25%`, middle = `50%`,
upper = `75%`, ymax = `100%`)) +
geom_boxplot(stat = "identity") + geom_point()
我想预先计算数据的变量摘要(使用 plyr
并传递 quantile
函数),然后使用 geom_boxplot(stat = "identity")
进行绘图。这很好用,除了它 (a) 不将异常值绘制为点并且 (b) 将 "whiskers" 扩展到正在绘制的数据的最大值和最小值。
示例:
library(plyr)
library(ggplot2)
set.seed(4)
df <- data.frame(fact = sample(letters[1:2], 12, replace = TRUE),
val = c(1:10, 100, 101))
df
# fact val
# 1 b 1
# 2 a 2
# 3 a 3
# 4 a 4
# 5 b 5
# 6 a 6
# 7 b 7
# 8 b 8
# 9 b 9
# 10 a 10
# 11 b 100
# 12 a 101
by.fact.df <- ddply(df, c("fact"), function(x) quantile(x$val))
by.fact.df
# fact 0% 25% 50% 75% 100%
# 1 a 2 3.25 5.0 9.00 101
# 2 b 1 5.50 7.5 8.75 100
# What I can do...with faults (a) and (b) above
ggplot(by.fact.df,
aes(x = fact, ymin = `0%`, lower = `25%`, middle = `50%`,
upper = `75%`, ymax = `100%`)) +
geom_boxplot(stat = "identity")
# What I want...
ggplot(df, aes(x = fact, y = val)) +
geom_boxplot()
我能做的...对于上面提到的错误 (a) 和 (b):
我想获得什么,但仍然通过plyr
(或其他方法)利用预计算:
初步想法:也许有一些方法可以预先计算出没有异常值的胡须的真实终点?然后,对异常值的数据进行子集化并将它们作为 geom_point()
?
动机: 在处理较大的数据集时,我发现利用 plyr
、dplyr
、and/or 更快更实用data.table
预先计算统计数据然后绘制它们,而不是让 ggplot2
进行计算。
更新
我可以使用以下 dplyr
和 plyr
代码的组合来提取我需要的内容,但我不确定这是否是最有效的方法:
df %>%
group_by(fact) %>%
do(ldply(boxplot.stats(.$val), data.frame))
Source: local data frame [6 x 3]
Groups: fact
fact .id X..i..
1 a stats 2
2 a stats 4
3 a stats 10
4 a stats 13
5 a stats 16
6 a n 9
要获得正确的统计数据,您需要做更多的计算,而不仅仅是找到分位数。 geom_boxplot
函数与 stat = "identity"
不绘制离群值。所以你必须计算没有异常值的统计数据,然后使用 geom_point
单独绘制异常值。以下函数(基本上是 stat_boxplot
的简化版本)可能不是最有效的,但它给出了所需的结果:
box.df <- df %>% group_by(fact) %>% do({
stats <- as.numeric(quantile(.$val, c(0, 0.25, 0.5, 0.75, 1)))
iqr <- diff(stats[c(2, 4)])
coef <- 1.5
outliers <- .$val < (stats[2] - coef * iqr) | .$val > (stats[4] + coef * iqr)
if (any(outliers)) {
stats[c(1, 5)] <- range(c(stats[2:4], .$val[!outliers]), na.rm=TRUE)
}
outlier_values = .$val[outliers]
if (length(outlier_values) == 0) outlier_values <- NA_real_
res <- as.list(t(stats))
names(res) <- c("lower.whisker", "lower.hinge", "median", "upper.hinge", "upper.whisker")
res$out <- outlier_values
as.data.frame(res)
})
box.df
## Source: local data frame [2 x 7]
## Groups: fact
##
## fact lower.whisker lower.hinge median upper.hinge upper.whisker out
## 1 a 2 3.25 5.0 9.00 10 101
## 2 b 1 5.50 7.5 8.75 9 100
ggplot(box.df, aes(x = fact, y = out, middle = median,
ymin = lower.whisker, ymax = upper.whisker,
lower = lower.hinge, upper = upper.hinge)) +
geom_boxplot(stat = "identity") +
geom_point()
这是我的答案,使用内置函数 quantile
和 boxplot.stats
。
geom_boxplot
对箱线图的计算与 boxplot.stats
略有不同。阅读 ?geom_boxplot
和 ?boxplot.stats
以了解我在下面的实现
#Function to calculate boxplot stats to match ggplot's implemention as in geom_boxplot.
my_boxplot.stats <-function(x){
quantiles <-quantile(x, c(0, 0.25, 0.5, 0.75, 1))
labels <-names(quantile(x))
#replacing the upper whisker to geom_boxplot
quantiles[5] <-boxplot.stats(x)$stats[5]
res <-data.frame(rbind(quantiles))
names(res) <-labels
res$out <-boxplot.stats(x)$out
return(res)
}
计算统计数据并绘制它的代码
library(dplyr)
df %>% group_by(fact) %>% do(my_boxplot.stats(.$val)) %>%
ggplot(aes(x=fact, y=out, ymin = `0%`, lower = `25%`, middle = `50%`,
upper = `75%`, ymax = `100%`)) +
geom_boxplot(stat = "identity") + geom_point()