気づいてしまったのだ……
僕は気づいてしまいました、せっかく超高速で配列処理をできるNumpyがあるのにそれを活用できていないということに…
そういったわけで、本日はNumpyを意味もなくいじっていきます。
NumPyは、プログラミング言語Pythonにおいて数値計算を効率的に行うための拡張モジュールである。効率的な数値計算を行うための型付きの多次元配列(例えばベクトルや行列などを表現できる)のサポートをPythonに加えるとともに、それらを操作するための大規模な高水準の数学関数ライブラリを提供する。
まずは、その高速さを実感してみるために九九表でもつくってみます。とりあえず何も考えずバニラなPythonでfor文を回して作ってみます。
import time start = time.perf_counter() result=[] for i in range(1,10): for j in range(1,10): result.extend([i*j]) print([result[i:i+9] for i in range(0,81,9)]) end = time.perf_counter() print (end-start)
実行結果
[[1, 2, 3, 4, 5, 6, 7, 8, 9], [2, 4, 6, 8, 10, 12, 14, 16, 18], [3, 6, 9, 12, 15, 18, 21, 24, 27], [4, 8, 12, 16, 20, 24, 28, 32, 36], [5, 10, 15, 20, 25, 30, 35, 40, 45], [6, 12, 18, 24, 30, 36, 42, 48, 54], [7, 14, 21, 28, 35, 42, 49, 56, 63], [8, 16, 24, 32, 40, 48, 56, 64, 72], [9, 18, 27, 36, 45, 54, 63, 72, 81]]
意味はないけど、なんかこういい感じに見栄えを整えてみる。
そして、numpyを使っての九九表を作ってみます。
import time import numpy as np start = time.perf_counter() row = np.arange(1,10)[np.newaxis, :] column = np.arange(1,10)[:, np.newaxis] print(row*column) end = time.perf_counter() print (end-start)
実行結果
[[ 1 2 3 4 5 6 7 8 9] [ 2 4 6 8 10 12 14 16 18] [ 3 6 9 12 15 18 21 24 27] [ 4 8 12 16 20 24 28 32 36] [ 5 10 15 20 25 30 35 40 45] [ 6 12 18 24 30 36 42 48 54] [ 7 14 21 28 35 42 49 56 63] [ 8 16 24 32 40 48 56 64 72] [ 9 18 27 36 45 54 63 72 81]]
Numpyはfor文を使ったら負けかなみたいなやつなのでそういう書き方で書き直してみる。そして、この実行結果を比較してみまs……。なんか速度そんな変わらんですね……。なんでやろな……。
まあ、いいや。こんな感じでNumpyを使うとfor文を使わずとも計算ができて処理が爆速だそうです(説得力なし)。
じゃあ、数学やります
なんか、このまま終わらせるとNumpyに手を出した意味を感じなくなってしまうので、「(僕だけが)たのしいベクトルのはなし」(唐突)でもしてNumpy使ってよかったって感じにまとめていきたいと思います。Numpyは数値計算ライブラリなんでそういうのいじるのに特化してます。
そういうわけでまずはベクトルについての話をば……。このブログを読んでいる聡明な読者の皆様ならベクトルは余裕で分かる人しかいないと思いますが、説明します。ベクトルとはベクトル空間上にある要素のことです(突然の超抽象概念)。ベクトル空間とは……。
まあ、そう抽象化されてもわけわかんないですよね。普通に生きていくのに使うレベルのベクトルだったら「大きさと向きを持った矢印さん」って認識でいいと思います。その認識を持っていると何がよろしいのかといいますと、例えばゲームキャラクターの動く速度をどんな向きで動かしても一定に担保したりするのに役立ちます。
そういったわけで、ベクトルにすると座標にして位置情報で管理するよりもパラメータの管理が便利になったりします。そして、扱うものが座標から矢印さんをベースにすることで応用できる概念が生まれたりします。それが内積だったり、外積だったりします。んで、これがわかると何が良いのかというと以下のようなものを知りたいときに応用が利きます。
平面の図で適当に描いてみるとこんな感じ。
雑に書いた結果何がなんやらになってしまった。図にすると外積の方はイメージしやすい気が……。そして、内積はあの図のなかでどう落とし込めばいいんですかね……。
まあいいや、内積は上の図と公式より「同じ方向の成分に落とし込んだ矢印さん同士をかけたもの」って言い換えることができます。物理などの世界では仕事量とかそういうので利用されます。この仕事量の考え方を良い感じに扱うと統計での相関の考え方に応用できるようになります。また、矢印さんのなす角度によって正負の判定ができるので、鈍角・鋭角の判定にも利用できます。
ちなみにNumpyでは以下のメソッドが用意されています。
# 内積(ドット積) numpy.dot(a, b, out = None)
# 内積
numpy.inner(a, b)
外積のほうは図のような感じであらわすことができます。物理の世界だとローレンツ力とかなんかの円運動するやつによく利用されたりします。ゲームとかですと、掛ける順番で向きが代わる性質利用して平面の左右の位置関係を調べたりするのに使えるらしいね。あとは三角ポリゴンの裏表を調べるのとか……。
ちなみにNumpyでは以下のメソッドが用意されています。
# 外積(クロス積) numpy.cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None)
# 外積 numpy.outer(a, b, out=None)
まあ、そんな感じで複雑な計算しなくてもNumpy側でそういう計算が用意されているそうです。やはり、Numpyは便利なので使っていくしかないですね(無理やりまとめる)。完全にゲーム脳だからゲームで使うレベルでの知識範囲しか想定してない……。これはどうしたものか……。まあいいや。どう使っていくかは、またNumpy使うときにまた見ていくことにします。
― 終