7

2 つの部分からなる線をデータに当てはめようとしています。

サンプルデータは次のとおりです。

x<-c(0.00101959664756622, 0.001929220749155, 0.00165657261751726, 
0.00182514724375389, 0.00161532360585458, 0.00126991061099209, 
0.00149545009309177, 0.000816386510029308, 0.00164402569283353, 
0.00128029006251656, 0.00206892841921455, 0.00132378793976235, 
0.000953143467154676, 0.00272964503695939, 0.00169743839571702, 
0.00286411493120396, 0.0016464862337286, 0.00155672067449593, 
0.000878271561566836, 0.00195872573138819, 0.00255412836538339, 
0.00126212428137799, 0.00106206607962734, 0.00169140916371657, 
0.000858015581562961, 0.00191955159274793, 0.00243104345247067, 
0.000871042201994687, 0.00229814264111745, 0.00226756341241083)

y<-c(1.31893118849162, 0.105150790530179, 0.412732029152914, 0.25589805483046, 
0.467147868109498, 0.983984462069833, 0.640007862668818, 1.51429617241365, 
0.439777145282391, 0.925550163462951, -0.0555942758921906, 0.870117027565708, 
1.38032147826294, -0.96757052387814, 0.346370836378525, -1.08032147826294, 
0.426215616848312, 0.55151485221263, 1.41306889485598, 0.0803478641720901, 
-0.86654892295057, 1.00422341998656, 1.26214517662281, 0.359512373951839, 
1.4835398594013, 0.154967053938309, -0.680501679226447, 1.44740598234453, 
-0.512732029152914, -0.359512373951839)

最適な 2 つの部分の線を定義できることを望んでいます (手描きの例を示しています)。

プロット

次に、2 部構成の線形関数を見つける区分関数を定義します。定義は、2 つの線の勾配と互いの切片に基づいており、線を完全に定義する必要があります。

# A=gradient of first line segment
# B=gradient of second line segment
# Cx=inflection point x coord
# Cy=inflexion point y coord 

out_model <- nls(y ~ I(x <= Cx)*Cy-A*(Cx-x)+I(x > Cx)*Cy+B*(x), 
                  data = data.frame(x,y), 
                  start = c(A=-500,B=-500,Cx=0.0001,Cy=-1.5) )

ただし、次のエラーが表示されます。

エラー nls(y ~ I(x <= Cx) * Cy - A * (Cx - x) + I(x > Cx) * Cy + B * : 特異勾配

Finding a curve to match dataから基本的な方法を得ました

私が間違っているアイデアはありますか?

4

4 に答える 4

4

エレガントな答えはありませんが答えはあります。

(よりエレガントな回答については、以下の編集を参照してください)

Cxが小さすぎて適合するデータ ポイントが存在しない場合、またはが十分Aに大きいため適合するデータ ポイントが存在しない場合、QR 分解行列は特異になります。そして、それぞれがデータに等しくよく適合します。CyCxBCyCxACyCxBCy

私はこれをテストしCxて、取り付けられないようにしました。Cx(say)Cx = mean(x)で修正するとnls()、問題は問題なく解決します。

nls(y ~ ifelse(x < mean(x),ya+A*x,yb+B*x), 
               data = data.frame(x,y), 
               start = c(A=-1000,B=-1000,ya=3,yb=0))

...与えます:

Nonlinear regression model
  model:  y ~ ifelse(x < mean(x), ya + A * x, yb + B * x) 
   data:  data.frame(x, y) 
        A         B        ya        yb 
-1325.537 -1335.918     2.628     2.652 
 residual sum-of-squares: 0.06614

Number of iterations to convergence: 1 
Achieved convergence tolerance: 2.294e-08 

Cxそこで、絶対に範囲外に出ないように変形すれば[min(x),max(x)]解決するのではないかと思いました。実際、「A」の線と「B」の線のそれぞれに適合するために、少なくとも 3 つのデータ ポイントが利用できるようにしたいので、Cx は の 3 番目に低い値と 3 番目に高い値の間にある必要がありますx。適切な算術演算で関数を使用すると、範囲を にatan()マップできるので、次のコードを取得しました。[-inf,+inf][0,1]

trans <- function(x) 0.5+atan(x)/pi
xs <- sort(x)
xlo <- xs[3]
xhi <- xs[length(xs)-2]
nls(y ~ ifelse(x < xlo+(xhi-xlo)*trans(f),ya+A*x,yb+B*x), 
               data = data.frame(x,y), 
               start = c(A=-1000,B=-1000,ya=3,yb=0,f=0))

ただし、残念ながら、singular gradient matrix at initial parametersこのコードからまだエラーが発生するため、問題は依然として過剰にパラメータ化されています。@Henrik が示唆しているように、これらのデータでは、双線形近似と単一線形近似の違いはあまり大きくありません。

それでも、双一次近似の答えを得ることができます。nls()を修正すると問題が解決するので、を使用して 1 次元最小化を行うだけで、残差標準誤差を最小化するCxの値を見つけることができます。特にエレガントなソリューションではありませんが、何もないよりはましです。Cxoptimize()

xs <- sort(x)
xlo <- xs[3]
xhi <- xs[length(xs)-2]
nn <- function(f) nls(y ~ ifelse(x < xlo+(xhi-xlo)*f,ya+A*x,yb+B*x), 
               data = data.frame(x,y), 
               start = c(A=-1000,B=-1000,ya=3,yb=0))
ssr <- function(f) sum(residuals(nn(f))^2)
f = optimize(ssr,interval=c(0,1))
print (f$minimum)
print (nn(f$minimum))
summary(nn(f$minimum))

...の出力が得られます:

[1] 0.8541683
Nonlinear regression model
  model:  y ~ ifelse(x < xlo + (xhi - xlo) * f, ya + A * x, yb + B * x) 
   data:  data.frame(x, y) 
        A         B        ya        yb 
-1317.215  -872.002     2.620     1.407 
 residual sum-of-squares: 0.0414

Number of iterations to convergence: 1 
Achieved convergence tolerance: 2.913e-08 

Formula: y ~ ifelse(x < xlo + (xhi - xlo) * f, ya + A * x, yb + B * x)

Parameters:
     Estimate Std. Error t value Pr(>|t|)    
A  -1.317e+03  1.792e+01 -73.493  < 2e-16 ***
B  -8.720e+02  1.207e+02  -7.222 1.14e-07 ***
ya  2.620e+00  2.791e-02  93.854  < 2e-16 ***
yb  1.407e+00  3.200e-01   4.399 0.000164 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 

Residual standard error: 0.0399 on 26 degrees of freedom

Number of iterations to convergence: 1 

の値との値との値Aとの値の間に大きな違いはありませんが、 の最適値には多少の違いがあります。Byaybf

(編集 - エレガントな答え)

問題を 2 つのステップに分けたので、もう使用する必要はありませんnls()lm()次のように、正常に動作します。

function (x,y) 
{
    f <- function (Cx) 
        {
        lhs <- function(x) ifelse(x < Cx,Cx-x,0)
        rhs <- function(x) ifelse(x < Cx,0,x-Cx)
        fit <- lm(y ~ lhs(x) + rhs(x))
        c(summary(fit)$r.squared, 
            summary(fit)$coef[1], summary(fit)$coef[2],
            summary(fit)$coef[3])
        }

    r2 <- function(x) -(f(x)[1])

    res <- optimize(r2,interval=c(min(x),max(x)))
    res <- c(res$minimum,f(res$minimum))

    best_Cx <- res[1]
    coef1 <- res[3]
    coef2 <- res[4]
    coef3 <- res[5]
    plot(x,y)
    abline(coef1+best_Cx*coef2,-coef2) #lhs  
    abline(coef1-best_Cx*coef3,coef3)  #rs
}

...これは次を与えます:

ここに画像の説明を入力

于 2013-04-08T11:12:08.117 に答える
3

ブレークポイントがわかっている場合は、線形回帰を使用できます

「Rを使用した実用的な回帰とAnova」からの壊れたスティック回帰

ジュリアン・J・ファラウェイ

2000 年 12 月

k <- 0.0025

lhs <- function(x) ifelse(x < k,k-x,0)
rhs <- function(x) ifelse(x < k,0,x-k)
fit <- lm(y ~ lhs(x) + rhs(x))
于 2013-04-08T11:32:39.093 に答える
1

私を正しい道に導いてくれた Henrik に感謝します! これは、単純なプロットを使用した、より完全で比較的エレガントなソリューションです。

range_x<-max(x)-min(x)
intervals=1000
coef1=c()
coef2=c()
coef3=c()
r2=c()

for (i in 1:intervals)  
{
Cx<-min(x)+(i-1)*(range_x/intervals)
lhs <- function(x) ifelse(x < Cx,Cx-x,0)
rhs <- function(x) ifelse(x < Cx,0,x-Cx)
fit <- lm(y ~ lhs(x) + rhs(x))
coef1[i]<-summary(fit)$coef[1]
coef2[i]<-summary(fit)$coef[2]
coef3[i]<-summary(fit)$coef[3]
r2[i]<-summary(fit)$r.squared
}
best_r2<-max(r2)                             # get best r squared
pos<-which.max(r2)                                          
best_Cx<-min(x)+(pos-1)*(range_x/intervals)  # get Cx for best r2

plot(x,y)
abline(coef1[pos]+best_Cx*coef2[pos],-coef2[pos]) #lhs  
abline(coef1[pos]-best_Cx*coef3[pos],coef3[pos])  #rs

ここに画像の説明を入力

于 2013-04-09T02:48:32.623 に答える