如何在对数图中处理零

时间:2016-10-24 13:23:58

标签: r ggplot2

问题

我有数据,我想使用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"))

鉴于上述数据,我们预计有两条线,第一条线应该在对数图上有三个有限点,第二条线应该在对数图上只有两个有限点。

Misleading plot

但是,正如您所看到的,这会产生一种非常误导的情节。看起来蓝色和红色线都会收敛到1e-4和1e-3之间的值。原因是log(0)给出-Inf,ggplot只是放在下轴上。

我的问题

使用ggplot2在R中处理此问题的最佳方法是什么? best 我的意思是效率方面,而且是意识形态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]
}

此时情节如下:

Vertical lines and points

垂直线在那里。但是,也有一些观点。这些都是误导性的,因为它们表明那里有一个实际的数据点,这是不正确的。

要删除我复制y数据的点(看起来很浪费),我们称之为yp,并将{0}替换为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_linegeom_point提供不同的美学。

最后,情节看起来像这样。

Final Plot

正确的方法是什么?

3 个答案:

答案 0 :(得分:1)

我使用

+ scale_y_continuous(trans=scales::pseudo_log_trans(base = 10)

答案 1 :(得分:1)

最简单的方法是为每个数字添加一个小值。例子,

df <- mutate(df, log_var = log(var + 0.01))
ggplot(df, aes(x = log_var)) + geom_histogram()

答案 2 :(得分:0)

如果使用的是ggplot,则可以使用scales::pseudo_log_trans()作为转换对象。这会将您的-inf替换为0。

从文档(https://scales.r-lib.org/reference/pseudo_log_trans.html),

  

将数字映射到有符号对数刻度的转换,并平滑地过渡到0附近的线性刻度。

     

pseudo_log_trans(sigma = 1, base = exp(1))

例如,我的比例表达式如下所示:

+ scale_fill_gradient(name = "n occurrences", trans="pseudo_log")