Pythonの数値計算ライブラリ NumPy入門

Scientific Computing Tools For Python — Numpy

NumPy は Pythonプログラミング言語の拡張モジュールであり、大規模な多次元配列や行列のサポート、これらを操作するための大規模な高水準の数学関数ライブラリを提供する。(via Wikipedia)

これまで知識があいまいだったNumPyについて、もう一度おさらいしたいと思います。NumPyはSciPyと併せて科学技術計算でよく利用されています。また、高速に行列演算ができるのでOpenCV(コンピュータビジョンライブラリ)でもNumPyを利用したPythonインタフェースが提供されるようになりました。

OpenCVのPythonバインディングについては去年のエントリーでも取り上げていますので参考までに。
* さくらVPSにOpenCVをインストールしてPythonから使う

[2017/04/29 更新]

  • CentOS 7.0, Python 3.6, NumPy 1.12で動作確認
  • Record Arrays, Automatic Reshaping, 乱数生成, Linear Algebra(線形代数)について新規説明を追加

環境

  • CentOS 7.0 (x86_64)
  • Python 3.6.0
  • NumPy 1.12.0

NumPyの日本語ドキュメントは豊富にありますが、自分で手を動かしながらここに整理しようと思います。

  • NumPy配列(numpy.ndarray)とは
    • numpy.ndarrayの属性(attributes)
    • データ型について
  • 配列の生成
    • Record Arrays
  • 配列形状の変更
    • Automatic Reshaping
  • Indexing
    • Fancy Indexing
    • インデックスの検索
  • 配列に対する操作/演算
    • 配列の結合/分割、軸操作
    • 配列のソート
    • 配列要素に対する演算
  • Broadcasting
  • 配列の走査
  • 乱数生成
  • 統計関数
  • 線形代数
  • ファイル入出力

NumPy配列(numpy.ndarray)とは

An ndarray is a (usually fixed-size) multidimensional container of items of the same type and size.

numpy.ndarray は多次元配列を扱うクラスです。基本的に以下の制限があります。

 * 配列内要素の型は全て同じ
 * 配列長は固定 (固定長配列)
 * 配列の各次元の要素数は同じ

(※ ただし、制限付きで配列の形状変更は可能。説明は後述)
実体はC言語の配列になっています。制限がある分、Pythonのリスト(list)型と比較して大規模な配列を扱う際の処理効率が良くなっています。また、これ以降 “配列” と表記したときは基本的に numpy.ndarray を指すこととします。

* import

numpy.ndarrayの属性(attributes)

numpy.ndarray の主な属性については以下の通り。効率良く処理するためにndarrayのデータはメモリの連続領域上に保持されていますが、これらの属性を参照するとデータがメモリ上にどうレイアウトされているかを調べることができます。

An instance of class ndarray consists of a contiguous one-dimensional segment of computer memory

* Internal memory layout of an ndarray

ndarray.flags 配列データのメモリレイアウト情報 (numpy.flagsobj)
ndarray.ndim 配列の次元数
ndarray.size 配列の要素数
ndarray.shape 各次元の要素数
ndarray.itemsize 1要素のバイト数
ndarray.strides 各次元で次の要素に移動する際に必要なバイト数
ndarray.nbytes 配列全体のバイト数
ndarray.dtype 配列要素のデータ型 (numpy.dtype)

stridesは、メモリ上でa[0,0]とa[0,1]は8バイト離れており、a[0,0]とa[1,0]は24バイト離れていることを示します。データの並びがFortran型の場合は、strides は (8, 32) となります。一次元の場合はC型もFortran型も関係ありません。

データ型について

配列要素のデータ型はnumpy.dtypeというオブジェクトで扱われています。指定できる型については大きく分けて、論理型、符号付き整数型、符号無し整数型、浮動小数点型、複素数型の5つ。あとはデータ型のビット数別にそれぞれ指定できます。詳細は公式サイトを参照してください。

* Data types — NumPy

また、文字列表現でも型指定が可能です。

データ型のキャストも可能です。ndarray.astype() を使います。

ダウンキャストでも例外は発生しません。また、ndarray.astype() は新しい配列を生成して返すので注意してください。

配列の生成

まずは配列の生成方法から。生成方法はたくさんありますが、ここでは基本的でよく使われる方法を中心に紹介します。

numpy.random モジュールによる疑似乱数生成については後半で詳しく紹介します。

Record Arrays

冒頭で配列内要素の型は全て同じと書きましたが、各要素個別に型指定することで配列内に複数の型の値を入れることができます。また、各要素を数値インデックスでなく属性で参照することもできます。

このように配列内要素を構造化することができます。初期化が少し面倒ですね。

配列形状の変更

ndarrayオブジェクトは制限付きで配列形状の変更が可能です。
※ ビュー(View:参照)
NumPyの一部の操作で返されるオブジェクトはビュー(View)と呼ばれ、元データの参照となります。なので、ビュー内の値を変更すると元データも変更されるので注意してください。ディープコピーが必要な場合は前述した ndarray.copy() を利用しましょう。

返される配列がビューかコピーになるかはきちんと把握しておいた方がいいです。それと ndarray.reshape() はよく使うのでこれも覚えておくといいかと思います。

Automatic Reshaping

配列形状変更の際に、要素数の指定を一部省略することができます。

これは便利ですね。配列の分割操作等もスマートに書けそうです。

Indexing

配列要素の参照/代入、配列のスライスなどについて紹介します。基本的にPythonのリスト(list)とよく似た操作方法ですが、一部拡張構文があるので確認しておきます。

Fancy Indexing

要素の位置や条件などでマスクした特殊なインデックス指定も可能です。

インデックスの検索

ndarrayの内部構造はCの配列と似ていてもインタフェースはさすが高級言語ですね。 ただ、配列のスライス処理でNumPy固有の記法を使いすぎると読みづらくなるような気もするので、複数人で開発するときは節度ある使い方をした方が良さそうです。

配列に対する操作/演算

前述の配列形状の変更以外にも様々な操作が可能です。ここでは紹介しきれないのでほんの一部だけ載せます。

配列の結合/分割、軸操作

配列のソート

配列要素に対する演算

様々な配列要素に対する(element-wise)演算機能が提供されています。また、それらの機能の多くは各演算子を用いて利用することも可能です。

Broadcasting

前述の配列要素に対する各演算は同じサイズ/形状の配列同士で行っていましたが、NumPyではサイズ/形状の異なる配列同士の演算も可能で、これをブロードキャストを呼んでいます。

2つめの例は面白いですね。ブロードキャスト機能は上手く使いこなせばコード量を大きく減らすことができそうです。

配列の走査

配列の走査はリスト(list)と同様に for in 構文を使って行うことができます。

乱数生成

Mersenne Twisterアルゴリズムによる疑似乱数生成器が利用できます。numpy.random モジュールはPython標準の random モジュールよりも大規模データを扱う際に効率的に処理されます。

同じ機能に複数の別名関数(エイリアス)があるのはPythonicじゃないと思います。何らかの確率分布に従う乱数が欲しい場合は SciPy の scipy.stats モジュールを使った方がわかりやすいかもしれません。

統計関数

NumPyでは基礎的な統計処理用の関数群が提供されています。

より高度な統計処理を行いたい場合は SciPy を利用することになると思います。

線形代数

基礎的な線形代数関連の関数も備えています。

逆行列を計算してからベクトルとの積を取るよりも、linalg.solve() で計算した方が楽だし計算も速いとのことです。

ファイル入出力

配列データのファイル入出力もできます。実験作業などではよくお世話になる機能です。

巨大なデータを保存するときは、バイナリ形式で保存した方がファイルサイズが小さくなるので良いかと。

今回はNumPyの基礎について整理してみました。僕自身はNumPyを単体で利用することはほとんどないのですが、OpenCVのPythonバインディングを利用するときによくお世話になっています。NumPyは機能が豊富なため、必要に応じてその都度公式リファレンスを参照しながら使っていく必要がありそうです。

* 参考
NumPy Reference
科学技術計算のために Python を始めよう
機械学習の Python との出会い

あわせて読む:

3 Thoughts

  1. ありがとうございます。
    とても参考になりました。

  2. 参考になりました
    最後の例にxとaのtypoがあります

  3. ご指摘ありがとうございます。修正致しました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です