如何获取R中两个分布卷积结果对应的x值?
我知道这个问题可能更偏向统计理论,但我的核心需求是在R语言里实现对应的计算。最近我在尝试把多个分布相加,查看结果的分布情况,这里就用两个正态分布随机变量p1和p2来举例:
set.seed(21) N <- 1000 p1 <- rnorm(N, mean = 0, sd = 1) p2 <- rnorm(N, mean = 10, sd = 1)
我已经能画出它们的分布图像:
library(tidyverse) data.frame(p1, p2) %>% gather(key="dist", value="value") %>% ggplot(aes(value, color=dist)) + geom_density()
之后我想用convolve函数实现分布相加,但卡在了如何为卷积后的结果分布匹配准确的x值上。之前手动添加的方式太不准确了,我试过类似这样的代码得到卷积结果并绘图,但x轴的对应关系一直不对:
pdf.c <- convolve(pdf1.y, pdf2.y, type = "open") plot(pdf.c, type="l")
我感觉自己在统计基础上有认知缺口,想搞明白怎么正确获取新分布对应的x值。
附一下我生成pdf1和pdf2的代码:
set.seed(21) N <- 1000 p1 <- rnorm(N, mean = 0, sd = 1) p2 <- rnorm(N, mean = 10, sd = 1) pdf1.x <- density(p1)$x pdf2.x <- density(p2)$x pdf1.y <- density(p1)$y / sum(density(p1)$y) pdf2.y <- density(p2)$y / sum(density(p2)$y) df1 <- data.frame(pdf.x = pdf1.x, pdf.y = pdf1.y, dist = "1", stringsAsFactors = FALSE) df2 <- data.frame(pdf.x = pdf2.x, pdf.y = pdf2.y, dist = "2", stringsAsFactors = FALSE) df <- bind_rows(df1, df2)
其实核心是理解卷积的x值是两个原分布x值的所有可能和,但因为我们用的是密度估计后的离散点,需要先保证两个分布的x轴间隔一致,这样计算出来的卷积x轴才能准确对应。
步骤1:统一两个分布的x轴范围和间隔
首先,我们需要让pdf1.x和pdf2.x有相同的步长(间隔),并且覆盖足够大的范围,这样卷积后的结果不会丢失信息。可以用seq()来生成统一的x序列,然后用approx()把原密度值插值到这个统一的x轴上:
library(tidyverse) # 先确定统一的x轴范围:取两个分布x的最小值到最大值的扩展范围 min_x <- min(pdf1.x, pdf2.x) max_x <- max(pdf1.x, pdf2.x) # 扩展一点范围,避免卷积后边缘截断 extended_min <- min_x - 3 extended_max <- max_x + 3 # 统一步长,用原密度的平均步长 step <- mean(diff(pdf1.x)) # 生成统一的x序列 unified_x <- seq(extended_min, extended_max, by = step) # 把pdf1和pdf2的y值插值到统一x轴上 pdf1_y_unified <- approx(pdf1.x, pdf1.y, xout = unified_x)$y pdf2_y_unified <- approx(pdf2.x, pdf2.y, xout = unified_x)$y # 替换插值后的NA为0(边缘可能出现) pdf1_y_unified[is.na(pdf1_y_unified)] <- 0 pdf2_y_unified[is.na(pdf2_y_unified)] <- 0
步骤2:计算卷积并生成对应的x值
当两个分布的x轴统一后,卷积的x值范围就是min(unified_x) + min(unified_x)到max(unified_x) + max(unified_x),步长和原统一x轴一致。用convolve计算后,对应的x序列可以这样生成:
# 计算卷积(注意convolve的type参数,这里用"open"对应线性卷积) pdf_conv <- convolve(pdf1_y_unified, pdf2_y_unified, type = "open") # 生成卷积对应的x值 conv_x <- seq(2*extended_min, 2*extended_max, by = step) # 注意:convolve返回的长度是length(pdf1_y_unified) + length(pdf2_y_unified) - 1,和conv_x的长度一致
步骤3:绘图验证
现在就可以把原分布和卷积后的分布画在一起验证了:
# 整理数据 conv_df <- data.frame(x = conv_x, y = pdf_conv, dist = "p1+p2") original_df <- bind_rows( data.frame(x = unified_x, y = pdf1_y_unified, dist = "p1"), data.frame(x = unified_x, y = pdf2_y_unified, dist = "p2") ) # 绘图 ggplot() + geom_line(data = original_df, aes(x = x, y = y, color = dist)) + geom_line(data = conv_df, aes(x = x, y = y, color = dist), linetype = "dashed") + theme_minimal()
额外小技巧:利用正态分布性质简化计算
如果你是处理已知参数的正态分布,其实可以直接利用正态分布的性质:两个独立正态分布之和仍然是正态分布,均值是两者均值之和,方差是两者方差之和,这样可以直接生成理论分布来验证,比如:
# 理论分布的x和y theory_x <- seq(8, 12, by = 0.1) theory_y <- dnorm(theory_x, mean = 0+10, sd = sqrt(1+1))
内容的提问来源于stack exchange,提问作者Lloyd Christmas

