在R中使用geom_density_2d()时出错:在“ stat_density2d()”中计算失败:带宽必须严格为正

时间:2018-10-31 02:13:25

标签: r ggplot2

为了尝试使用ggplot2制作2d密度测试图,我使用了代码段:

ggplot(df, aes(x = S1.x, y = S1.y)) + geom_point() + geom_density_2d()

我收到错误消息:“ stat_density2d()中的计算失败:带宽必须严格为正”

我的数据框如下:

> df

transcriptID S1.x      S1.y      S2.x       S2.y    
DQ459412     0.000000  0.000000  0.000000   0.000000
DQ459413     1.584963  2.358379  4.392317   3.085722    
DQ459415     0.000000  0.000000  0.000000   0.000000    
DQ459418     0.000000  0.000000  0.000000   0.000000    
DQ459419     0.000000  0.000000  4.000000   2.891544    
DQ459420     0.000000  0.000000  0.000000   0.000000      

还有var(df[,"S1.x"]) > 0var(df[,"S1.y"]) > 0

Fig 1 - 2d density plot with error

但是,通过运行我得到了没有错误的密度图:

ggplot(df, aes(x = S2.x, y = S2.y)) + geom_point() + geom_density_2d()

Fig 2 - density plot without error

如何解决图1中的错误?

2 个答案:

答案 0 :(得分:1)

@Mike Wise的回答确实很可靠,我的回答对此有所补充。实际上,bandwidth.nrd函数计算的是 3rd 1st 分位数而不是2nd和1st(该函数的代码)之间的差:

r <- quantile(distances, c(0.25, 0.75))

我建议您自己预先计算带宽,然后将其传递给函数,以测试非零值,而不是像这样:

kde2d(df$s1x, df$s1y, 
      h = c(ifelse(bandwidth.nrd(df$s1x) == 0, 0.1, bandwidth.nrd(df$s1x)),
            ifelse(bandwidth.nrd(df$s1y) == 0, 0.1, bandwidth.nrd(df$s1y))))

希望这会有所帮助。

答案 1 :(得分:0)

因此,真正的问题是S1.xS1.y的值在其列中只有一个非零值。事实证明,geom_density_2d不能仅用一个或两个值来估计密度。但是请继续阅读...

更新:

此问题曾被问过,答案通常是您需要在数据列中具有非零方差。 但是您确实有非零方差,为什么它不起作用?

  • 查看geom_density_2d的内部结构,我们发现它使用MASS::kde2d包函数来计算分布。
  • kde2d看,我们发现它使用MASS::bandwidth.nrd(df$x)来估算带宽。
  • 查看bandwidth.nrd的帮助(包含代码),我们看到它使用经验法则来获取分布的quantile,并从第一个分位数减去第二个分位数得到带宽估算。
  • 对原始数据进行分位数,我们看到数据的分位数为零。
  • MASS::kde2d带宽估计的基础上对原始数据运行bandwidth.nrd会给您同样的错误:
library(MASS)
nn <- c("DQ459412","DQ459413","DQ459415","DQ459418","DQ459419","DQ459420")
s1x <- c(0,1.584963,0,0,0,0)
s1y <- c(0,2.358379,0,0,0,0) 
s2x <- c(0,4.392317,0,0,4,0)
s2y <- c(0,3.085722,0,0,2.891544,0) 
df <- data.frame(transcriptID=nn,S1.x=s1x,S1.y=s1y,S2.x=s2x,S2.y=s2y)
> quantile(df$s1x)
      0%      25%      50%      75%     100% 
0.000000 0.000000 0.000000 0.000000 1.584963 
> quantile(df$s1y)
      0%      25%      50%      75%     100% 
0.000000 0.000000 0.000000 0.000000 2.358379 
h <- c(MASS::bandwidth.nrd(df$x), MASS::bandwidth.nrd(df$y))
dens <- MASS::kde2d(df$s1x, df$s1y, h = h, n = n,  lims = c(0,1,0,1))
     

MASS :: kde2d(df $ s1x,df $ s1y,h = h,n = n,lims = c(0,1,0,1))中的错误:     带宽必须严格为正

因此,使用geom_density_2D的真正标准是x和y数据的第一和第二分位数之间必须有一个非零的间隙。

现在要修复它,如果我做了一些小修改-用0.1替换零,就像这样:

nn <- c("DQ459412","DQ459413","DQ459415","DQ459418","DQ459419","DQ459420")
s1x <- c(0,1.584963,0,0,0.1,0)
s1y <- c(0,2.358379,0,0,0.1,0) 
s2x <- c(0,4.392317,0,0,4,0)
s2y <- c(0,3.085722,0,0,2.891544,0) 
df <- data.frame(transcriptID=nn,S1.x=s1x,S1.y=s1y,S2.x=s2x,S2.y=s2y)
print(df)

收益:

  transcriptID     S1.x     S1.y     S2.x     S2.y
1     DQ459412 0.000000 0.000000 0.000000 0.000000
2     DQ459413 1.584963 2.358379 4.392317 3.085722
3     DQ459415 0.000000 0.000000 0.000000 0.000000
4     DQ459418 0.000000 0.000000 0.000000 0.000000
5     DQ459419 0.100000 0.100000 4.000000 2.891544
6     DQ459420 0.000000 0.000000 0.000000 0.000000

然后我得到这个图,而不是你的错误。

enter image description here 您可以让该0.1值接近零,最终它将不再能够计算分布,并且您将再次得到错误。

一种处理这种情况的一般方法是在数据中添加少量噪声,这是一种模拟事实,即基于连续分布的真实测量进行的任何有意义的计算都应不受该噪声的影响。噪音。

希望有帮助。