No.11581 非線形回帰後の線形回帰  【atoh】 2009/12/24(Thu) 21:19

統計解析もRも始めて間もない者です。

ある実験結果に対する回帰式を得ようとしています。
モデル式がy=A*(1-A)e^(-B*x)であることから,Rのnls()関数による非線形回帰を行おうと思っています。
しかしnls()はlm()と異なりpredict()を用いた切片の信頼区間の計算やplot()による多彩な残差分析のやクックの距離などのプロットができないようです。
本来ならば非線形回帰により得られた回帰式に対して適切な信頼区間の算出や外れ値の検定を行うべきだとは思うのですが,どのように計算して良いか分からないでいます。
そこで,nls()で得られた非線形回帰式の係数を使ってlm()で再度線形回帰式を求め直すことでpredict()やplot()を利用できないかと思っています。
実際に計算してみたところ,lm()で得られた係数はnls()ので得られたものとほとんど違いはありませんでしたが,全く同じというわけでもありませんでした。

そこで質問なのですが,上記のような非線形回帰分析で得られた回帰式について更に線形回帰分析をしなおすようなやり方は,間違った結果を得てしまうものでしょうか?

具体的には以下のように計算しようとしています。
a<-nls(y~a1*exp(a2*x)+a3,Dataset,start=list(a1=xx,a2=xx,a3=xx))
a22<-coef(a)[2]
Dataset<-transform(Dataset,a=exp(x*a22))
b<-lm(y~a,data=Dataset)
predict(b,newdata=data.frame(a=exp(0*a22)),interval="confidence",level=0.95)
plot(b)

よろしくお願い申し上げます。

No.11582 Re: 非線形回帰後の線形回帰  【atoh】 2009/12/24(Thu) 23:59

>モデル式がy=A*(1-A)e^(-B*x)であることから,Rのnls()関数による非線形回帰を行おうと思っています。
申し訳ございません。モデルを書き間違えました。
正しいモデルはy=C*(A-(A-1)*e^(-B*x))でした。

よろしくお願い申し上げます。

No.11592 Re: 非線形回帰後の線形回帰  【青木繁伸】 2009/12/25(Fri) 19:47

非線形回帰においては,線形回帰と同じ統計量を求められるとは思わない方がよろしいでしょう。
提示された 非線形関数の場合であっても,独立変数の変域によっては殆ど直線近時が成り立つのかも知れず(「lm()で得られた係数はnls()ので得られたものとほ とんど違いはありませんでしたが」といっておられるので),そのようならば,lm でよいのではないですか(若干の言い訳をして)。

No.11594 Re: 非線形回帰後の線形回帰  【知ったかぶり】 2009/12/25(Fri) 23:45

>上記のような非線形回帰分析で得られた回帰式について更に線形回帰分析をしなおすようなやり方は,間違った結果を得てしまうものでしょうか?

本来は推定値であるものを定数として扱っているわけですから,得られる結果はもともとの非線形回帰の信頼区間とは別ものでしょう.

非線形最小二乗法における信頼区間については,以下が参考にならないでしょうか?
http://tolstoy.newcastle.edu.au/R/help/04/10/5039.html

No.11596 Re: 非線形回帰後の線形回帰  【atoh】 2009/12/26(Sat) 15:35

青木先生,知ったかぶりさん,お忙しい中ご回答ありがとうございます。

>提示された非線形関数の 場合であっても,独立変数の変域によっては殆ど直線近時が成り立つのかも知れず(「lm()で得られた係数はnls()ので得られたものとほとんど違いは ありませんでしたが」といっておられるので),そのようならば,lm でよいのではないですか(若干の言い訳をして)。

実は実際求めたいのは外挿によって得られる回帰式のy切片(モデル式のC)とその点における傾きを使って更に計算する数値でして,直線近似では傾きがだいぶ変わってしまうので,好ましくないかと考えています。
計算すると直線近似で求められる値の方が結果のばらつきが小さくなるため都合が良いといえば良いのですが,それではいけないと思ってモデル式にこだわろうとしています。

>本来は推定値であるものを定数として扱っているわけですから,得られる結果はもともとの非線形回帰の信頼区間とは別ものでしょう.

そうなんですね。そこさえ良く理解できていませんでした。
ご紹介いただいたURLを見たのですが,こちらもちょっと・・・
質問者さん違ってexampleを試してもエラーがでてしまってうまく動きませんでした。切片の信頼区間を根拠に棄却すべきデータの判別をしたかったのですが,諦めた方が良さそうです。

No.11598 Re: 非線形回帰後の線形回帰  【青木繁伸】 2009/12/26(Sat) 19:45

後半を読んでも何をやろうとしているのかよくわからなかったのですが,かなりへんなことをやろうとしていたのですね。lmの代わりにnlsをやろうとしているだけだと思っていました。

No.11599 Re: 非線形回帰後の線形回帰  【横やり】 2009/12/27(Sun) 01:26

内容を読んでいまして上記のy=C*(A-(A-1)*e^(-B*x))の線形回帰式を計算したところ-C*((-B*exp^(-B*x)*(A-1)))・・・(1)となりました。
atohさんの言う
>具体的には以下のように計算しようとしています。
a<-nls(y~a1*exp(a2*x)+a3
と述べられている上記式には当てはまりません。したがって青木先生のおっしゃる
>後半を読んでも何をやろうとしているのかよくわからなかったのですが
ということに関して僕も良く解りませんでした。
当 方の見解としておそらく非線形回帰式のある点における切片を信頼区間(正規分布?)による推定を行うことで検定を行いたかったのかと思われますので,上記 非線形回帰式の接線の傾きと切片からある点における線形回帰式の母分散と切片の検定を行うことは可能だと思います。上記(1)の線形回帰式の数式で再一度検定 を行ってみてはどうでしょうか?

No.11600 Re: 非線形回帰後の線形回帰  【atoh】 2009/12/27(Sun) 12:48

青木先生,横やりさん,ご回答ありがとうございます。

モデル式は線形回帰できる形に変換できないと思い,非線形回帰に手を染めました。横やりさんの(1)はどのように計算されたのか,もしよろしければお教えください。

私としては,以下のような考えでいました。
モデルとなる式y=C*(A-(A-1)*e^(-B*x))を展開するとC*A-C*(A-1)*e^(-B*x)となり,C*A=a3, C*(A-1)=a1, -B=a2, として非線形回帰式をnls()を用いて得ます。
その後a2の推定値を定数として,e^(a2*x)の値をxと同じデータセットに入力してから,lm()でa1, a3にあたる係数を求めなおして,x=0の時のyの値とその信頼区間やplot()による残差分析用の図を求めます。

横やりさんの(1)について一度検討してみたいと思います。後ほど結果をご報告させていただきます。

No.11604 Re: 非線形回帰後の線形回帰  【atoh】 2009/12/27(Sun) 19:45

度々失礼いたします。

横やりさんの式を検討してみました。
式が指数関数なので,対数変換し,lm(log(y)=x)で得られたlog(y)=b1*x+b2について指数に戻し,y=e^(b1*x+b2)によりx=0のときのyと傾きを求めました。
その結果,普通にlm(y~x)で求めたときと近く,非線形回帰で得られたものとは異なりました。グラフにしてみたところ,もとのデータはやや曲線を描くのに対してy=e^(b1*x+b2)はほぼ直線となっていました。

(1)の使い方を間違えているのでしょうか?

No.11606 Re: 非線形回帰後の線形回帰  【青木繁伸】 2009/12/27(Sun) 21:11

No. 11596
> 紹介いただいたURLを見たのですが,こちらもちょっと・・・
> 質問者さん違ってexampleを試してもエラーがでてしまってうまく動きませんでした。

こ れはね,回答者もちょっと配慮不足(というか,R のバージョンによってはこれでちゃんと再現できていたのでしょう)。ちゃんと動かすためには,example 関数の次の行にダミー入力行を入れておく必要があります(逆に,この動作特性があるために,本来実行して欲しい R の文(行)が読み捨てられてうまく動かないということもあります)。
example(predict.nls) 
junk # 何でも良いです(par(ask=TRUE) に対するダミーの入力です)
se.fit <- sqrt(apply(attr(predict(fm,list(Time = tt)),"gradient"),1,
function(x) sum(vcov(fm)*outer(x,x))))
matplot(tt, predict(fm,list(Time = tt))+
outer(se.fit,qnorm(c(.5, .025,.975))),type="l")

points(demand ~ Time, data = BOD)
ただ,実行して見ればわかるけど,これは,予測値の信頼区間の推定についてであって,これが,あなたの望むもの「切片の信頼区間を根拠に棄却すべきデータの判別をしたかった」かどうかわかりませんね。

でもまあ,これが問題解決の一つのヒントになればよいのですけど。

No.11607 Re: 非線形回帰後の線形回帰  【青木繁伸】 2009/12/27(Sun) 21:29

あるパラメータ一の信頼区間を求めるには,ひとつの考え方としては,ブートストラップ法を使うというのもあるかとは思います(まあ,データ組数がある程度ないとダメでしょうけど)。ちょっと,このあと,テストデータを作って実行例を付けてみます。
何時間かかるかわからないけど(^_^;)

No.11608 Re: 非線形回帰後の線形回帰  【青木繁伸】 2009/12/27(Sun) 22:40

まずは,プログラム
実際にやるときには,1行目(乱数の初期値設定)は削除すること。ただし,いくつかウォーニングは出るでしょう(対処はしているつもりですけど)。
set.seed(11111) # 乱数の初期値
data <- data.frame( # テストデータ(あなたの手元にあるデータと様相はちがうかもしれないけど,こんな風かな?)
x = c(0.09, 0.09, 0.31, 0.64, 0.93, 1.25, 2.74, 1.51, 1.27, 1.64, 1.95, 2.31, 2.33, 2.56, 2.59),
y = c(0.81, 0.81, 0.43, 1.04, 0.81, 1.66, 4.68, 1.46, 1.09, 2.19, 2.77, 2.47, 3.8, 3.63, 4.24))
pdf("graph%i.pdf", onefile=FALSE, width=500/72, height=400/72) # 2 枚のグラフを描くので,ファイルへ出力
plot(data, pch=19) # データ点のプロット
ans <- nls(y~a1*exp(a2*x)+a3, data, start=list(a1=0.5, a2=0.8, a3=0.1)) # 非線形回帰
summary(ans) # その結果
x2 <- seq(0, 3, length=2000)
lines(x2, predict(ans, newdata=data.frame(x=x2))) # 当てはめ結果の図
n <- nrow(data) # これ以降,ブートストラップ
trial <- 1000 # 繰り替えし数(なるべく多く)
ans <- replicate(trial, # 以下を実行
{
data2 <- data[sample(n, replace=TRUE), ]
try(nls(y~a1*exp(a2*x)+a3, data2, start=list(a1=0.5, a2=0.8, a3=0.1))$m$getPars()[3]) # 任意のパラメータベクトルを抽出(切片といているのはこれ?
})
const <- as.numeric(ans)
const <- const[!is.na(const)] # 推定が成功した場合の結果のみを抽出
hist(const, main="constant") # ヒストグラムを描いてみる
quantile(const, c(0.025, 0.975)) # 2.5%, 97.5% 点の数値
dev.off()
実行結果
> set.seed(11111) # 乱数の初期値
> data <- data.frame( # テストデータ(あなたの手元にあるデータと様相はちがうかもしれないけど,こんな風かな?)
+ x = c(0.09, 0.09, 0.31, 0.64, 0.93, 1.25, 2.74, 1.51, 1.27, 1.64, 1.95, 2.31, 2.33, 2.56, 2.59),
+ y = c(0.81, 0.81, 0.43, 1.04, 0.81, 1.66, 4.68, 1.46, 1.09, 2.19, 2.77, 2.47,
+ 3.8, 3.63, 4.24))
> pdf("graph%i.pdf", onefile=FALSE, width=500/72, height=400/72) # 2 枚のグラフを描くので,ファイルへ出力
> plot(data, pch=19) # データ点のプロット
> ans <- nls(y~a1*exp(a2*x)+a3, data, start=list(a1=0.5, a2=0.8, a3=0.1)) # 非線形回帰
> summary(ans) # その結果

Formula: y ~ a1 * exp(a2 * x) + a3

Parameters:
Estimate Std. Error t value Pr(>|t|)
a1 0.3859 0.2923 1.320 0.21148
a2 0.8860 0.2520 3.515 0.00426 **
a3 0.2256 0.4730 0.477 0.64199
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.377 on 12 degrees of freedom

Number of iterations to convergence: 4
Achieved convergence tolerance: 2.583e-06

> x2 <- seq(0, 3, length=2000)
> lines(x2, predict(ans, newdata=data.frame(x=x2))) # 当てはめ結果の図
> n <- nrow(data) # これ以降,ブートストラップ
> trial <- 1000 # 繰り替えし数(なるべく多く)
> ans <- replicate(trial, # 以下を実行
+ {
+ data2 <- data[sample(n, replace=TRUE), ]
+ try(nls(y~a1*exp(a2*x)+a3, data2, start=list(a1=0.5, a2=0.8, a3=0.1))$m$getPars()[3]) # 任意のパラメータベクトルを抽出(切片といているのはこれ?)
+ })
Error in nls(y ~ a1 * exp(a2 * x) + a3, data2, start = list(a1 = 0.5, :
step 因子 0.000488281 は 0.000976562 の 'minFactor' 以下に縮小しました
Error in nls(y ~ a1 * exp(a2 * x) + a3, data2, start = list(a1 = 0.5, :
step 因子 0.000488281 は 0.000976562 の 'minFactor' 以下に縮小しました
Error in nls(y ~ a1 * exp(a2 * x) + a3, data2, start = list(a1 = 0.5, :
step 因子 0.000488281 は 0.000976562 の 'minFactor' 以下に縮小しました
Error in nls(y ~ a1 * exp(a2 * x) + a3, data2, start = list(a1 = 0.5, :
繰り返し数が最大値 50 を超えました
> const <- as.numeric(ans)
警告メッセージ:
強制変換により NA が生成されました
> const <- const[!is.na(const)] # 推定が成功した場合の結果のみを抽出
> hist(const, main="constant") # ヒストグラムを描いてみる
> quantile(const, c(0.025, 0.975)) # 2.5%, 97.5% 点の数値
2.5% 97.5%
-1.1173381 0.7600651
> dev.off()
quartz
2




No.11609 Re: 非線形回帰後の線形回帰  【横やり】 2009/12/28(Mon) 02:04

atohさんの質問で
(1)の使い方を間違えているのでしょうか?に関しまして
私が計算したのはモデ ル式のxに関する偏微分を求めたので,各パラメーターごとの微分はそれぞれ別個に求める必要があります。線形にモデルを変換して推定するという本来の趣旨 と少しかけ離れてしまい回答がいまいち要点を得ないと思いますが,当方が考えたていたのは非線形回帰式を線形変換せずオーソドックスに偏微分係数から各パ ラメーターごとに係数を求める為の手順で考えていましたので申し訳ありませんが本件での回答としてはあまり要領をえていないと思います。上記青木先生の おっしゃる手法を試すのが最も良いと思われます。

No.11612 Re: 非線形回帰後の線形回帰  【atoh】 2009/12/28(Mon) 16:59

青木先生,横やりさん,ご回答ありがとうございました。

ブートストラップ法という方法があるのですね。どこかで聞いたことはありましたが,実際の使用方法は存じませんでした。
青 木先生のスクリプトを参考に私のデータを一部計算してみたところ,lm()で無理矢理計算させたときより少し広めの区間になりました。多分この区間の方が 正解に近いように思えます。10000回くらいの計算を繰り返させてみましたが,区間にいくらか変動があるようでした。信頼区間の変動は計算回数を増やせ ば増やす程一定の値に落ち着くと考えてよいのでしょうか?

ところで,
>非線形回帰においては,線形回帰と同じ統計量を求められるとは思わない方がよろしいでしょう。
とのことでしたが,これはクックの距離についてもそうなのでしょうか?
またその場合,非線形回帰でクックの距離に相当するような回帰線に強く影響する点を評価する方法はあるのでしょうか?

頻繁に質問ばかりして申し訳ございませんが,ご回答いただければ幸いです。
よろしくお願い申し上げます。

No.11613 Re: 非線形回帰後の線形回帰  【のね】 2009/12/29(Tue) 00:04

モデル式を書き換えても良いのであれば,
y = a1*exp(a2*x)+a3
において,y0 を x=0 の時の y の値(=切片)として,
y = y0 + a1*(exp(a2*x)-1)
とおき,nls を行った方が簡単では?

No.11615 Re: 非線形回帰後の線形回帰  【atoh】 2009/12/29(Tue) 18:29

のねさん,ご提案ありがとうございます。

>y = y0 + a1*(exp(a2*x)-1)
この式は,展開するとa1*exp(a2*x)-a1+y0となり,定数項をa3とみなすのと同じように思うのですが,違うのでしょうか?

No.11616 Re: 非線形回帰後の線形回帰  【のね】 2009/12/29(Tue) 21:25


  y = a1*exp(a2*x)+a3

の a3 は「定数項」ではあっても「切片」ではありません。
 最初の方に「切片の信頼区間を根拠に棄却すべきデータの判別」という話があったので,切片とその信頼区間の簡単な求め方を示したものです。
 もし,あなたの求めたかった物が「定数項」であれば,私の投稿は無視してください

No.11618 Re: 非線形回帰後の線形回帰  【atoh】 2009/12/29(Tue) 22:58

のねさん,ご回答ありがとうございました。

>y = y0 + a1*(exp(a2*x)-1)
を用いると,例えば青木先生が示したブートストラップ法を計算するときにa3-a1の計算にしなくてもよくなるということですね。全然気づきませんでした。
確かにご提案いただいた式で計算させてみると,y = a1*exp(a2*x)+a3で求めた回帰係数と近い値が計算されました。この方法は処理が良さそうなので,使ってみようと思います。ありがとうございました。

No.11624 Re: 非線形回帰後の線形回帰  【のね】 2009/12/30(Wed) 09:13

> y = a1*exp(a2*x)+a3
において,切片を y0 = a1+a3 で計算することは妥当だとおもいますが,y0の信頼区間を a1の信頼区間+a3の信頼区間 として求めることはできません。(相関がある可能性があるので)
> y = y0 + a1*(exp(a2*x)-1)
を用いると, [nls が切片の信頼区間を計算してくれる]というのが有利な点です。

なお,外れ値(測定点)を求める場合は,nlsの計算結果から残渣を求め,平均値(=0となってるはず)から大きくずれた点を考察するのが普通ではないでしょうか。もちろん,青木先生が日頃おっしゃっているように,ずれの原因を考察することが必要です。

● 「統計学関連なんでもあり」の過去ログ--- 043 の目次へジャンプ
● 「統計学関連なんでもあり」の目次へジャンプ
● 直前のページへ戻る