You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R语言中从非标准函数生成样本的技术问询

从自定义分布 $f(x) = \frac{1}{(\Gamma(1+1/x))^N}$ 中抽取样本的R实现方案

作为刚接触R的新手,碰到这种没有现成采样函数的自定义分布确实容易卡壳,我来一步步帮你解决问题——先从修正你写的函数开始,再逐个分析你尝试过的方法,给出可直接运行的代码。

一、先把目标密度函数写对

你提供的Falp函数有几个明显的问题:没传入关键参数x和N、定义了没用的变量ti、初始化矩阵时依赖未定义的x。先把基础的未归一化目标密度函数写好(采样时大多不需要归一化常数,省掉计算麻烦):

# 未归一化的目标密度函数,x必须>0,N为样本数量
target_density <- function(x, N) {
  if (any(x <= 0)) return(0)  # 过滤x<=0的无效输入
  1 / (gamma(1 + 1/x))^N
}

# 测试一下:x=1时gamma(2)=1,所以结果为1;x=2时gamma(1.5)=sqrt(pi)/2≈0.886,结果≈1/(0.886^10)≈0.63
target_density(x = c(1, 2), N = 10)

二、为什么分位数法行不通?

分位数法需要知道累积分布函数(CDF)的反函数,但这个分布的CDF是$\int_0^x f(t)dt$,这个积分没有解析解,根本没法写出反函数,所以这个方法直接放弃就好,不是你的问题~

三、拒绝采样的简便实现:用自适应拒绝采样包

手动找合适的提议分布和常数M对新手太麻烦,R里的ars包专门处理单峰分布的自适应拒绝采样,自动帮你搞定这些细节:

  1. 先安装并加载包:
install.packages("ars")
library(ars)
  1. 定义对数形式的目标密度(ars包要求输入对数密度,数值稳定性更好):
log_target <- function(x) {
  if (x <= 0) return(-Inf)  # x<=0时密度为0,对应对数负无穷
  -N * log(gamma(1 + 1/x))
}
  1. 生成样本并验证:
N <- 10  # 假设样本数量为10
# 生成1000个样本,初始点选两个能覆盖密度主要区域的点(比如0.5和2)
samples_ars <- ars(n = 1000, logf = log_target, x = c(0.5, 2))

# 对比采样结果和目标密度的形状
x_vals <- seq(0.1, 5, length.out = 1000)
dens_vals <- sapply(x_vals, target_density, N = N)

plot(density(samples_ars), main = "拒绝采样样本密度 vs 目标密度", col = "red", lwd=2)
# 把目标密度缩放后对齐绘制
lines(x_vals, dens_vals / max(dens_vals) * max(density(samples_ars)$y), col = "blue", lwd=2)
legend("topright", legend = c("采样样本密度", "目标密度"), col = c("red", "blue"), lty = 1)

四、Metropolis-Hastings(MH)算法的手动实现

如果不想依赖第三方包,自己写MH算法也不难。这里用对数变换来避免处理x<=0的问题(把x转成y=log(x),y的范围是全体实数,提议分布用正态分布更方便):

mh_sample <- function(n_samples, N, sigma = 0.5, burn_in = 2000) {
  # 初始化:从x=1开始,对应y=log(1)=0
  y_current <- 0
  samples <- numeric(n_samples + burn_in)
  
  for (i in 1:(n_samples + burn_in)) {
    # 生成候选y值,用正态提议分布
    y_proposal <- rnorm(1, mean = y_current, sd = sigma)
    x_proposal <- exp(y_proposal)
    x_current <- exp(y_current)
    
    # 计算接受率(因为提议分布对称,雅可比行列式抵消,直接用对数密度差)
    log_alpha <- log_target(x_proposal) - log_target(x_current)
    alpha <- min(1, exp(log_alpha))
    
    # 决定是否接受候选样本
    if (runif(1) <= alpha) {
      y_current <- y_proposal
    }
    
    samples[i] <- exp(y_current)
  }
  
  # 去掉前2000个燃烧期样本,返回有效样本
  samples[(burn_in + 1):(burn_in + n_samples)]
}

# 生成1000个样本
samples_mh <- mh_sample(n_samples = 1000, N = 10, sigma = 0.5)

# 验证采样结果
plot(density(samples_mh), main = "MH算法样本密度 vs 目标密度", col = "green", lwd=2)
lines(x_vals, dens_vals / max(dens_vals) * max(density(samples_mh)$y), col = "blue", lwd=2)
legend("topright", legend = c("MH样本密度", "目标密度"), col = c("green", "blue"), lty = 1)

注意:sigma是提议分布的标准差,需要调整——如果接受率太低(比如<0.2)就调小sigma,太高(比如>0.5)就调大sigma,一般维持在0.2-0.5之间采样效率最高。

五、你的原函数Falp修正版

如果只是想计算给定x和N的密度值,修正后的函数可以写成这样:

Falp <- function(x, N) { 
  if (any(x <= 0)) stop("x必须大于0哦!")
  1 / ((gamma(1 + 1/x))^N)
}

# 测试
Falp(x = c(0.5, 3), N = 5)

内容的提问来源于stack exchange,提问作者miki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:20:07