非負のリッジ回帰を実行するにはどうすればよいですか?


10

非負のリッジ回帰を実行するにはどうすればよいですか?非負の投げ縄はで利用できますscikit-learnが、リッジの場合、ベータの非負を強制できません。実際、負の係数を取得しています。これがなぜか誰か知っていますか?

また、通常の最小二乗法でリッジを実装できますか?これを別の質問に移動しました:OLS回帰の観点からリッジ回帰を実装できますか?


1
ここでは2つの完全に直交する質問があります。「最小二乗でリッジを実装できますか」を別の質問として分類することを検討します。
Matthew Drury 2016年

回答:


8

これがなぜなのか知っている人はいますか?」に対するかなりの気候への答えは、単に負でないリッジ回帰ルーチンを実装するのに十分なほど気にしていないということです。主な理由の1つは、人々がすでに負でないエラスティックネットルーチン(たとえば、ここここ)の実装を開始していること です。エラスティックネットには、特殊なケースとしてリッジ回帰が含まれています(本質的にLASSO部分にゼロの重みを設定しています)。これらの作品は比較的新しいため、scikit-learnまたは同様の汎用パッケージにまだ組み込まれていません。コードについては、これらの論文の著者に問い合わせることをお勧めします。

編集:

@amoebaと私がコメントで議論したように、これの実際の実装は比較的単純です。たとえば、次のような回帰問題があるとします。

y=2x1x2+ϵ,ϵN(0,0.22)

ここで、とはどちらも次のような標準法線です:。標準化された予測変数を使用しているため、後で正規化する必要がないことに注意してください。簡単にするため、切片も含めません。標準の線形回帰を使用して、この回帰問題をすぐに解決できます。したがって、Rでは次のようになります。x1x2xpN(0,1)

rm(list = ls()); 
library(MASS); 
set.seed(123);
N = 1e6;
x1 = rnorm(N)
x2 = rnorm(N)
y = 2 * x1 - 1 * x2 + rnorm(N,sd = 0.2)

simpleLR = lm(y ~ -1 + x1 + x2 )
matrixX = model.matrix(simpleLR); # This is close to standardised
vectorY = y
all.equal(coef(simpleLR), qr.solve(matrixX, vectorY), tolerance = 1e-7)  # TRUE

最後の行に注目してください。ほとんどすべての線形回帰ルーチンは、QR分解を使用してを推定します。同じことをリッジ回帰問題にも使用したいと思います。この時点で、@ whuberによるこの投稿を読んでください。この手順を正確に実装します。つまり、元の設計行列に対角行列と応答ベクトルにゼロをます。このようにして、元のリッジ回帰問題をとして 再表現できここで、βXλIpyp(XTX+λI)1XTy(X¯TX¯)1X¯Ty¯¯拡張バージョンを象徴します。これらのノートのスライド18から19もチェックして、完全であることを確認してください。したがって、Rでは次のようになります。

myLambda = 100;  
simpleRR = lm.ridge(y ~ -1 + x1 + x2, lambda = myLambda)
newVecY = c(vectorY, rep(0, 2))
newMatX = rbind(matrixX, sqrt(myLambda) * diag(2))
all.equal(coef(simpleRR), qr.solve(newMatX, newVecY), tolerance = 1e-7)  # TRUE

そしてそれは動作します。さて、リッジ回帰の部分を得ました。ただし、別の方法で解決することもできます。これは、残差二乗和がコスト関数である最適化問題として定式化し、それに対して最適化することもできます。。案の定、それを行うことができます。minβ||y¯X¯β||22

myRSS <- function(X,y,b){ return( sum( (y - X%*%b)^2 ) ) }
bfgsOptim = optim(myRSS, par = c(1,1), X = newMatX, y= newVecY, 
                  method = 'L-BFGS-B')
all.equal(coef(simpleRR), bfgsOptim$par, check.attributes = FALSE, 
          tolerance = 1e-7) # TRUE

予想通り再び機能します。だから今私たちはただ欲しい:ここで。これは単に同じ最適化問題ですが、解が負にならないように制約されています。minβ||y¯X¯β||22β0

bfgsOptimConst = optim(myRSS, par = c(1,1), X=newMatX, y= newVecY, 
                       method = 'L-BFGS-B', lower = c(0,0))
all(bfgsOptimConst$par >=0)  # TRUE
(bfgsOptimConst$par) # 2.000504 0.000000

これは、元の非負のリッジ回帰タスクが、単純な制約付き最適化問題として再公式化することで解決できることを示しています。いくつかの警告:

  1. (実際には)正規化された予測変数を使用しました。自分で正規化を説明する必要があります。
  2. 同じことが切片の正規化にも当てはまります。
  3. 私は使用optimL-BFGS-Bの引数を。範囲を受け入れるのは、最も一般的なRソルバーです。きっと数十の優れたソルバーが見つかるはずです。
  4. 一般的な制約では、線形最小二乗問題は二次最適化タスクとして提起されます。これはこの投稿ではやり過ぎですが、必要に応じて速度を上げることができることを覚えておいてください。
  5. コメントで述べたように、リッジ回帰をaugmented-linear-regression部分としてスキップし、リッジコスト関数を最適化問題として直接エンコードできます。これははるかに単純で、この投稿は大幅に小さくなります。議論のために、この2番目のソリューションも追加します。
  6. 私はPythonで完全に会話しているわけではありませんが、基本的にはNumPyのlinalg.solveとSciPyの最適化関数を使用してこの作業を複製できます。
  7. ハイパーパラメータなどを選択するには、通常のCVステップを実行するだけです。何も変わりません。λ

ポイント5のコード:

myRidgeRSS <- function(X,y,b, lambda){ 
                return( sum( (y - X%*%b)^2 ) + lambda * sum(b^2) ) 
              }
bfgsOptimConst2 = optim(myRidgeRSS, par = c(1,1), X = matrixX, y = vectorY,
                        method = 'L-BFGS-B', lower = c(0,0), lambda = myLambda)
all(bfgsOptimConst2$par >0) # TRUE
(bfgsOptimConst2$par) # 2.000504 0.000000

1
これはやや誤解を招くものです。非負のリッジ回帰を実装するのは簡単です。リッジ回帰を拡張データの通常の回帰として書き直し(stats.stackexchange.com/questions/203687へのコメントを参照)、非負の回帰ルーチンを使用できます。
amoeba 2016年

実装が簡単であることには同意します(+1する)。(私は以前のあなたとグレンのコメントも他のスレッドで賛成した)。問題は、なぜ実装されていないのか、難しい場合ではないのです。この問題について、最適化問題としてこのNNRRタスクを直接定式化することは、最初にそれを拡張データ回帰として定式化してからQuadを使用するよりもさらに単純であると強く思います。プログラム この回帰を解決するための最適化。それは実装部分に挑戦するので、私は私の答えでこれを述べませんでした。
usεr11852

または単にスタンでそれを書いてください。
Sycoraxによると、モニカは2016

あ、そう; 私はQを主に非負の隆起を行う方法を尋ねるように(そして、なぜそれが通過で実装されないのかについてのみ尋ねるように)理解しました。これをタイトルに入れるために編集さえしました。いずれにせよ、それをどうやってやるかは、もっと興味深い質問のように思えます。非負のリッジを実装する方法の説明で回答を更新できれば、それは将来の読者にとって非常に役立つと思います(そして私は喜んで賛成します:)。
amoeba 2016年

1
クールです。後で行います(新しいタイトルに気づかなかったので、申し訳ありません)。おそらく、OLS /疑似観測の観点から実装を説明するので、他の質問にも答えます。
usεr11852

4

エラスティックネットを実装するRパッケージのglmnet、つまりlassoとridgeはこれを可能にします。パラメータlower.limitsとを使用するとupper.limits、各ウェイトの最小値または最大値を個別に設定できるため、下限を0に設定すると、非負の弾性ネット(投げ縄/尾根)が実行されます。

pythonラッパーhttps://pypi.python.org/pypi/glmnet/2.0.0もあります


2

解決しようとしていることを思い出してください:

minimizexAxy22+λx22s.t. x>0

以下と同等です。

minimizexAxy22+λxIxs.t. x>0

さらに代数を使って:

minimizexxT(ATA+λI)x+(2ATy)Txs.t. x>0

疑似Pythonでの解決策は、単に次のようにすることです。

Q = A'A + lambda*I
c = - A'y
x,_ = scipy.optimize.nnls(Q,c)

参照:形式の正則化器を使用して、非負の最小二乗をスパースする方法は?KxRkx

もう少し一般的な答えについては。


行c =-A'yはc = A'yを読み取らないのですか?これは正しいと思いますが、解決策はscipy.optimize.nnls(newMatX、newVecY)とは少し異なることに注意してください。ここで、newMatXはX行で、対角線に沿ってsqrt(lambda)の対角行列で拡張され、NewVecYはYです。 nvarゼロで補強されています。私はあなたが言及した解決策は正しいものだと思います...
トムウェンセリアーズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.