考虑一个两态系统, 分别用0/1表示,其转移矩阵可以用一个2x2的跃迁矩阵表示 \[ \begin{bmatrix} 1-p & p \\ p & 1-p \end{bmatrix} \] 其中p为系统在下一步中离开原来状态的概率.
系统依据跃迁矩阵变化的代码如下:
simula <- function(trans, N) {
transita <- function(char, trans) {
sample(colnames(trans), 1, prob = trans[char, ])
}
sim <- integer(N)
sim[1] <- as.integer(sample(colnames(trans), 1))
for (i in 2:N) {
sim[i] <- as.integer(transita(as.character(sim[i - 1]), trans))
}
return(sim)
}
下文中,我们以p=0.1为例,生成一个包含10000个采样的数据集.
tmax <- 10000
p <- 0.1
mat <- matrix(c(1 - p, p, p, 1 - p), ncol = 2, byrow = TRUE)
colnames(mat) <- c("0", "1")
row.names(mat) <- c("0", "1")
data <- simula(mat, tmax)
生成的数据为0和1组成的数组,如
print(data[1:70])
## [1] 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## [36] 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
通过简单计算我们可以知道,数据集的期望为 \[ \left \langle x \right \rangle = (\frac {N}{2} \times 0 + \frac{N}{2} \times 1) / N = 0.5 \] 方差为 \[ \left \langle x^2 \right \rangle - \left \langle x \right \rangle ^2 = 0.5 - (0.5)^2 = 0.25 \] 在计算机模拟等领域,常见的一个错误是将方差作为期望的误差估计给出了.实际上,很多时候当我们得到一个物理量,也就是对一个均值进行了估计之后,关心的是这个估计的精度,也就是这个平均值的误差,而非原随机变量的误差.对于一个涨落很大的随机变量(如压强),其平均值或许已经估计得很准,远远小于其涨落大小,那究竟这个精度该如何计算见后文.
首先给出采样冗余的计算公式(参考文献 Use of the Weighted Histogram Analysis Method for the Analysis of Simulated and Parallel Tempering Simulations, by Chodera, JCTC, 3-26, 2007)
calstateff <- function(skip = 1, N = 10, plt = FALSE) {
ac <- acf(data[(1:(tmax/skip)) * skip], lag.max = lmax/skip, plot = plt)
tau <- sum((1 - (ac$lag/lmax)) * ac$acf) - 1
if (tau < 0)
tau <- 0 #由于数据的噪音有时tau可能取到负值
gf <- 1 + 2 * tau
print(sprintf("skip=%d, Neff=%f", skip, gf))
return(gf)
}
我们取最大时间范围为lmax=400,当取全部数据进行计算时
lmax <- 400
gfdat <- numeric(20)
gfdat[1] <- calstateff(1, lmax, TRUE)
## [1] "skip=1, Neff=10.721383"
可以看到数据冗余量约为10左右,采样效率很低.逐渐加大采样间隔可以得到
for (skip in 2:20) {
gfdat[skip] <- calstateff(skip, lmax)
}
## [1] "skip=2, Neff=5.681595"
## [1] "skip=3, Neff=4.269735"
## [1] "skip=4, Neff=3.360553"
## [1] "skip=5, Neff=2.432393"
## [1] "skip=6, Neff=2.277844"
## [1] "skip=7, Neff=1.816193"
## [1] "skip=8, Neff=1.669858"
## [1] "skip=9, Neff=2.078204"
## [1] "skip=10, Neff=1.598440"
## [1] "skip=11, Neff=1.568251"
## [1] "skip=12, Neff=1.714554"
## [1] "skip=13, Neff=1.532862"
## [1] "skip=14, Neff=1.000000"
## [1] "skip=15, Neff=1.354868"
## [1] "skip=16, Neff=1.306202"
## [1] "skip=17, Neff=1.003490"
## [1] "skip=18, Neff=1.590329"
## [1] "skip=19, Neff=1.625481"
## [1] "skip=20, Neff=1.180311"
在skip大于10后,采样效率达到最大,冗余接近1即没有冗余,采样效率达到最高.
上一节中我们看到,对于一组数据由于其自身的相关性,并不需要取所有的数据点进行计算即可保证信息不会丢失(也就是精度不变),更多的采样并不能增加精度,而过少的采样会造成精度的下降.这一节,我们用bootstrapping方法来验证这一结果.
对于初始的数据集合,可以通过bootstrap方法来估计其平均值的精度.本方法的核心思想在于,以相同概率从原数据集中抽取采样,并将其再放回去继续这一过程,得到一组新的数据,多次重复统计所得均值的分布,即可描述原数据集的性质.代码如下
bootstrapping <- function(dat, n = 100) {
m <- numeric(n)
for (i in 1:n) {
m[i] <- mean(sample(dat, replace = TRUE))
}
return(m)
}
我们以不同的采样间隔构建数据集合,并评估其均值的精度
vardat <- numeric(20)
for (skip in 1:20) {
subdat <- data[(1:(tmax/skip)) * skip]
re <- bootstrapping(subdat, 500)
vardat[skip] <- var(re)
print(sprintf("mean_raw=%f,mean_re=%f, var_re=%f", mean(data), mean(re),
vardat[skip]))
}
## [1] "mean_raw=0.475400,mean_re=0.475098, var_re=0.000024"
## [1] "mean_raw=0.475400,mean_re=0.473792, var_re=0.000054"
## [1] "mean_raw=0.475400,mean_re=0.474940, var_re=0.000073"
## [1] "mean_raw=0.475400,mean_re=0.473638, var_re=0.000105"
## [1] "mean_raw=0.475400,mean_re=0.470961, var_re=0.000118"
## [1] "mean_raw=0.475400,mean_re=0.476696, var_re=0.000150"
## [1] "mean_raw=0.475400,mean_re=0.481789, var_re=0.000175"
## [1] "mean_raw=0.475400,mean_re=0.469251, var_re=0.000193"
## [1] "mean_raw=0.475400,mean_re=0.470734, var_re=0.000224"
## [1] "mean_raw=0.475400,mean_re=0.461850, var_re=0.000250"
## [1] "mean_raw=0.475400,mean_re=0.484262, var_re=0.000256"
## [1] "mean_raw=0.475400,mean_re=0.476992, var_re=0.000320"
## [1] "mean_raw=0.475400,mean_re=0.479347, var_re=0.000297"
## [1] "mean_raw=0.475400,mean_re=0.468571, var_re=0.000360"
## [1] "mean_raw=0.475400,mean_re=0.487850, var_re=0.000386"
## [1] "mean_raw=0.475400,mean_re=0.484570, var_re=0.000394"
## [1] "mean_raw=0.475400,mean_re=0.471850, var_re=0.000428"
## [1] "mean_raw=0.475400,mean_re=0.466984, var_re=0.000425"
## [1] "mean_raw=0.475400,mean_re=0.470388, var_re=0.000489"
## [1] "mean_raw=0.475400,mean_re=0.455916, var_re=0.000528"
实际的精度,还需要乘以采样冗余,我们给出精度随采样间隔的变化
plot(1:20, gfdat * vardat)
虽然有较大噪音,但我们依然可以看出,在skip<10左右的区域,由于没有信息丢失,均值的误差处在同一水平.而skip继续增大时,误差线性增加,也就发生了信息的丢失.