Неверный ответ от интеграции Монте-Карло - PullRequest
0 голосов
/ 16 сентября 2018

Как я могу приблизить интеграл от [x ^ 4 * sin (x)] / [exp (1) ^ (x / 5)] (от 0 до + Inf) методом Монте-Карло в R?

То, что я пытался сделать, это

set.seed(666)
func1 <- function(x)
    {
      (x^4 * sin(x))/exp(1)^(x/5)
    }

n <- 1000000

x <- rexp(n, 0.2)
f <- func1(x)
E <- mean(f)

но результат E неверен

Ответы [ 2 ]

0 голосов
/ 17 сентября 2018

В последующем я намеренно не выставляю случайное семя.


Как я уже упоминал в моих комментариях, есть по крайней мере два вводных вопроса и ответа по интеграции Монте-Карло в переполнении стека:

Оба объяснили, как получить оценку Монте-Карло, но забыли о стандартной ошибке оценки. Просто получается, что оценка Монте-Карло имеет чрезвычайно медленную скорость сходимости по вашей функции.

Общеизвестно, что интеграция Монте-Карло имеет скорость сходимости O(1 / sqrt(N)), где N - это размер выборки, а O() - это big O нотация . Однако константа, стоящая за этим большим O , может быть очень большой для некоторых функций, поэтому реалистическая скорость сходимости может быть намного медленнее.

Ваши функции могут быть определены как минимум двумя способами:

## direct definition
f <- function (x) x^4 * sin(x) * exp(-x/5)

## using gamma distribution; see ?rgamma
g <- function (x) sin(x) * 5 ^ 5 * gamma(5) * dgamma(x, 5, 1/5)

curve(f, from = 0, to = 100)
curve(g, add = TRUE, col = 2)

В первом разделе вопросов и ответов объяснялось, как вычислить интеграцию Монте-Карло с использованием равномерно распределенных выборок. Ваша функция f или g почти равна нулю за пределами x = 200, поэтому интеграция на [0, +Inf) эффективно на [0, 200]. Следующая функция вернет вам интеграцию и ее стандартную ошибку:

MCI1 <- function (n) {
  x <- runif(n, 0, 200)
  y <- 200 * f(x)
  c(mean.default(y), sqrt(var(y) / n))
  }

Другой способ - выборка по важности, как объяснено во 2-м вопросе и ответе. Здесь гамма-распределение используется в качестве распределения предложений (как предложил Бен Болкер).

MCI2 <- function (n) {
  x <- rgamma(n, 5, 0.2)
  y <- sin(x) * 75000
  c(mean.default(y), sqrt(var(y) / n))
  }

Теперь давайте проверим скорость сходимости.

n <- seq(1000, by = 5000, length = 100)
tail(n)
#[1] 471000 476000 481000 486000 491000 496000

b1 <- sapply(n, MCI1)
b2 <- sapply(n, MCI2)

Для равномерной выборки имеем

par(mfrow = c(1, 2))
plot(b1[1, ], main = "estimate")
plot(b1[2, ], main = "standard error")

b1[, (ncol(b1) - 5):ncol(b1)]
#         [,1]     [,2]      [,3]      [,4]      [,5]      [,6]
#[1,] 115.1243 239.9631  55.57149 -325.8631 -140.3745  78.61126
#[2,] 181.0025 179.9988 178.99367  178.2152  177.2193 175.31446

Для гамма-выборки мы имеем

par(mfrow = c(1, 2))
plot(b2[1, ], main = "estimate")
plot(b2[2, ], main = "standard error")

b2[, (ncol(b2) - 5):ncol(b2)]
#           [,1]       [,2]     [,3]      [,4]      [,5]      [,6]
#[1,] -100.70344 -150.71536 24.40841 -49.58032 169.85385 122.81731
#[2,]   77.22445   76.85013 76.53198  76.03692  75.69819  75.25755

Какой бы это ни был метод, обратите внимание, насколько велика стандартная ошибка (по сравнению с самой оценкой) и насколько медленно она уменьшается.

Гораздо проще использовать числовое интегрирование (что неудивительно для интеграции одномерных функций):

integrate(f, 0, 200)
#11.99356 with absolute error < 0.0012

## trapezoidal rule
200 * mean.default(f(seq(0, 200, length = 10000)))
#[1] 11.99236

В трапециевидном правиле, даже если взяты только 1e + 4 равномерно распределенных точки отбора, интегрирование достаточно близко к истине.


Примечание

Интеграция с Монте-Карло была бы менее трудной, если бы мы делали интеграцию в более ограниченной области. Из рисунка f или g мы видим, что это колебательная функция. И на самом деле, он пересекает ось X с периодом pi. Давайте рассмотрим интеграцию на [lower, upper].

MCI3 <- function (n, lower, upper) {
  x <- runif(n, lower, upper)
  y <- (upper - lower) * f(x)
  c(mean.default(y), sqrt(var(y) / n))
  }

a1 <- sapply(n, MCI3, lower = 0, upper = pi)
a2 <- sapply(n, MCI3, lower = pi, upper = 2 * pi)
a3 <- sapply(n, MCI3, lower = 2 * pi, upper = 3 * pi)
a4 <- sapply(n, MCI3, lower = 3 * pi, upper = 4 * pi)

a1[, (ncol(a1) - 5):ncol(a1)]
#            [,1]        [,2]        [,3]        [,4]        [,5]        [,6]
#[1,] 17.04658711 16.97935808 17.01094302 17.02117843 16.96935285 16.99552898
#[2,]  0.02407643  0.02390894  0.02379678  0.02368683  0.02354298  0.02342799

a2[, (ncol(a2) - 5):ncol(a2)]
#             [,1]         [,2]         [,3]         [,4]         [,5]
#[1,] -406.5646843 -404.9633321 -405.4300941 -405.4799659 -405.8337416
#[2,]    0.3476975    0.3463621    0.3442497    0.3425202    0.3409073
#             [,6]
#[1,] -405.8628741
#[2,]    0.3390045

a3[, (ncol(a3) - 5):ncol(a3)]
#            [,1]        [,2]        [,3]        [,4]        [,5]        [,6]
#[1,] 1591.539911 1592.280780 1594.307951 1591.375340 1593.171500 1591.648529
#[2,]    1.197469    1.190251    1.183095    1.177079    1.172049    1.165667

a4[, (ncol(a4) - 5):ncol(a4)]
#             [,1]         [,2]         [,3]         [,4]         [,5]
#[1,] -3235.561677 -3239.147235 -3241.532097 -3238.421556 -3238.667702
#[2,]     2.336684     2.321283     2.311647     2.300856     2.286624
#             [,6]
#[1,] -3237.043068
#[2,]     2.279032
0 голосов
/ 16 сентября 2018

Если вы собираетесь производить выборку по экспоненте, ее не следует использовать снова в функции.

Из кода

set.seed(32345)

func <- function(x) { (x^4 * sin(x)) }

n <- 10000000

x <- rexp(n, 0.2)
f <- func(x)
E <- mean(f)

Я получаю ответ

[1] 13.06643

ОБНОВЛЕНИЕ

Оно колеблется и сильно колеблется.

Не стоит сначала начинать с правильного ответа, который согласно Mathematica равен 4453125/371293 = 11.9936.

Я преобразовал интеграл из

I = ∫ dx exp (-x / 5) x 4 sin (x)

с использованием подстановки y=x/5 в

I = 5 5 Γ (5) y dy exp (-y) y 5-1 / Γ (5) sin (5 * y)

Все, кроме sin(5*y) - это нормализованное гамма-распределение, которое мы будем использовать для выборки, а sin(5*y) будет нашей функцией для вычисления среднего значения.

И использовал следующий трюк вместе с большим количеством выборок: я разделилрасчет положительных и отрицательных значений.Это помогает, если у вас есть колеблющийся ответ со значениями, отменяющими друг друга.Я также делал расчеты партиями.Гамма-функция 5 - это всего лишь 4!(факториал)

Код

set.seed(32345)

N  <- 10000000 # number of samples per batch
NN <- 640      # number of batches

pos <- rep(0, NN) # positive values
neg <- rep(0, NN) # negative values

for(k in 1:NN) { # loop over batches
    y <- rgamma(N, shape=5, scale=1)
    f <- sin(5.0 * y)
    pnf <- ifelse(f > 0.0, f, 0.0)
    pos[k] <- mean(pnf)
    pnf <- ifelse(f < 0.0, -f, 0.0)
    neg[k] <- mean(pnf)
    print(k)
}

mean(pos)
sd(pos)/sqrt(NN)

mean(neg)
sd(neg)/sqrt(NN)

5*5*5*5*5*4*3*2*(mean(pos) - mean(neg))

Вывод

> mean(pos)
[1] 0.3183912
> sd(pos)/sqrt(NN)
[1] 4.749269e-06
> 
> mean(neg)
[1] 0.3182223
> sd(neg)/sqrt(NN)
[1] 5.087734e-06
> 
> 5*5*5*5*5*4*3*2*(mean(pos) - mean(neg))
[1] 12.67078

Вы можете видеть, что мы действительно вычисляем разницу двух очень близких значений, поэтому труднополучить сближение.На моей рабочей станции Xeon потребовалось чуть более 20 минут.

И с другим начальным числом = 12345

> mean(pos)
[1] 0.3183917
> sd(pos)/sqrt(NN)
[1] 4.835424e-06
> 
> mean(neg)
[1] 0.3182268
> sd(neg)/sqrt(NN)
[1] 4.633129e-06
> 
> 5*5*5*5*5*4*3*2*(mean(pos) - mean(neg))
[1] 12.36735 
...