Использование optimize() для поиска кратчайшего интервала, занимающего 95% площади под кривой в R.

Предыстория:

У меня есть кривая, значения Y которой получены моей небольшой R-функцией ниже (аккуратно аннотированной). Если вы запустите весь мой код R, вы увидите мою кривую (но помните, что это функция, поэтому, если бы я изменил значения аргументов, я мог бы получить другую кривую):

введите здесь описание изображения

Вопрос:

Очевидно, можно определить/предполагать множество интервалов, которые охватывают/занимают 95% всей площади под этой кривой. Но как с помощью optimize() найти САМЫЙ КРАТЧАЙШИЙ (в единицах x-значения) из множества возможных 95% интервалов? Какими тогда будут соответствующие значения x для двух концов этого кратчайшего 95-процентного интервала?

Примечание. Идея кратчайшего интервала для одномодальной кривой, такой как моя, имеет смысл. На самом деле самым коротким будет тот, который имеет тенденцию быть ближе к середине, где высота (значение y) больше, поэтому значение x не обязательно должно быть таким большим, чтобы предполагаемый интервал покрывал / занимал 95 % от общей площади под кривой.

Вот мой код R (пожалуйста, запустите весь код):

ppp <- function(f, N, df1, df2, petasq, alpha, beta) {

 pp <- function(petasq) dbeta(petasq, alpha, beta)
 ll <- function(petasq) df(f, df1, df2, (petasq * N) / (1 - petasq) )

 marg <- integrate(function(x) pp(x)*ll(x), 0, 1)[[1]]

po <- function(x) pp(x)*ll(x) / marg
return(po(petasq) )

}
## @@@ END OF MY R FUNCTION.

# Now I use my function above to get the y-values for my plot:

petasq  <- seq(0, 1, by = .0001) ## These are X-values for my plot
f  <- 30       # a function needed argument
df1 <- 3       # a function needed argument
df2 <- 108     # a function needed argument
N  <- 120      # a function needed argument
alpha = 5      # a function needed argument
beta = 4       # a function needed argument


## Now use the ppp() function to get the Y-values for the X-value range above:
y.values <- ppp(f, N, df1, df2, petasq, alpha, beta)

## Finally plot petasq (as X-values) against the Y.values:
plot(petasq, y.values, ty="l", lwd = 3 )

person rnorouzian    schedule 07.04.2017    source источник


Ответы (3)


Основываясь на вашем пересмотренном вопросе, я нашел оптимизацию, которая минимизирует КРАТЧАЙШЕЕ расстояние (в единицах x-значения) между ЛЕВОЙ и ПРАВОЙ границами:

ppp <- function(petasq, f, N, df1, df2, alpha, beta) {

 pp <- function(petasq) dbeta(petasq, alpha, beta)
 ll <- function(petasq) df(f, df1, df2, (petasq * N) / (1 - petasq) )

 marg <- integrate(function(x) pp(x)*ll(x), 0, 1)[[1]]

po <- function(x) pp(x)*ll(x) / marg
return(po(petasq) )
}

petasq  <- seq(0, 1, by = .0001) ## These are X-values for my plot
f  <- 30       # a function needed argument
df1 <- 3       # a function needed argument
df2 <- 108     # a function needed argument
N  <- 120      # a function needed argument
alpha = 5      # a function needed argument
beta = 4       # a function needed argument

optim_func <- function(x_left) {
    int_function <- function(petasq) {
        ppp(petasq, f=f, N=N, df1=df1, df2=df2, alpha=alpha, beta=beta)
    }

    # For every LEFT value, find the corresponding RIGHT value that gives 95% area.  

    find_95_right <- function(x_right) {
        (0.95 - integrate(int_function, lower=x_left, upper=x_right, subdivisions = 10000)$value)^2
    }
    x_right_obj <- optimize(f=find_95_right, interval=c(0.5,1))
    if(x_right_obj$objective > .Machine$double.eps^0.25) return(100)

    #Return the DISTANCE BETWEEN LEFT AND RIGHT
    return(x_right_obj$minimum - x_left)
}

#MINIMIZE THE DISTANCE BETWEEN LEFT AND RIGHT
x_left <- optimize(f=optim_func, interval=c(0.30,0.40))$minimum
find_95_right <- function(x_right) {
    (0.95 - integrate(int_function, lower=x_left, upper=x_right, subdivisions = 10000)$value)^2
}
    int_function <- function(petasq) {
        ppp(petasq, f=f, N=N, df1=df1, df2=df2, alpha=alpha, beta=beta)
    }
x_right <- optimize(f=find_95_right, interval=c(0.5,1))$minimum

Смотрите комментарии в коде. Надеюсь, это, наконец, удовлетворит ваш вопрос :) Результаты:

> x_right
[1] 0.5409488
> x_left
[1] 0.3201584

Кроме того, вы можете построить расстояние между LEFT и RIGHT как функцию левой границы:

left_x_values <- seq(0.30, 0.335, 0.0001)
DISTANCE <- sapply(left_x_values, optim_func)

plot(left_x_values, DISTANCE, type="l")

сюжет

person thc    schedule 08.04.2017
comment
Я получаю следующую ошибку после запуска вашей последней строки: > x_right <- optimize(f=find_95_right, interval=c(0.5,1))$minimum Error in match.fun(f) : object 'int_function' not found Called from: match.fun(f) - person rnorouzian; 08.04.2017
comment
thc, я действительно (очень, очень) ценю ваш ответ и опыт. Пожалуйста, позвольте мне тщательно проверить это, чтобы увидеть, дает ли он самый короткий интервал 95% из всех. И я дам вам знать. Огромное спасибо. - person rnorouzian; 08.04.2017
comment
О боже! Ваш метод дает совершенно неправильные результаты! Просто измените f с 30 на f = 5, чтобы увидеть, насколько ошибочными будут результаты!!! - person rnorouzian; 08.04.2017
comment
Интервал поиска устанавливается от 0,3 до 0,4. Это на самом деле работает отлично... Измените интервал поиска... не думайте, что все будет просто ложкой. - person thc; 09.04.2017
comment
Пожалуйста, примите мои извинения за то, что я не полностью знаком с optimize() в R, поэтому весь диапазон поддержки (значения по оси x) ограничен между 0 и 1. Пик кривой может быть где угодно. Итак, чтобы значения left_x и right_x были всегда (независимо от того, как изменяются входные значения), как мне лучше всего установить интервал для x_left и x_right? - person rnorouzian; 09.04.2017
comment
В этой строке: x_left ‹- optimise(f=optim_func, interval=c(0.30,0.40))$minimum, измените интервал на ок. где будет значение LEFT x. - person thc; 10.04.2017
comment
Ох, если бы это каждый раз корректировалось вручную, то было бы очень сложно использовать его в динамически изменяющемся процессе, где входными значениями могло бы быть что угодно. - person rnorouzian; 10.04.2017

Если мы представим это как попытку вычислить интервал с наименьшей площадью, мы можем начать вычислять площади каждой из областей, которые мы наносим на график. Затем мы можем найти самую большую область (которая, предположительно, будет недалеко от центра) и начать идти, пока не найдем область, которую ищем.

Поскольку вы уже вычислили значения x и y для графика, я повторно использую их, чтобы сохранить некоторые расчеты. Вот реализация этого алгоритма

pseduoarea <- function(x, y, target=.95) {
  dx <- diff(x)
  areas <- dx * .5 * (head(y,-1) + tail(y, -1))
  peak <- which.max(areas)
  range <- c(peak, peak)
  found <- areas[peak]
  while(found < target) {
    if(areas[range[1]-1] > areas[range[2]+1]) {
      range[1] <- range[1]-1
      found <- found + areas[range[1]-1]
    } else {
      range[2] <- range[2]+1
      found <- found + areas[range[2]+1]
    }   
  }
  val<-x[range]
  attr(val, "indexes")<-range
  attr(val, "area")<-found
  return(val)
}

И мы называем это с

pseduoarea(petasq, y.values)
# [1] 0.3194 0.5413

Это предполагает, что все значения в petasq расположены на одинаковом расстоянии друг от друга.

person MrFlick    schedule 07.04.2017
comment
MrFlick, возможно ли, что ваша функция выше изменена, чтобы она также могла находить 95% интервалов в half-curves [т.е. усеченных распределениях]? - person rnorouzian; 23.12.2017

Я не думаю, что вам нужно использовать оптимизацию (если только это не было частью недопустимого домашнего задания). Вместо этого просто нормализуйте кумулятивную сумму и выясните, в каких точках выполняются ваши критерии:

> which(cusm.y >= 0.025)[1]
[1] 3163
> which(cusm.y >= 0.975)[1]
[1] 5375

Вы можете проверить, что это разумные индексы для использования для извлечения значений из вектора petasq с помощью:

abline( v= c( petasq[  c( which(cusm.y >= 0.025)[1], which(cusm.y >= 0.975)[1])]),
        col="red")

Это, по общему признанию, эквивалентно построению функции интегрирования с константой нормализации в области определения функции «плотности». Тот факт, что все интервалы имеют одинаковую размерность, позволяет исключить разность вектора «x» при расчете высоты, умноженной на основание.

введите здесь описание изображения

Я полагаю, что возможна и другая интерпретация. Это потребует, чтобы мы выяснили, сколько значений отсортированной по возрастанию версии petasq необходимо, чтобы в сумме получить 95% от общей суммы. Это дает другую стратегию, и график показывает, где горизонтальная линия пересекает кривую:

which( cumsum( sort( y.values, decreasing=TRUE) ) > 0.95* sum(y.values, na.rm=TRUE) )[1]
#[1] 2208
sort( y.values, decreasing=TRUE)[2208]
#[1] 1.059978
png()
  plot(petasq, y.values, ty="l", lwd = 3 )
  abline( h=sort( y.values, decreasing=TRUE)[2208], col="blue")
dev.off()

введите здесь описание изображения

Чтобы получить значения petasq, вам нужно определить первое значение y.values, превышающее это значение, а затем следующее значение y.values, значение которого опустилось ниже этого уровня. Их можно получить через:

order(y.values, decreasing=TRUE)[2208]
#[1] 3202
order(y.values, decreasing=TRUE)[2209]
#[1] 5410

И тогда сюжет будет выглядеть так:

png(); plot(petasq, y.values, ty="l", lwd = 3 )
      abline( v=  petasq[  c(3202, 5410)], col="blue", lty=3, lwd=2)
dev.off()

Площадь между двумя пунктирными синими линиями составляет 95% от общей площади над нулевой линией:

введите здесь описание изображения

person IRTFM    schedule 07.04.2017
comment
Спасибо за отзыв! Не домашнее задание или ЧТО-НИБУДЬ связанное с этим! - person rnorouzian; 08.04.2017
comment
@парвин карими. Вы хотите объяснить, что вы считаете неправильным в этом? - person IRTFM; 08.04.2017
comment
Да. Это то, что, как я думал, было запрошено. Если требуется что-то другое, вам следует отредактировать свой вопрос, чтобы сделать запрос более ясным. Вы до сих пор не проголосовали ни за один ответ, не говоря уже о том, чтобы поставить галочку, и я не первый человек, который явно неправильно понял ваш вопрос. - person IRTFM; 08.04.2017
comment
Пожалуйста, отредактируйте свой вопрос. Часть с самой высокой плотностью оказалась неоднозначной для некоторых из нас. Вам нужно стать более математически точным в своем запросе. - person IRTFM; 08.04.2017
comment
(Возможно) Теперь я понимаю. - person IRTFM; 08.04.2017
comment
-42, не могли бы вы объяснить свой код в желтом ящике? Он не работает так, как отображается в желтом поле, я имею в виду: order(y.values, decreasing=TRUE)2208 3202 order(y.values, decreasing=TRUE)2209 5410 - person rnorouzian; 08.04.2017
comment
Я просто забыл сделать отступ блока кода. Я почистил его. - person IRTFM; 08.04.2017
comment
Итак, ваша ВТОРАЯ стратегия заключается в том, что вы создаете горизонтальную линию и, начиная с вершины кривой, опускаете горизонтальную линию вверх до тех пор, пока область над горизонтальной линией не покроет 95% общей площади кривой? Правильно ли я понимаю вашу вторую стратегию? - person rnorouzian; 25.04.2017