gpt4 book ai didi

r - 样本大小和概率不同时的高效多项式抽样

转载 作者:行者123 更新时间:2023-12-04 17:48:51 25 4
gpt4 key购买 nike

这个问题与从具有不同样本大小和概率的多项分布中进行有效抽样有关。下面我描述了我使用的方法,但不知道是否可以通过一些智能矢量化来改进它。

我正在模拟生物在多个种群中的扩散。来自总体的个体 j分散到人群i概率p[i, j] .假设种群 1 中的初始丰度为 10,以及扩散概率 c(0.1, 0.3, 0.6)分别对种群 1、2 和 3,我们可以用 rmultinom 模拟扩散过程。 :

set.seed(1)
rmultinom(1, 10, c(0.1, 0.3, 0.6))

# [,1]
# [1,] 0
# [2,] 3
# [3,] 7

我们可以扩展它以考虑 n来源人群:
set.seed(1)
n <- 3
p <- replicate(n, diff(c(0, sort(runif(n-1)), 1)))
X <- sample(100, n)

以上, p是从一个总体(列)移动到另一个(行)的概率矩阵,并且 X是初始种群大小的向量。现在可以使用以下方法模拟分散在每对种群(以及留在原地的种群)之间的个体数量:
sapply(seq_len(ncol(p)), function(i) {
rmultinom(1, X[i], p[, i])
})

# [,1] [,2] [,3]
# [1,] 19 42 11
# [2,] 8 18 43
# [3,] 68 6 8

其中 i 处元素的值第 1 行和 j第 th 列是从总体 j 中移动的个体数人口 i . rowSums这个矩阵给出了新的人口规模。

我想用常数概率矩阵重复多次,但具有不同的(预定义的)初始丰度。下面的小例子实现了这一点,但对于更大的问题效率低下。得到的矩阵给出了三个种群中每个种群的分散后丰度,其中每个种群具有不同的初始丰度。
X <- matrix(sample(100, n*5, replace=TRUE), nrow=n)

apply(sapply(apply(X, 2, function(x) {
lapply(seq_len(ncol(p)), function(i) {
rmultinom(1, x[i], p[, i])
})
}), function(x) do.call(cbind, x), simplify='array'), 3, rowSums)

# [,1] [,2] [,3] [,4] [,5]
# [1,] 79 67 45 28 74
# [2,] 92 99 40 19 52
# [3,] 51 45 16 21 35

有没有办法更好地矢量化这个问题?

最佳答案

这是多项式的 RcppGSL 实现。但是,它需要您独立安装gsl....这可能不太实用。

// [[Rcpp::depends(RcppGSL)]]

#include <RcppGSL.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <unistd.h> // getpid

Rcpp::IntegerVector rmn(unsigned int N, Rcpp::NumericVector p, gsl_rng* r){

size_t K = p.size();

Rcpp::IntegerVector x(K);
gsl_ran_multinomial(r, K, N, p.begin(), (unsigned int *) x.begin());
return x; // return results vector
}

Rcpp::IntegerVector gsl_mmm_1(Rcpp::IntegerVector N, Rcpp::NumericMatrix P, gsl_rng* r){
size_t K = N.size();
int i;
Rcpp::IntegerVector x(K);
for(i=0; i<K; i++){
x += rmn(N[i], P(Rcpp::_, i), r);
}
return x;
}

// [[Rcpp::export]]
Rcpp::IntegerMatrix gsl_mmm(Rcpp::IntegerMatrix X_, Rcpp::NumericMatrix P){
int j;
gsl_rng * r = gsl_rng_alloc (gsl_rng_mt19937);
long seed = rand()/(((double)RAND_MAX + 1)/10000000) * getpid();
gsl_rng_set (r, seed);
Rcpp::IntegerMatrix X(X_.nrow(), X_.ncol());
for(j=0; j<X.ncol(); j++){
X(Rcpp::_, j) = gsl_mmm_1(X_(Rcpp::_,j), P, r);
}
gsl_rng_free (r);
return X;
}

我还将它与纯 R 实现和 jbaums 的版本进行了比较
library(Rcpp)
library(microbenchmark)
sourceCpp("gsl.cpp")

P = matrix(c(c(0.1,0.2,0.7),c(0.3,0.3,0.4),c(0.5,0.3,0.2)),nc=3)
X = matrix(c(c(30,40,30),c(20,40,40)), nc=2)

mmm = function(X, P){
n = ncol(X)
p = nrow(X)
Reduce("+", lapply(1:p, function(j) {
Y = matrix(0,p,n)
for(i in 1:n) Y[,i] = rmultinom(1, X[j,i], P[,j])
Y
}))
}

jbaums = function(X,P){
apply(sapply(apply(X, 2, function(x) {
lapply(seq_len(ncol(P)), function(i) {
rmultinom(1, x[i], P[, i])
})
}), function(x) do.call(cbind, x), simplify='array'), nrow(X), rowSums)
}
microbenchmark(jbaums(X,P), mmm(X,P), gsl_mmm(X, P))

这就是结果
> microbenchmark(jbaums(X,P), mmm(X,P), gsl_mmm(X, P))
Unit: microseconds
expr min lq median uq max neval
jbaums(X, P) 165.832 172.8420 179.185 187.2810 339.280 100
mmm(X, P) 60.071 63.5955 67.437 71.5775 92.963 100
gsl_mmm(X, P) 10.529 11.8800 13.671 14.6220 40.857 100

gsl 版本比我的纯 R 版本快 6 倍。

关于r - 样本大小和概率不同时的高效多项式抽样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23097269/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com