模拟一个近似伽玛分布的AR(1)过程。

huangapple go评论51阅读模式
英文:

Simulate an AR(1) process that approximates a gamma distribution

问题

我想模拟一个AR(1)时间序列,该序列近似于伽玛分布而不是正态分布。我希望结果具有指定的速率和形状,并具有给定的phi的AR(1)过程。我已经看到这个帖子,并理解严格的伽玛模拟存在问题,但我对近似形状和速率的结果会感到满意。粗略调整形状和速率,作为phi的函数,可能已经足够满足我的需求。有什么想法?

例如,

n <- 500
foo <- rgamma(n = n, shape = 1.5 , rate = 5)

phi <- 0.3
bar <- arima.sim(list(order = c(1,0,0), ar = phi), n = n, 
                 rand.gen = rgamma, shape = 1.5,
                 rate = 5)

ggplot() + 
  geom_density(aes(x=foo),fill="#FF8C00",alpha=0.5) + 
  geom_density(aes(x=bar),fill="#A034F0",alpha=0.5)

<details>
<summary>英文:</summary>

I’d like to simulate an AR(1) time series that approximates a gamma distribution rather than a normal distribution. I’d like the result to have a specified rate and shape along with a AR(1) process with a given phi. I have seen this [post][1] and understand that a strict gamma simulation is problematic, but I&#39;d be satisfied with a result that approximates the shape and rate. Some crude adjustment of shape and rate as a function of phi is likely enough for my needs. Any idea?

E.g.,

n <- 500
foo <- rgamma(n = n, shape = 1.5 , rate = 5)

phi <- 0.3
bar <- arima.sim(list(order = c(1,0,0), ar = phi), n = n,
rand.gen = rgamma, shape = 1.5,
rate = 5)

ggplot() +
geom_density(aes(x=foo),fill="#FF8C00",alpha=0.5) +
geom_density(aes(x=bar),fill="#A034F0",alpha=0.5)



  [1]: https://stats.stackexchange.com/questions/180109/generate-a-random-variable-which-follow-gamma-distribution-and-ar1-process-sim

</details>


# 答案1
**得分**: 2

从[这个CV回答][1]中借用函数,我们可以首先从所需的分布中进行采样,然后 *重新排序* 这些样本以近似来自AR过程的期望ACF。

```R
set.seed(721893540)

n <- 500
foo <- rgamma(n = n, shape = 1.5 , rate = 5)
phi <- 0.3

# 匹配前4个滞后的自相关,当自相关(当n -&gt; Inf时)首次下降到0.01以下
alpha <- phi^(0:ceiling(log(0.01)/log(0.3)))

# 重新排序foo以获得所需的ACF(ARIMA(0,0,1),phi = 0.3)
bar <- acf.reorder(foo, alpha)

bar的ACF将与alpha更接近,而不是从随机生成的AR(1)中预期的:

# 随机高斯AR(1)的自相关函数:
ACF <- acf(arima.sim(list(order = c(1,0,0), ar = phi), n), plot = 0)$acf

data.frame(
  normal = ACF[1:length(alpha)],
  gamma = acf(bar, length(alpha) - 1, plot = 0)$acf
)
#&gt;         normal      gamma
#&gt; 1  1.000000000 1.00000000
#&gt; 2  0.334034734 0.29929104
#&gt; 3  0.060370711 0.09063563
#&gt; 4  0.001948240 0.03818762
#&gt; 5 -0.004354808 0.01196619

如果这种行为不理想,一个选项是将alpha设置为从随机生成的AR(1)的ACF(直到它不再单调下降):

alpha <- ACF[1:which.max(diff(ACF) > 0)]
bar2 <- acf.reorder(foo, alpha)

data.frame(
  normal = ACF[1:length(alpha)],
  gamma = acf(bar, length(alpha) - 1, plot = 0)$acf,
  gamma2 = acf(bar2, length(alpha) - 1, plot = 0)$acf
)
#&gt;         normal      gamma       gamma2
#&gt; 1  1.000000000 1.00000000  1.000000000
#&gt; 2  0.334034734 0.29929104  0.333494498
#&gt; 3  0.060370711 0.09063563  0.060757048
#&gt; 4  0.001948240 0.03818762 -0.017663549
#&gt; 5 -0.004354808 0.01196619  0.008826011

为了方便,包括acf.reorder函数:

acf.reorder <- function(x, alpha) {
  tol <- 1e-5
  maxIter <- 10L
  n <- length(x)
  xx <- sort(x)
  y <- rnorm(n)
  w0 <- w <- alpha1 <- alpha
  m <- length(alpha)
  i1 <- sequence((m - 1):1)
  i2 <- sequence((m - 1):1, 2:m)
  i3 <- cumsum((m - 1):1)
  tol10 <- tol/10
  iter <- 0L
  x <- xx[rank(filter(y, w, circular = TRUE))]
  SSE0 <- Inf
  f <- function(ww) {
    sum((c(1, diff(c(0, cumsum(ww[i1]*(ww[i2]))[i3]))/sum(ww^2)) - alpha1)^2)
  }
  ACF <- function(x) acf(x, lag.max = m - 1, plot = FALSE)$acf[1:m]
  
  while ((SSE <- sum((ACF(x) - alpha)^2)) > tol) {
    if (SSE < SSE0) {
      SSE0 <- SSE
      w <- w0
    }
    if ((iter <- iter + 1L) == maxIter) break
    w1 <- w0
    a <- 0
    sse0 <- Inf
    
    while (max(abs(alpha1 - a)) > tol10) {
      a <- c(1, diff(c(0, cumsum(w1[i1]*(ww1[i2]))[i3]))/sum(w1^2))
      
      if ((sse <- sum((a - alpha1)^2)) < sse0) {
        sse0 <- sse
        w0 <- w1
      } else {
        # w0 failed to converge; try optim
        w1 <- optim(w0, f, method = "L-BFGS-B")$par
        a <- c(1, diff(c(0, cumsum(w1[i1]*(w1[i2]))[i3]))/sum(w1^2))
        if (sum((a - alpha1)^2) < sse0) w0 <- w1
        break
      }
      
      w1 <- (w1*alpha1/a + w1)/2
    }
    
    x <- xx[rank(filter(y, w0, circular = TRUE))]
    alpha1 <- (alpha1*alpha/ACF(x) + alpha1)/2
  }
  
  xx[rank(filter(y, w, circular = TRUE))]
}
英文:

Borrowing the function from this CV answer, we can first sample from the desired distribution, then reorder the samples to approximate the expected ACF from the AR process.

set.seed(721893540)
n &lt;- 500
foo &lt;- rgamma(n = n, shape = 1.5 , rate = 5)
phi &lt;- 0.3
# match the autocorrelation for the first 4 lags, when the
# autocorrelation (in the limit as n -&gt; Inf) first drops below 0.01
alpha &lt;- phi^(0:ceiling(log(0.01)/log(0.3)))
# reorder foo to get the desired ACF (ARIMA(0,0,1), phi = 0.3)
bar &lt;- acf.reorder(foo, alpha)

The ACF of bar will match alpha more closely than would be expected from a randomly generated AR(1):

# autocorrelation function of a random Gaussian AR(1):
ACF &lt;- acf(arima.sim(list(order = c(1,0,0), ar = phi), n), plot = 0)$acf
data.frame(
normal = ACF[1:length(alpha)],
gamma = acf(bar, length(alpha) - 1, plot = 0)$acf
)
#&gt;         normal      gamma
#&gt; 1  1.000000000 1.00000000
#&gt; 2  0.334034734 0.29929104
#&gt; 3  0.060370711 0.09063563
#&gt; 4  0.001948240 0.03818762
#&gt; 5 -0.004354808 0.01196619

If this behavior is undesirable, one option is to set alpha to the ACF from a randomly generated AR(1) (until it stops decreasing monotonically).

alpha &lt;- ACF[1:which.max(diff(ACF) &gt; 0)]
bar2 &lt;- acf.reorder(foo, alpha)
data.frame(
normal = ACF[1:length(alpha)],
gamma = acf(bar, length(alpha) - 1, plot = 0)$acf,
gamma2 = acf(bar2, length(alpha) - 1, plot = 0)$acf
)
#&gt;         normal      gamma       gamma2
#&gt; 1  1.000000000 1.00000000  1.000000000
#&gt; 2  0.334034734 0.29929104  0.333494498
#&gt; 3  0.060370711 0.09063563  0.060757048
#&gt; 4  0.001948240 0.03818762 -0.017663549
#&gt; 5 -0.004354808 0.01196619  0.008826011

Including acf.reorder for convenience.

acf.reorder &lt;- function(x, alpha) {
tol &lt;- 1e-5
maxIter &lt;- 10L
n &lt;- length(x)
xx &lt;- sort(x)
y &lt;- rnorm(n)
w0 &lt;- w &lt;- alpha1 &lt;- alpha
m &lt;- length(alpha)
i1 &lt;- sequence((m - 1):1)
i2 &lt;- sequence((m - 1):1, 2:m)
i3 &lt;- cumsum((m - 1):1)
tol10 &lt;- tol/10
iter &lt;- 0L
x &lt;- xx[rank(filter(y, w, circular = TRUE))]
SSE0 &lt;- Inf
f &lt;- function(ww) {
sum((c(1, diff(c(0, cumsum(ww[i1]*(ww[i2]))[i3]))/sum(ww^2)) - alpha1)^2)
}
ACF &lt;- function(x) acf(x, lag.max = m - 1, plot = FALSE)$acf[1:m]
while ((SSE &lt;- sum((ACF(x) - alpha)^2)) &gt; tol) {
if (SSE &lt; SSE0) {
SSE0 &lt;- SSE
w &lt;- w0
}
if ((iter &lt;- iter + 1L) == maxIter) break
w1 &lt;- w0
a &lt;- 0
sse0 &lt;- Inf
while (max(abs(alpha1 - a)) &gt; tol10) {
a &lt;- c(1, diff(c(0, cumsum(w1[i1]*(w1[i2]))[i3]))/sum(w1^2))
if ((sse &lt;- sum((a - alpha1)^2)) &lt; sse0) {
sse0 &lt;- sse
w0 &lt;- w1
} else {
# w0 failed to converge; try optim
w1 &lt;- optim(w0, f, method = &quot;L-BFGS-B&quot;)$par
a &lt;- c(1, diff(c(0, cumsum(w1[i1]*(w1[i2]))[i3]))/sum(w1^2))
if (sum((a - alpha1)^2) &lt; sse0) w0 &lt;- w1
break
}
w1 &lt;- (w1*alpha1/a + w1)/2
}
x &lt;- xx[rank(filter(y, w0, circular = TRUE))]
alpha1 &lt;- (alpha1*alpha/ACF(x) + alpha1)/2
}
xx[rank(filter(y, w, circular = TRUE))]
}

huangapple
  • 本文由 发表于 2023年7月7日 02:33:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76631654.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定