web-dev-qa-db-ja.com

曲線下面積を計算する

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)をプロットしました。このプロットされた「曲線」を統合する方法はありますか?

56
Dani

AUCは、毎回_x_i_、_x_{i+1}_、_y{i+1}_、_y_i_の範囲で区切られた多数の台形図を見ることで、簡単に近似できます。 Zooパッケージの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()を使用して定積分のみを計算できます。正式な関数のプロットは、定義できる場合にのみ可能です。

41
Joris Meys

プログラムに次を追加するだけで、曲線の下の領域が得られます。

require(pracma)
AUC = trapz(strike,volatility)

?trapzから:

このアプローチは、ベースポイントxの台形規則を使用して関数を統合するための近似と正確に一致します。

32
simon

スプライン法を使用するオプションとシンプソンのルールを使用するオプションを含む、さらに3つのオプション...

# 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/

21
Ben

OKなので、パーティーに少し遅れて到着しましたが、答えを調べてみると、問題に対する単純な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)を使用できます。

12
Victor Klos

薬物動態(PK)の世界では、さまざまなタイプのAUCを計算することが一般的で基本的なタスクです。以下のような薬物動態のためのさまざまなAUC計算があります。

  • AUC0-t =ゼロから時間tまでのAUC
  • AUC0-last =ゼロから最後の時点までのAUC(上記と同じ場合があります)
  • AUC0-inf =ゼロから時間無限までのAUC
  • AUCint =時間間隔にわたるAUC
  • AUCall =データが存在する全期間にわたるAUC

これらの計算を行う最適なパッケージの1つは、ファイザーの人々からの比較的新しいパッケージPKNCAです。見てみな。

3
hackR

Joris Meysの答え は素晴らしかったが、サンプルからNAを取り除くのに苦労した。以下は、それらを処理するために作成した小さな関数です。

_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))

それが私のような初心者に役立つことを願っています:-)

編集:境界を追加

0
Dan Chaltiel