独学Common Lisp

行列とつるかめ算

概要

Minimum Common Lispの多値のページで、「つるかめ算」をCommon Lispで実装しました。そこで少しだけ、方程式でも解くことができることを説明しました。

Linear Algebra、すなわち線形代数の最も基本的な部分は、一次方程式を美しく表記し、美しく解くことにあります。美しく解くだけでは自己満足ですが、その美しい解き方は、実は計算機にとっても扱いやすい解法なのです。

このページでは線形代数、行列の基礎的な話に入る前に、行列で何ができるか、という視点から、「つるかめ算」の別の解法をCommon Lispで示します。

行列: 行と列

Common Lispはライブラリがなくとも、行列をサポートしています。ところで、「行列」とは何でしょうか。

答えは単純で、行と列で構成されるデータです。

我々が最もよく目にする行列は、エクセルの表計算シートでしょう。いわゆる「表」は行列の一種です。

しかし、計算における行列はエクセルのシートとは異なる点があります。それは、「全て同質の数値データであること」が計算における行列に不可欠な要素だからです。

エクセルの表計算シートには文字を含めることもできますし、計算式が記述してあるかもしれません。背景が塗りつぶされていたり、フォントが変更されているかもしれません。エクセルはそのようなところを含めて表計算シートですが、計算における行列は純粋に「数」だけを含みます。

では、「同質」とはどういうことでしょうか。例えば、学校におけるクラスの生徒数と、そのクラスの試験の平均点のデータは、ともに「数」ではありますが、片方は人数を表しており、他方は点数を表しているので、「同質」とは言えません。より厳密に言えば、生徒数という行列と、平均点という行列の二つがたまたま同じシートに存在するということになります。一方、国語の点数と算数の点数のデータが羅列されていれば、それは同質なデータですから、行列と言えます。

では、A君の国語の点数とB君の国語の点数は同質でしょうか。これは、2通りの答えがあると思います。

まず、先の例のように国語と算数の点数の比較の文脈であれば、A君とB君で特に区別する必要がありませんから、より一層同質なデータと言えます。つまり、あるクラスの国語の点数が二人分存在するだけ、ということになります。

しかし、もしA君とB君の成績の違いを分析したい場合は、この2つを明確に区別する必要があります。この場合は、A君の国語、算数、理科、社会と、B君の国語、算数、理科、社会、というようなまた別の行列(得点データ)として捉えることができ、2者がとても同質なデータとは言えず、区別すべきデータと言えます。

つまり、行列には大きく「同質性」と「異質性」があるのです。

単純に数学的な行列を習得する場合はあまり意識しないかもしれませんが、統計的手法による経済分析(以後、「計量経済(econometrics)」という言葉を使うかもしれません)では行列の行と列にそれぞれ意味があり、行は「個体」を、列は「変数」を意味することが大半です。つまり先の事例では、A君とB君の違いは1行目と2行目として表現し、国語と算数、理科・社会の違いは1列目、2列目、3列目、4列目というように表現します。列は変数(教科)の数だけ存在し、行は個体(生徒)の数だけ存在します。よって、一般的には行の方が列よりも大きな縦長の行列がイメージされます。

行列において、行だけ、あるいは列だけを抜き出したものを「ベクトル」と呼びます。つまり、A君の「行ベクトル」や国語の「列ベクトル」のように、同質なものだけを特に抽出したものがベクトルです。

行ベクトルと列ベクトルが「クロス」する点は、特定の値が抽出できますから、その特定の値を「スカラ」と呼びます。スカラはただの数です。この場合、A君の国語の点数とB君の算数の点数を比較してもあまり意味がありません。なぜなら、異質なものを比較しようとしているからです。

しかし、これはデータの次元が「生徒」と「教科」という2次元だからであって、もし「時間」という別の次元が加わったら、例えば学期の初めの点数と終わりの点数ということで比較することが可能であれば、クロスな比較にも意味があります。例えば、A君の国語もB君の算数もともに点数が上昇していれば、勉強の効果があったと推定されますが、どちらか片方しか上がっていなければそれは誤差かもしれません。どちらも下がっていたら、何か勉強の逆効果があったのかもしれません。「時間」という別の次元を導入すると、クロスな比較にも意味が生じます。ただし、この場合は3次元になってしまいますから、国語や算数と同じ並び(列)として時間を導入することはできません。計算における行列を拡張し、異質な列も2次元のデータに落とし込んだデータは「データフレーム」と呼ばれます。この場合、学期初めを0という基準で表し、、学期終わりを1という変化要因として数値化して扱うことになります。

計量経済において行列を扱うのは、様々なデータを行列に落とし込むと計算がしやすいからです。データフレームは1行目が列名の行ベクトルになっていますが、2行目以降は特殊な行列として扱うことができます(もちろん数値以外のデータは含めることはできません。数値以外のデータを含める場合は、そのデータ型に対する計算方法を用意しなければなりません)。

方程式から行列へ

このように、行列は単なる行と列ですが、実際には行列として扱うことに意味があります。本題に戻り、つるかめ算を行列で解いてみます。

つるかめ算は鶴と亀の足の本数と全体の頭数が分かっており、それぞれの頭数が分からないという問題でした。そこで、分からないデータである鶴をx羽、亀をy匹とすると、つるかめ算は一般に以下の連立方程式で表現できます。

 x +  y = 頭の数
2x + 4y = 足の数

Minimum Common Lispでの例題は、頭が8で、足が26でしたから、その数を当てはめてみます。

 x +  y =  8
2x + 4y = 26

ここで、上の式では1という「係数」が省略されているので、これを付け足してみます。1というのは鶴も亀も頭の数はそれぞれ1つずつという意味での1です。

1x + 1y =  8
2x + 4y = 26

これがいわゆる「連立方程式」の完全な形です。行列で計算するというのは、これをもっと単純に、そしてそのままの形で問題を解くということです。

では、単純に扱うために記号を省略してみます。

1    1     8
2    4    26

行列っぽくなってきました。ここで、左辺と右辺でそれぞれ行列を作ります。せっかくなので、Common Lispの「配列」表記で記述してみます。左辺はこのようになります。

#2a((1 1)
    (2 4))

そして右辺はこのようになります。

#2a((8)
    (26))

これはCommon Lispによる完全な行列表記法です。この行列をCommon Lispはそのまま評価してくれますから、自分のCommon Lisp処理系の入力画面に打ち込むか、コピペしてみてください。

#2a((1 1)
    (2 4))
; => #2A((1 1) (2 4))

#2a((8)
    (26))
; => #2A((8) (26))

方程式を解く: solve

方程式を行列で表記することができれば、あとはCommon Lispが勝手に方程式の解を求めてくれます。まずはLLAをロードしてください(以後、LLAはロードされている前提で説明します)。

(ql:quickload :lla)

そして、lla:solve関数に、先ほどの二つの行列を引数として渡してください。

(lla:solve #2a((1 1) (2 4)) #2a((8) (26)))
; => #2A((3.0D0) (5.0D0))

これが、つるかめ算の解です。3.0D0'double-float型になっていますが、鶴が3匹であることを、同じく5.0D0は亀が5匹であることを示します。

solve関数がどのようにして方程式の解を求めたのかが気になるところだと思うので、それは次回以降で説明していきますが、このsolve関数は極めて単純に方程式の解を得ることができます。「つるかめ算」自体には特別な解法が存在し、Minimum Common Lispではその解法を実装しましたが、実はCommon Lispで解くなら行列を使うのが一番シンプルです。見ての通り、1行で解決していますから。

線形代数及び行列の役割は様々ですが、計量経済の分野ではこの「方程式を解く」ということが最も重要な役割です。私たちは方程式の解き方を考えて、その手順をプログラムする必要はありません。例え変数が増えても、行列による一般的な解法を備えた関数(solve)さえ用意されれば、様々な方程式に対応することができます。

xyのように数の代わりに文字を使うことを「代数(algebra)」と呼びますが、「線形代数(linear algebra)」というのは方程式が1次であるという意味です。例えば、

y = 2x

をグラフに描くと直線ですが、

y = x^2

をグラフに描くと曲線になります。linearというのは直線ということです。

なんだ直線的なものしか求められないのか、と思わないでください。実は本来的に曲線的であるものも、対数を取ることで直線的になることがあります。計量経済の分野では対数を取ってから線形代数(行列)によって解を求めることも非常に一般的です。


Copyright © 2017- satoshiweb.net All rights reserved.