【问题标题】:R ggplot2 logarithmic cut with negative and positive values on x-axis and mean per bin of y-axisR ggplot2 对数切割,x 轴上有负值和正值,y 轴每个 bin 的平均值
【发布时间】:2015-11-10 09:22:22
【问题描述】:

我正在寻找一种方法来绘制一个变量的平均值在另一个变量(具有正值和负值)的 log2 值的 bin 中的分布,利用 ggplot2 中更复杂的函数。我想我主要是让这个复杂化,它可能是在 ggplot2 精炼选项中硬编码的,但我无法正确处理,所以在回到基础之前,我想我可以尝试学习如何在这里应用这些功能。

value <- rnorm(1000,0,20)
dist = c(rep(0, 15), sample(1:490), sample(-1:-495))
data = data.frame(value=value, dist=dist)

data$log=log2(abs(data$dist)+1)
# re-lable the x-axis: 
data$Labels=2^(abs(data$log))-1

data$bins=cut(data$log, breaks=10)
# Try to recover the negative log after transformation
data$sign=ifelse(data$dist==0, 0, ifelse(data$dist>0, "+", "-"))

# find the average expression of value per each bin
data=with(data, aggregate(data$value, by = list(bins, sign), FUN =    function(x) c(mn =mean(x), n=length(x) )))
data= as.data.frame(as.list(data))
names(data)=c("bins", "sign", "mean", "length")

# I am doing this in a very contorted way to try to achieve what I would like which is something like this:

bin_num = do.call("rbind", lapply(strsplit(sapply(as.character(data$bins), function(x) substr(x, 2, nchar(x)-1)), ","), as.numeric))
data$bin_num=bin_num[,1]
data$bin_num=ifelse(data$sign==0, 0, ifelse(data$sign=="-", -data$bin_num, data$bin_num))
data = data[order(data$bin_num),]

data <- transform(data, x2 = factor(paste(sign, bins)))
data <- transform(data, x2 = reorder(x2, rank(bin_num)))

# Line plot to show the distribution of the means across the bins of log2 of x:
ggplot(data, aes(y = mean, x = bin_num, group=1)) +  geom_point() + geom_line()

# 然后我尝试通过添加标签来重新标记这里的对数变换,但它当然不起作用:

ggplot(data, aes(y = mean, x = bin_num, group=1)) +  geom_point() + geom_line() + scale_x_discrete(labels=data$dist, breaks=data$bin_num)

我看到 ggplot2 具有直接计算平均值的功能,所以我什至可能不需要前面的命令。我试过了:

ggplot(data, aes(x = bins, y = mean)) + stat_summary(fun.y = "mean") +     geom_line() + scale_x_continuous(breaks = labels)

但是当然它不起作用...我还看到 ggplo2 具有自动帮助对数标记的功能,而不是我在这里使用的功能,但是当有负值时我不知道该怎么做被记录。另一个问题here 有一个非常好的函数,它可以转换两个值,但我认为在这个阶段它没有用。非常感谢您提供有关如何解决此问题的任何建议……非常感谢!

【问题讨论】:

  • 你能分享一张你试图实现的图片/绘图吗?
  • 嗨大卫,我添加了一个尝试,大致完成了我想要实现的目标,但它非常扭曲......我希望有更好的方法......
  • TBH,我完全迷失了,不知道你想要达到什么目的......所以在 x 轴上你想要 bin 编号,y 轴描绘平均值那个箱子。假设我们在 (-10, 3) 看到一个点,这意味着在 bin -10 中,变量的平均值是 3?!箱子大小呢?那么对数转换呢?
  • 感谢您的帮助,抱歉不清楚。是的点 (-10, 3) 应显示为 (2^(-10), 3)。我想 1) 将我的 x 变量转换为对数刻度,2) 将我的 log x 变量拆分为多个 bin,3) 找到每个 bin 的 y 平均值,4) 用 y= 绘图(平均值y 对于 log x 的每个 bin)和 x =(这些 bin,但标有原始非对数值)...我认为这些是当 x 变量非常大并且需要转换时的正常分级程序成对数刻度以更好地拟合数据,但也许这不是通常的程序?
  • 好的,我现在正在检查你的东西。同时,您能否更正您的示例,既没有找到x,也没有找到y,我假设它是value 和dist

标签: r plot ggplot2 transformation logarithm


【解决方案1】:

答案的第一个版本,使用data.table 以获得更快的速度和更好的可读性:

代码用更短更快的代码重现问题

library(data.table)

# function that returns the lower bound of a cut
lower.bound <- function(x, n) {
  c <- cut(x, n)
  tmp <- substr(x = c, start = 2, stop = regexpr(",", c) - 1)
  return(as.numeric(tmp))
}

nbin <- 10
set.seed(123)
dat <- data.table(value = rnorm(1000,0, 20),
                  dist = c(rep(0, 15), sample(1:490), sample(-1:-495)))

dat[, log := log2(abs(dist) + 1)]
dat[, labels := 2^(abs(log))]
dat[, sign := ifelse(dist == 0, 
                     0,
                     ifelse(dist > 0, "+", "-"))]

dat[, bin := ifelse(sign == 0, 
                    0,
                    ifelse(sign == "+", 
                           lower.bound(log, nbin),
                           -lower.bound(log, nbin)))]

sumdat <- dat[, .(mvalue = mean(value),
                  nvalue = .N,
                  ylab = mean(dist)), 
                 by = .(bin, sign)][order(bin)]

ggplot(sumdat, aes(x = ylab, y = mvalue)) + geom_line()

【讨论】:

  • 更多讨论请看这里:chat.stackoverflow.com/rooms/94732/… 之后我会更新最终答案
  • 谢谢大卫...我正在寻找一种方法来用原始非对数值标记 x 轴,以便 x 轴范围为 range(dat$dist) [1] - 495 490,这可能吗?
  • 感谢大卫,这非常有效:sumdat
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
相关资源
最近更新 更多