最小二乗法のような複数の座標から二次関数を求める方法はありますか?
積分は得意なんですが、微分はイマイチでして、微分などを使わないで複数の座標から二次関数y=ax^2+bx+cを求める方法があれば教えてください!
今更で申し訳ないのですが、最小二乗法はどんな原理で近似式を求めているのですか?
例えば、すべての座標を足して、座標の数で割ると言った平均を求める方法で求めるとかでしょうか?
うまく伝わっていないかもしれませんが原理的なものが知りたいですね。
調べるとwikiは出てくるんですが、説明が難しくって私の頭では追いつきませんでした。
編集8/28
私自身でも今現在進行形で方法を考えて三角関数とかでなんとかなるんじゃないかと考えているんですが、もしよろしければ付き合っていただけないでしょうか?
ほんの気になったことなのですが、y=(X^2+3X+1)^4を微分の定義とかを使わないで傾きを求められないかと考えています。もちろん、微分って傾き求めるもんなんだから定義を使わないなら求まるわけねーじゃんって思う方もいると思いますが、自分なりに探求しています。
もし、こんな方法もあるよって方がいらっしゃいましたら教えていただけると嬉しいです。
同時進行ではありますが、y=(X^2+3X+1)^4の傾きを微分の定義を使わないで解くアルゴリズムをプログラムにできないかとも考えています。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/08/23 09:14
2018/08/23 12:19
2018/08/23 13:20
2018/08/28 00:55
2018/08/28 07:48
回答5件
0
こんにちは。
最小二乗法はn次多項式でも使えますよ。
投稿2018/08/23 08:25
総合スコア23272
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/08/23 09:06
2018/08/23 11:47 編集
2018/08/23 12:21
2018/08/23 12:39
2018/08/24 00:45 編集
2018/08/24 00:48
2018/08/24 02:54
2018/08/24 03:20
2018/08/24 03:36
2018/08/24 03:56
2018/08/27 08:58
0
ベストアンサー
別回答のコメントで書いたやつ:
すぐ思いつく「最小二乗じゃない簡単な手段」としては,「適当な3点を選んで2次関数の係数を解いて,他の点群を用いてその結果を評価する」ことを何度も行って一番マシなやつを選ぶとか…… (これでもRANSACと呼べるのかな?)
をとても原始的に実装してみました.(下記コードはC++ですけど,やってることの意味がわかればCでも書けるかと)
データや必要精度次第ですが,とっかかりのCoarseな係数値くらいはこんな雑な方法でも求まるでしょう.
(下記コードでは,3点から係数{a,b,c}を求む処理にはOpenCVのcv::solve()を使いましたが,ここは適当な連立方程式を解く処理を入れればよいです)
- 3点を選ぶ際に,互いにある程度離れた組合せを選ぶようにする
- 評価の際にも,3点から一定以上離れたデータ点群だけを用いるようにする
等の工夫を入れれば,結果がマシになる率が高まるかと思います.
//2次関数 y=F(x; a,b,c) = a*x*x + b*x + c inline double F( double x, double a, double b, double c ) { return (a*x + b )*x + c; } //main int main(void) { //乱数用 std::random_device seed_gen; std::mt19937 MT(seed_gen()); //てきとーに乱数でデータ点群を用意 const int N = 50; //データ点個数 double X[N], Y[N]; //データ点座標 { //正解の係数 const double TrueA = 0.5; const double TrueB = 4.0; const double TrueC = 3.33; //PI const double PI = acos( -1.0 ); //誤差量Max const double MaxErr = 5; // std::uniform_real_distribution<double> Dist; for( int i=0; i<N; ++i ) { //正解の式上の点を求めて… X[i] = Dist(MT) * 100 - 50; Y[i] = F( X[i], TrueA,TrueB,TrueC ); //てきとーに誤差を与えてデータ点とする double ErrR = Dist(MT) * MaxErr; double ErrTheta = Dist(MT) * 2 * PI; X[i] += cos( ErrTheta ) * ErrR; Y[i] += sin( ErrTheta ) * ErrR; std::cout << X[i] << ", " << Y[i] << std::endl; } } //データ点のうち3点を選んで係数を求めることを何度も繰り返して,最も良い係数を求む double ResultA,ResultB,ResultC; //結果係数 { const double deltaTresh = 2.5; cv::Matx< double, 3,3 > A; cv::Matx< double, 3, 1 > b; cv::Matx< double, 3, 1 > x; int Indexes[N]; for( int i=0; i<N; ++i ){ Indexes[i] = i; } int CurrScore = -1; for( int i=0; i<N*3; ++i ) //てきとーな回数繰り返す { std::shuffle( Indexes, Indexes+N, MT ); //係数を解く処理を自前で書くのが面倒なのでOpenCVを使ってます for( int j=0; j<3; ++j ) { double X_ = X[ Indexes[j] ]; double Y_ = Y[ Indexes[j] ]; A( j,0 ) = X_ * X_; A( j,1 ) = X_; A( j,2 ) = 1; b( j ) = Y_; } cv::solve( A, b, x ); //残りのデータ点群を用いて係数の良さを評価 int Score = 0; for( int j=3; j<N; ++j ) { double X_ = X[ Indexes[j] ]; double Y_ = Y[ Indexes[j] ]; double delta = fabs( Y_ - F( X_, x(0),x(1),x(2) ) ); if( delta <= deltaTresh ){ ++Score; } } if( Score > CurrScore ) { CurrScore = Score; ResultA=x(0); ResultB=x(1); ResultC=x(2); } } } std::cout << ResultA << ", " << ResultB << ", " << ResultC << std::endl; // std::cin.ignore(); return 0; }
投稿2018/08/24 02:29
編集2018/08/24 02:30総合スコア11954
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/08/24 02:41
2018/08/27 08:51
0
最小二乗法(直線)の簡単な説明 - 高校数学の美しい物語
このリンクは直線近似の話ですが、曲線でも基本的な原理は変わりません。
要は、
- 直線y=ax+bを仮定する
- それぞれの点に対し、同じx座標を取る直線上の点とのy座標の差(いわば誤差)を求め、
その2乗の合計を計算する
0. その合計が最小になるように直線の式の係数a,bを求める
ということです。3.の「最小となる」条件に微分を利用します。
微分苦手ということですが、多項式の微分しかやらないのでやってください。
追記に対して
y=(X^2+3X+1)^4の傾きを微分の定義を使わないで解くアルゴリズム
傾きを求めたい点のx座標をaとすると、aからわずかに離れた点(a+0.01など)とのy座標との差を取り、
x座標の差で割る
例えばa=1での傾きを求めたいなら、
[{(1.01)^2+31.01+1}^4 - (1^2+31+1)^4] / 0.01
を計算する。
厳密にいうとこちらが微分係数の定義であり、数式の微分は微分の性質というか微分法の話
8/29追記
最小二乗法の3においてどうしても微分を使いたくないということならば、平方完成による手法が考えられます。
pA^2 + qB^2 + r - 2sA - 2tB + 2uAB
=p{A^2 + 2(uB - s)/p A} + qB^2 - 2tB + r
=p{A + (uB - s)/p}^2 + (Bの2次式)
以下Bについて平方完成し、2乗の中身が0になるようA,Bを決定
ただし微分に比べ計算が面倒
投稿2018/08/23 16:44
編集2018/08/28 17:33総合スコア20669
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
微分などを使わない
の意味するところがよくわかりません.
プログラムには(机上で必要な数式を導いた結果の)必要な式だけをインプリメントすれば済みますが,「その必要な式を導出する机上計算で微分などが発生するのがもう嫌!」という話なのでしょうか?
さて,単純な最小二乗法による2次関数フィッティングであれば…
- 固有値問題の形にまで机上で求めておく形になるかと思いますが,この場合,固有値問題を解いてくれるライブラリを探す必要が発生することになるかと.
- 上記を嫌って数値探索的に解こうとする場合,最急降下法やNewton法のような手段を用いるなら最小化対象たる目的関数の(机上での)微分作業は一般に必要ですが,これが面倒な場合には,数値微分で済ますという手もあります.
- 探索法として勾配法的でないものを使うならば,机上での微分計算も要らなくなる可能性はあります.(例えば,Nelderらの滑降Simplex法とか)
投稿2018/08/23 10:56
編集2018/08/23 11:00総合スコア11954
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/08/23 11:02
2018/08/23 11:12 編集
2018/08/23 11:26 編集
2018/08/23 12:27 編集
2018/08/23 13:23
2018/08/24 00:58
2018/08/27 08:55
2018/08/27 09:28
2018/08/27 09:44
2018/08/27 15:27
0
「微分などを使わないで」との事ですので、GA(遺伝的アルゴリズム)を使うのはどうでしょうか?
(a,b,c)を遺伝子として、適応度は「複数の座標との二乗誤差の平均」とすれば、ある程度の解を得られるかと思います。
GAに関しては、例えば「実数値GAのフロンティア」などが参考になるかと思います。
投稿2018/08/23 08:46
総合スコア298
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/08/23 09:05
2018/08/23 09:21
2018/08/23 09:29 編集
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。