いや…… ある日 LINE で遊んでいたら、相手の隠していた爪が露わになって戦慄しているのです。
高校最初のテストで世界トップクラスの成績……。
……なんか、定期的にガチ勢に出会うよね。
文系だろうが理系だろうが 100点は 100点だし世界の頂点だし神。
なんでキミがそんなに偉そうなんだよ!
まぁでも、たーせるくんも常々数学と仲直りしたがっているみたいだし、今日は軽く数学のお話でもしようか。
参考文献
- 金谷健一 著, 『これなら分かる応用数学教室―最小二乗法からウェーブレットまで』, 共立出版(2003).
直線の当てはめ
いいかい?
個のデータ に直線を当てはめたいとしよう。
ここで、当てはめたい直線を と置く。
は、どちらもこれから求める未知の定数だよ。
そうだね。
だから、すべての点の一番近くを通る直線を見つけることにしよう。
これは、 を満たす を見つける問題と見なせる。
ただし、 は「ほぼ等しい」という意味。
なるほど。。。
各点の ↕︎ をできるだけ短くできればいいのか。
各点と直線のズレを最小にする問題を、以下のように解釈しよう。
ちなみに、 は、その左側の式を最小にすることを表すものとするよ。
後の計算をラクにするためのおまじないだよ。
これで、変数 の2次関数の最小値を求めればよいことが分かるでしょ。
2次関数の最大値・最小値は、中学で平方完成を使った解法を学ぶので馴染みが深いと思う。
でも今回は多変数関数だから偏微分で解くよ。
そういえば高校生の頃、関数 の極値を求めるために、 を で解いたっけ。
あれは1変数関数だったけど、条件さえ揃えば多変数関数でも同じ議論が成立するんだったね。
従って、 を解けば が求められる。
肩慣らしだ、やってみよう。
単なる合成関数の微分だよ。
のとき、 っていう公式、覚えてる?
いやまぁ…… それは覚えている。
ただ、なんか微分する際に をこんなふうに扱っていいのか一瞬わからなくなったんだ。
ホントだ。
というか、邪悪な を解除して展開したら計算が合った。
結局、これを行列の形で書き直すと以下のようになる。
この方程式を解けば が定まるよ。
ここからの計算量ヤバいじゃん。
こんなものどうやって解けと。
例題
点 に直線を当てはめよ。
from pylab import plot, show x_numbers = [4, 15, 30, 100] y_numbers = [-17, -4, -7, 50] plot(x_numbers, y_numbers, 'o') show()
じゃあ Python で求解しよう。
方程式の係数行列を 、右辺のベクトルを とでもしておこう。
from functools import reduce import numpy as np from numpy.linalg import solve x_numbers = [4, 15, 30, 100] y_numbers = [-17, -4, -7, 50] A = reduce(lambda a, b: a + b, \ [np.matrix([[x ** 2, x], [x, 1]]) for x in x_numbers]) p = np.array([x_numbers, y_numbers]).T B = reduce(lambda a, b: a + b, \ [np.matrix([[x[0] * x[1]], [x[1]]]) for x in p]) print(solve(A, B))
matrix([[ 0.68729598], [-20.10177525]])
えっ…… コード短っ。
これが連立方程式の解?
そうだよ。
だね。
おまけ: ちょっと気になる Python の話
x_numbers = [4, 15, 30, 100] A = reduce(lambda a, b: a + b, \ # ❷ [np.matrix([[x ** 2, x], [x, 1]]) for x in x_numbers]) # ❶
x_numbers
の各要素を行列に map
してるんだ。reduce
によって、各行列の総和を取っている。こっちはちょっとトリッキーだよ。
これも順番に見ていこうか。
x_numbers = [4, 15, 30, 100] y_numbers = [-17, -4, -7, 50] p = np.array([x_numbers, y_numbers]).T # ❸ B = reduce(lambda a, b: a + b, \ # ❺ [np.matrix([[x[0] * x[1]], [x[1]]]) for x in p]) # ❹
まず ❸ では、 と のペアを作っている。
x_numbers
と y_numbers
をがっちゃんこして転置したものを変数 p
に代入している。
T
は転置の T なのか。続いて ❹ では、 の各項 を計算している。
あとはわかるね?
最後は ❺ の reduce
で全項を足し合わせて が得られるんだね。
というかすごいね、たったこれだけのコードで方程式が解けるなんて……。