Tentative NumPy Tutorial ノート¶
本稿は(現在アドレス不明の)Tentative NumPy Tutorial を読んだノートだ。かつて一度は目を通したハズだが、今ザッとリンク先を読んでみたら記憶から抜けている事項が妙に多いので、テキストの形でノートを残すことにした。
Prerequisites¶
これは問題ない。
NumPy を利用するためには、当然 Python のことを少々は知っている必要がある。最低でも Python と NumPy を開発環境で利用可能なようにしておく必要がある。
さらに次のものがあれば便利とある。私は後ろふたつは確保している。
IPython: IPython 利用ノート 参照。
SciPy: SciPy 利用ノート 参照。
The Basics¶
NumPy の基本は何と言ってもクラス ndarray
である。便宜上ここでは配列と呼ぶが、任意次元のテーブルと思ったほうがよい。以下 a
をこのクラスのオブジェクトとする。
array
という別名が付いている。そのテーブルの寸法 (dimensions) を axes と呼ぶ。
対応するプロパティーは
a.shape
である。型は
tuple
であり、どの要素も正の整数である。例えば三次元空間の横ベクトルならば
(3,)
となる。縦ベクトルならばなんと(3, 1)
になる。テーブルの外側から内側に向かって axis の個数が列挙されている。
axes の個数を rank と呼ぶ。対応するプロパティーは
a.ndim
であり、値はlen(a.shape)
と等しい。
An example¶
上述の配列オブジェクトのプロパティーのはたらきを示すコードなので、理解度を念のため確認しておけばよい。
Array Creation¶
配列オブジェクトを生成する方法はいくつもある。
クラス
array
のコンストラクターに Python のlist
またはtuple
のオブジェクトを渡して生成する。配列の
dtype
は各要素から推論 (deduce) されて決まる。またはキーワード引数dtype
で明示的に指定できる。生成する配列の rank に応じて、
list
またはtuple
を入れ子にして指定する。
要素が具体的に決まっていないが、配列の dimensions だけから生成する方法としては、関数``ones``,
zeros
,empty
あるいはその系統の関数を用いる。引数に
(3, 4)
のように指定する。要素の型を明示的にキーワード引数
dtype
で指定することができる。指定しない場合はfloat64
になる。
関数
arange
を用いれば、Python の関数range
よろしく、いわゆる start-stop-step 方式で生成する配列要素を指定できる。ただし、浮動小数点型に対しては色々と危ない。代わりに関数
linspace
を使うのだ。こちらは start-stop-length 方式になる。
デフォルトでは生成配列の最後の要素が stop 自身になる。
Printing Arrays¶
高 rank の配列要素の出力結果の書式について述べている。基本ルールはこういう感じ:
最後の axis の要素(最も内側)は左から右に配列される。
最後から二番目の axis は上から下に配列される。
残りは上から下に配列されるが、各 axis 間は一行空く。
あまりに巨大な配列は適宜出力を省略するようになっている。
関数
set_printoptions
でその辺りを調整できる。
Basic Operations¶
配列同士の算術二項演算子による演算は element-wise になされる。
特に
operator*
もそのルールが採用される。ベクトルの内積・外積、行列の積はそれぞれ専用の関数を用いること。
配列にスカラーを作用させると、各要素にスカラーを作用させた配列が生成する。
a < 35
の例が面白かった。ブール型の配列ができる。
異なる要素型のオブジェクト同士の算術演算について、
operator(lhs, rhs)
タイプは、精度の高い要素のほうの要素型の配列が生成する。.operator(other)
タイプは、左辺値ほうの要素型の配列が生成する。
.sum()
,.min()
等のメソッドはデフォルトでは全要素を対象として演算を行うが、キーワード引数axis
を明示的に指定することで、配列の axis に沿って演算を行わせることができる。
Universal Functions¶
配列を引数にとって、戻り値を配列とする(数学的な)関数のことを universal function と呼ぶ(ちなみに universal を辞書で引くと <common to all members of a class or a group> という意味がある)。
np.sin
や np.exp
に何か浮動小数点型要素の配列を渡すと言わんとすることがわかる。
Indexing, Slicing and Iterating¶
一次元配列
添字で要素にアクセス可能。左辺値としても使える。
スライス操作ができる。構文は
a[start:stop:step]
でstop
は開区間エンド。a[start:stop:]
も可。a[:stop:step]
も可。a[::-1]
も可。
for i in a:
の構文で要素を順番にアクセスできる。右辺値。
多次元配列
カンマで区切ることで axis ごとに添字を指定することで要素にアクセスできる。
a[axis0, axis1]
は一番外側axis0
番目の、その次の内側axis1
番目の要素にアクセスする。
カンマ記法とスライス記法を組み合わせられる。例えば
a[0:5, 1]
ならば一番外側 axis の 0, 1, 2, 3, 4 番目の短冊を取って、一番内側 axis の左から一番目の要素を取って来られる。さらに dots 記法というのもある。これは一つの axis を丸ごと指定するようなスライスの省略らしい。例えば rank 3 の配列に対して
a[1, ...]
はa[1, :, :]
(ora[1]
) と同値。for i in a:
でループすると、一番外側から一個内側の axis を順番にアクセスすることになる。一方fot i in a.flat
としてループすると、一番内側の要素を一個一個順番にアクセスすることになる。
Shape Manipulation¶
Changing the shape of an array¶
配列のメモリレイアウトは基本は C 言語スタイル。
メソッド
ravel
,reshape
等にはキーワード引数で FORTRAN スタイルのメモリレイアウトで新しい配列を返すように指示することができる。メソッド
reshape
は自身は変更せずに新しいオブジェクトを返す。一方、メソッドresize
は自身を変更する。変形メソッドに一部の dimension を
-1
と指定することで、残りの引数から自動的に計算させることが可能。
Stacking together different arrays¶
異なる配列オブジェクトを異なる axis でくっつけられる。関数
vstack
やhstack
を用いる。a[:, newaxis]
という構文? がアレ? 横のものを縦にする?→
newaxis
を指定した添字位置に対応する axis が追加された新しい配列が生成する。関数
column_stack
やrow_stack
は縦横を入れ替えて並べた配列を生成する。配列全体ではなく、スライスを並べることもできる。
関数
vstack
やhstack
の強化版としてr_[]
,c_[]
という便利なものもある。
Splitting one array into several smaller ones¶
関数
hsplit
やvsplit
で、配列を分割できる。分割数または分割位置を指定する。
Copies and Views¶
SciPy の Cookbook でも少し触れたこと。
No Copy at All¶
単純な代入操作、要素操作ならばコピーは発生しない。
関数呼び出しの引数はコピーによる受け渡しではない。
View or Shallow Copy¶
ビュー、すなわち浅いコピーについて。
a.view()
で内部データを共有する新しい配列オブジェクトを生成できる。例えばビューの shape だけを変形させておきつつ、元の shape を触らない、というようなことが可能。
どこかビューの要素を変更すると、対応する元配列の要素も同じ値に変更される。
スライスもビューである。
Deep Copy¶
a.copy()
で、すべての要素が a
のそれと等しくかつ新しい配列オブジェクトが生成する。
Functions and Methods Overview¶
NumPy Example List という別文書へのリンク集。
Less Basic¶
基本というほどではなく。
Broadcasting rules¶
異なる dimensions を持つ配列を universal function に与える時になされる演算の規則性を規定するもの。
ランクの小さい方の配列の shape に対して、先頭(左)から 1 を追加していき、ランクの大きい方の配列のランクとまずは一致させる。
例を示す:
a.shape: (2, 3, 4, 5) b.shape: (6, 7) c.shape: (3, 1, 5) => a.shape (2, 3, 4, 5) a が最大ランクの配列なので、基準になる。 => b.shape (1, 1, 6, 7) 1 を左側に (a.ndim - b.ndim) 個入れた。 => c.shape (1, 3, 1, 5) 1 を左側に (a.ndim - c.ndim) 個入れた。
対応する各 axis に対して、次の条件のいずれか一方が成り立つとき、broadcasting は成功する。
両者の値が一致する。
どちらの値が 1 である。このとき、小さい方の配列を引き伸ばして、大きい方の配列の dimensions に合わせることになる。欠けていた要素の値は、元の一個しかなかったその値で埋める。
先ほどの配列で考えてみる:
(a + b).shape ValueError: operands could not be broadcast together with shapes (2,3,4,5) (6,7) (4, 5) != (6, 7) ゆえ。 (a + c).shape the same as a.shape (2, 3, 4, 5) と (1, 3, 1, 5) で値が 1 の axis を除けば、 両者は一致しているので OK とみなす。
Fancy indexing and index tricks¶
NumPy の配列の添字システムは Python の list よりも多彩。
Indexing with Arrays of Indices¶
配列オブジェクトを別の配列オブジェクトの添字として利用できる。言わば添字型の配列。
Indexing with Boolean Arrays¶
ブーリアン型の配列オブジェクトを配列の添字として用いると、値が True
の要素だけからなる配列が生成する。
The ix_() function¶
関数 ix_
を説明するのは面倒だ。相異なる n 個のベクトル(平坦な NumPy 配列と考えること)があり、これらから要素をひとつずつ取ってきて多項演算を行うという操作を一気に実行するための前準備をするものだ。
Indexing with strings¶
配列の要素に名前でアクセスする方法がある。
img = array([[(0,0,0), (1,0,0)],
[(0,1,0), (0,0,1)]],
[('r',float32), ('g',float32), ('b',float32)])
print(img['r'])
Linear Algebra¶
基本的な線形代数がここに来るとのこと。
Simple Array Operations¶
ファイル linalg.py
を見ろとのこと。
The Matrix Class¶
クラス
matrix
というものがある。コンストラクターに文字列を渡すようだ。
プロパティー
.T
で転置行列を得る。プロパティー
.I
で逆行列を得る。
Indexing: Comparing Matrices and 2D Arrays¶
配列クラスと行列クラスでの添字の違いを説明する。
同型の 2 次元配列と行列に対して、それぞれにスライス
[:, 1]
を得ようとすると、両者の結果の dimensions が異なる。配列の方はランク 1 の配列を生成し、一方行列の方はランク 2 の行列を生成する。行列クラスには
.A
というプロパティーがあり、これが行列成分の配列表現である。適宜利用するとよい。
Tricks and Tips¶
知っていると便利なコツ。
“Automatic” Reshaping¶
先述の配列オブジェクトの shape 変形にまつわる -1
記法について。
Vector Stacking¶
既に述べたことだが、同型の行ベクトルから二次元配列を生成する方法として、関数
vstack
を用いる。
Histograms¶
関数
np.histogram
は配列からヒストグラムのビン(各個数と各点)を返す。一方、関数
pylab.hist
はそれ相当の処理に加えてプロットまでを行う。
References¶
ここには 7 個の参考文書がリストされているが、おそらくどれも読まないで済ませそうだ。