Вычислить площадь под кривой
Я хотел бы, чтобы вычислить площадь под кривой, чтобы сделать интеграцию без определения функции, такие как integrate()
.
мои данные выглядят так:
Date Strike Volatility
2003-01-01 20 0.2
2003-01-01 30 0.3
2003-01-01 40 0.4
etc.
график plot(strike, volatility)
чтобы посмотреть на волатильность улыбки. Есть ли способ интегрировать эту построенную "кривую"?
7 ответов:
AUC аппроксимируется довольно легко, глядя на множество фигур трапеции, каждый раз связанных между
x_i
,x_{i+1}
,y{i+1}
иy_i
. Используя rollmean пакета зоопарка, вы можете сделать:library(zoo) x <- 1:10 y <- 3*x+25 id <- order(x) AUC <- sum(diff(x[id])*rollmean(y[id],2))
убедитесь, что вы заказываете значения x, или ваш результат не будет иметь смысла. Если у вас есть отрицательные значения где-то вдоль оси y, вам нужно будет выяснить, как именно вы хотите определить область под кривой и настроить ее соответствующим образом (например, используя
abs()
)Что касается вашего последующего наблюдения: если у вас нет формальной функции, как бы Вы ее построили? Так что если у вас есть только значения, единственное, что можно аппроксимировать определенный интеграл. Даже если у вас есть функция в R, вы можете вычислить только определенные интегралы с помощью
integrate()
. Построение формальной функции возможно только в том случае, если вы также можете ее определить.
просто добавьте в свою программу следующее, И вы получите область под кривой:
require(pracma) AUC = trapz(strike,volatility)
С
?trapz
:этот подход точно соответствует приближению для интегрирования функция, использующая трапециевидное правило с базовыми точками x.
еще три варианта, в том числе один с использованием метода сплайна и один с использованием правила Симпсона...
# get data n <- 100 mean <- 50 sd <- 50 x <- seq(20, 80, length=n) y <- dnorm(x, mean, sd) *100 # using sintegral in Bolstad2 require(Bolstad2) sintegral(x,y)$int # using auc in MESS require(MESS) auc(x,y, type = 'spline') # using integrate.xy in sfsmisc require(sfsmisc) integrate.xy(x,y)
трапециевидный метод менее точен, чем сплайновый метод, поэтому
MESS::auc
(использует метод сплайн) илиBolstad2::sintegral
(использует правило Симпсона), вероятно, следует предпочесть. DIY версии этих (и дополнительный подход с использованием квадратурного правила) находятся здесь:http://www.r-bloggers.com/one-dimensional-integrals/
хорошо, так что я прибываю немного поздно на вечеринке, но идя по ответам простой
R
решение проблемы отсутствует. Вот так, просто и чисто:sum(diff(x) * (head(y,-1)+tail(y,-1)))/2
решение для OP тогда читается как:
sum(diff(strike) * (head(volatility,-1)+tail(volatility,-1)))/2
это эффективно вычисляет площадь с помощью трапециевидного метода, принимая среднее значение "левого" и "правого" y-значений.
NB: как уже указал @Joris, вы можете использовать
abs(y)
если это будет иметь больше смысла.
в мире фармакокинетики (PK) вычисление различных типов AUC является общей и фундаментальной задачей. Есть много различных расчетов AUC для фармакокиетики, таких как
- AUC0-t = AUC от нуля до времени t
- AUC0-last = AUC от нуля до последней точки времени (может быть такой же, как выше)
- AUC0-inf = AUC от нуля до бесконечности времени
- AUCint = AUC за интервал времени
- AUCall = AUC over весь период времени, за который имеются данные
одним из лучших пакетов, который выполняет эти вычисления, является относительно новый пакет
PKNCA
от людей в Pfizer. Проверить его.
ответ Джориса Мейса было здорово, но я изо всех сил пытался удалить NAs из моих образцов. Вот небольшая функция, которую я написал, чтобы справиться с ними:
library(zoo) #for the rollmean function ###### #' Calculate the Area Under Curve of y~x #' #'@param y Your y values (measures ?) #'@param x Your x values (time ?) #'@param start : The first x value #'@param stop : The last x value #'@param na.stop : returns NA if one value is NA #'@param ex.na.stop : returns NA if the first or the last value is NA #' #'@examples #'myX = 1:5 #'myY = c(17, 25, NA, 35, 56) #'auc(myY, myX) #'auc(myY, myX, na.stop=TRUE) #'myY = c(17, 25, 28, 35, NA) #'auc(myY, myX, ex.na.stop=FALSE) auc = function(y, x, start=first(x), stop=last(x), na.stop=FALSE, ex.na.stop=TRUE){ if(all(is.na(y))) return(NA) bounds = which(x==start):which(x==stop) x=x[bounds] y=y[bounds] r = which(is.na(y)) if(length(r)>0){ if(na.stop==TRUE) return(NA) if(ex.na.stop==TRUE & (is.na(first(y)) | is.na(last(y)))) return(NA) if(is.na(last(y))) warning("Last value is NA, so this AUC is bad and you should feel bad", call. = FALSE) if(is.na(first(y))) warning("First value is NA, so this AUC is bad and you should feel bad", call. = FALSE) x = x[-r] y = y[-r] } sum(diff(x[order(x)])*rollmean(y[order(x)],2)) }
затем я использую его с применением на мой фрейм данных:
myDF$auc = apply(myDF, MARGIN=1, FUN=auc, x=c(0,5,10,15,20))
надеюсь, что это может помочь noobs, как я : -)
изменить: добавлены границы