線形代数をpythonで。part1

python.atelierkobato.com

まあ私が所属する予定の研究室はゴリゴリプログラムを書くらしく、主に線形代数を使うらしいので上記の記事をやっていこうと思う。

やってく中で疑問が生じた点や、メモを残す。主にサンプルプログラムのpythonの書き方についてを書くだろう。

ちなみに、pythonは全くの初心者ですので。

目次



01ベクトル

python.atelierkobato.com

例によって、以下の拡張パッケージが欲しいらしい。

 ・NumPy

 ・Scipy

 ・SymPy

 ・Matplotlib

Anacondaだと既にインストールされているらしい。しかし、私はなんかAnaconda使うのがいけ好かないので*1公式サイトでのPythonをインストールしている。

なので。

python -m pip install numpy
python -m pip install scipy

pipを使ってインストールした。pipは標準でついているので安心。

参照記事。 www.python-izm.com

準備はok.

最初にベクトルの演算をしたが。

import numpy as np

v=np.array([10,20,30])
w=np.array([2,4,6])

print("v+w:{}".format(v+w))
print("v-w:{}".format(v-w))

はい。わからない単語が出てきました。import。意味はわかるけど。 C言語言う、math.hとかstudio.hとかの部類だろう。

ここではモジュール、ライブラリ、パッケージを読み込むという意味である。(正直この三名称は全部同じようなものを指していると考えていいのか?) ここで使っているのはただのimportではなく、

import numpy as np

である。英語のasの意味を考えればすぐ覚えられるが、numpyをimportして、numpyをnpという名称で使いますよってこと。よく使う長いパッケージ名だとわかりやすくするといいのかもしれない。

NumPyやpandasなど、省略名でインポートするのが慣例となっているライブラリもある。

import numpy as np
import pandas as pd

numpyは慣例でnpらしい。

参照記事 note.nkmk.me

次は標準出力に当たるとこだが、ただのprintではない。

print("v+w:{}".format(v+w))
print("v-w:{}".format(v-w))

formatを使っている。 基本的に使い方は 文字列.format(値,値)文字列に値を入れたいところを{}と置く。 {:s}とかなんかいろいろある。C言語でいうところの%dとかそのあたりだろう。

参照記事 www.javadrive.jp

*の演算。

print(v*w)
[ 20  80 180]

ここのnumpyの*演算は内積でも外積でもない。各配列の要素の掛け算である。つかうことあるのかな。 割り算である/の演算も同様な挙動。ただし、ベクトルとベクトルの演算の場合。

ベクトルとスカラーの演算をするとどういう挙動を示すかというと、

print(v+1)
[11 21 31]
print(v*10)
[100 200 300]

となる。加算と減算が特殊だね。すべての成分にそのスカラー量が足されてます。


02ベクトルの大きさと単位ベクトル

ベクトルの大きさ

ベクトル \boldsymbol{v}=\begin{bmatrix}v_1,\
v_2\end{bmatrix}

の大きさは

\displaystyle
\parallel\boldsymbol{v}\parallel=\sqrt{v_1^2+v_2^2}

である。

一般にユークリッドノルムというらしい(初耳)

import numpy as np
v=np.array([1,2,3])
v_n=np.sqrt(np.sum(v**2))
print(v_n)
3.7416573867739413

と、ここにきてベクトルの*演算が出てきた。(さっきいつ使うんやとか言ってたのに)

np.sumは引数の配列をすべて足し合わせてくれる。そのルートだから、定義通りに素直にやってる。

import numpy as np
from scipy.linalg import norm

v=np.array([1,2,3])
v_n=norm(v)

print(v_n)

これはscipy.linalg.norm()を利用した楽なやり方。

import numpy as np
from scipy.linalg import norm

a=np.array([
    [1,2,3],
    [4,5,6]
])
#axis=1で行方向にノルムを計算。axis=0で列らしい
a_n=norm(a,axis=1)

print(a_n)

これはscipy.linalg.norm()のオプションを利用したもの。二次元配列を行ごとにnorm処理したいときに。

単位ベクトル

単位ベクトルは大きさ1のベクトルのこと。任意のベクトルvで考えるとこーなる。

{\displaystyle{\boldsymbol{e_v}=\frac{\boldsymbol{v}}{\parallel\boldsymbol{v}\parallel}}}

高校範囲。

で、なんかよくわからんものが出てきた。

np.set_printoptions(precision=3)

python.atelierkobato.com 曰く、小数点以下は3桁まで表示せよ。

import numpy as np
from scipy.linalg import norm
np.set_printoptions(precision=3)

v=np.array([1,2,3])
u=v/norm(v)

print(u)

出力は

python .\02.02.py
[0.267 0.535 0.802]

たしかに、割り算で小数点以下いっぱいは嫌だもんな。

次は複数のベクトルの大きさを1に正規化する。(二次元配列の) と、その前にprintの\nの使用について面白いのでメモ。 www.freecodecamp.org

# ベクトルの大きさを1に
import numpy as np
from scipy.linalg import norm
np.set_printoptions(precision=3)

a=np.array([
    [1,2,3],
    [4,5,6]
])

a=a/norm(a,axis=1,keepdims=True)#次元が保存される。三次元配列の和であれば三次元配列が出力されるらしいがよくわからん。
#行ベクトルの正規化
print("a:\n{}".format(a))
#行ベクトルのノルムが1であるか確認
a_norm=norm(a,axis=1,keepdims=True)

print("Row norm of vector a:\n{}".format(a_norm))
python .\02.03.py
a:
[[0.267 0.535 0.802]
 [0.456 0.57  0.684]]
Row norm of vector a:
[[1.]
 [1.]]

うむ。1.の表記はfloatという証。単純にnormのオプションのaxisとkeepdimsをつかうだけ。keepdimsをFalseにしたらエラーになった。


余談。HatenaBlogのTeX表記。

自分はmarkdownで記事を書いている。(便利だよ!!)

しかし、其のせいかはわからないが、TeX表記がバグることがある。

[tex:{\displaystyle
\parallel\boldsymbol{v}\parallel=\sqrt{v_1^2+v_2^2}
}]

とかくと [tex:{\displaystyle \parallel\boldsymbol{v}\parallel=\sqrt{v_12+v_22} }]

このようになる。なんでや。

とまあ、\[\sin\]でやってみたり\displaystyleを消してみたりしたが上手くいかない。 調べると以下の記事が見つかった。 minus9d.hatenablog.com

この記事をみて解決いたしました。

要は、怪しい記号(今回は_^)はすべてエスケープする(\を前につける)と上手く表示してくれます。

*1:完全に意地っ張り精神