【发布时间】:2017-03-06 07:16:07
【问题描述】:
问题
我想使用 ggplot2 在 y 轴上使用对数刻度绘制折线图中的数据。不幸的是,我的一些价值观一直下降到零。数据表示依赖于某些参数的特征的相对出现。当样本中没有观察到该特征时,值为零,这意味着它很少出现,或者实际上从不出现。这些零值会导致对数图中出现问题。
以下代码说明了简化数据集上的问题。实际上,数据集包含更多点,因此曲线看起来更平滑,参数p 的值也更多。
library(ggplot2)
dat <- data.frame(x=rep(c(0, 1, 2, 3), 2),
y=c(1e0, 1e-1, 1e-4, 0,
1e-1, 1e-3, 0, 0),
p=c(rep('a', 4), rep('b', 4)))
qplot(data=dat, x=x, y=y, colour=p, log="y", geom=c("line", "point"))
根据上面的数据,我们预计有两条线,第一条在对数图上应该有三个有限点,第二条在对数图上应该只有两个有限点。
但是,正如您所看到的,这会产生一个非常具有误导性的情节。看起来蓝线和红线都收敛到 1e-4 和 1e-3 之间的值。原因是log(0) 给出了-Inf,ggplot 只是放在了下轴上。
我的问题
在 R 中使用 ggplot2 处理这个问题的最佳方法是什么? 最佳我的意思是在效率方面,并且是理想的 R(我对 R 相当陌生)。
该图应表明这些曲线分别在 x=2(红色)或 x=1(蓝色)之后下降到“非常小”。理想情况下,从最后一个有限点向下有一条垂直线。我的意思如下所示。
我的尝试
在这里,我将描述我的想法。但是,鉴于我对 R 还很陌生,我怀疑可能有更好的方法。
library(ggplot2)
library(scales)
dat <- data.frame(x=rep(c(0, 1, 2, 3), 2),
y=c(1e0, 1e-1, 1e-4, 0,
1e-1, 1e-3, 0, 0),
p=c(rep('a', 4), rep('b', 4)))
与上述数据相同。
现在,我正在遍历每个唯一参数p,找到最后一个有限点的 x 坐标,并将其分配给 y 为零的所有点的 x 坐标。也就是实现一条垂直线。
for (p in unique(dat$p)) {
dat$x[dat$p == p & dat$y == 0] <- dat$x[head(which(dat$p == p & dat$y == 0), 1) - 1]
}
此时情节如下所示。
垂直线在那里。不过,也有几点。这些具有误导性,因为它们表明那里有一个实际的数据点,这是不正确的。
要删除我复制 y 数据的点(似乎很浪费),我们称之为yp,并将零替换为NA。然后我使用新的yp 作为geom_point 的 y 美学。
dat$yp <- dat$y
dat$yp[dat$y == 0] <- NA
ggplot(dat, aes(x=x, y=y, colour=p)) +
geom_line() +
geom_point(aes(y=dat$yp)) +
scale_y_continuous(trans=log10_trans(),
breaks = trans_breaks("log10", function(x) 10^x),
labels = trans_format("log10", math_format(10^.x)))
我使用ggplot 而不是qplot,这样我就可以为geom_line 和geom_point 赋予不同的美感。
最后,剧情是这样的。
这样做的正确方法是什么?
【问题讨论】:
-
处理这个问题的惯用方法不是在对数刻度上绘制零值。解决此问题的一种方法是改用
log(y + 1)之类的转换。 -
您是否考虑过替代转换?更高阶的第 n 个根不会有同样的问题。
-
不幸的是,它必须是以 10 为底的对数刻度。我需要将我的数据与现有图进行比较。