機械学習 はじめよう

第6回Numpyの導入

今回は第3回の冒頭で紹介した、Numpyの導入方法と簡単な使い方について説明します。次回で様々な分布を扱うためにNumpyの準備をしておきましょう。

Numpyの導入

Numpyはオープンソースの拡張モジュールで行列や多次元配列と、それらを操作するための数学関数ライブラリを提供しています。Numpyの内部はC言語で実装されているため、普通にPythonで実装した時と比較するとはるかに高速に実行することが可能です。

ここではインストールの仕方とNumpyの簡単な実行例を確認しておきましょう。

インストール

WindowsとMacOSXのPCにNumpyをインストールする場合は、NumpyのサイトのDownloadのページの上の方にあるNumPyのProjectからインストール先のマシンのOSに対応したファイルをダウンロードして実行してください。

しかし、MacOSXにデフォルトでバインドされているPythonを利用している場合はインストールできません。Snow Leopardを利用している場合はScipy Superpackを利用すると簡単にインストールできます。このパッケージのバイナリはSnow Leopard,Xcode 3.2.2,GCC4.2.1,Python2.6.1環境向けにビルドされています。

ソースコードリポジトリから最新版のインストールを行う場合は、以下のように実行してください。

$ svn co http://svn.scipy.org/svn/numpy/trunk numpy
$ cd numpy
$ su
$ sudo python setup.py install

また、gitからインストールもsvnの場合も同様に以下の手順でインストールできます。

$ mkdir ~/tmp
$ cd ~/tmp
$ git clone git://github.com/numpy/numpy.git numpy
$ cd numpy
$ sudo python setup.py install

インストールを終えたら、単体テストを実行してみましょう。単体テストを実行するにはnoseというサードパーティー製のライブラリをPython環境にインストールしておく必要があります。easy_installについて良くわからないという方はこちらを参照してください。

$ sudo easy_install nose

実際に単体テストを実行してみると、以下のようになります。

>>> import numpy
>>> numpy.test()
Running unit tests for numpy
NumPy version 2.0.0.dev8716
NumPy is installed in /opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/numpy
Python version 2.6.6 (r266:84292, Oct  8 2010, 22:12:21) [GCC 4.2.1 (Apple Inc. build 5646)]
nose version 0.11.3
 
(中略
 
----------------------------------------------------------------------
Ran 3029 tests in 17.020s
 
OK (KNOWNFAIL=4, SKIP=1)
<nose.result.TextTestResult run=3029 errors=0 failures=0>

numpy.test()でerrorが出力されていなければ、問題なくnumpyを利用できるでしょう。

Numpy簡単な使い方

それでは、簡単にNumpyの実行例を確認していきます。まずは対話型インタプリタを起動してNumpyをインポートしてみましょう。ここでは慣例に従ってnpと別名をつけて利用することにします。

$ python
Python 2.6.6 (r266:84292, Oct  8 2010, 22:12:21)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import numpy as np

以下の例では、numpyはインポートされているとしてインポートの部分は省略します。

Numpyのバージョンを確認する

これで現在利用しているNumpyのバージョンを確認できます。

>>> np.version.version
'2.0.0.dev8716'

キーワードからNumpyの機能を探す

Numpyでは関数lookfor()を利用することで、Numpy内のdocstringからキーワードから必要になりそうな機能をリストアップしてくれます。例えば、キーワード'array'から使えそうな機能を探してみましょう。

>>> np.lookfor('array')

すると、以下のように検索された機能の一覧が表示されます。

Search results for 'array'
--------------------------
numpy.array
   Create an array.
numpy.asarray
   Convert the input to an array.
numpy.ndarray
   ndarray(shape, dtype=float, buffer=None, offset=0,
numpy.asfarray
   Return an array converted to a float type.
numpy.recarray
   Construct an ndarray that allows field access using attributes.
numpy.all
   Test whether all array elements along a given axis evaluate to True.
numpy.array_str
   Return a string representation of the data in an array.
numpy.any
   Test whether any array element along a given axis evaluates to True.
numpy.eye
   Return a 2-D array with ones on the diagonal and zeros elsewhere.
(略...

検索結果の画面から、通常の対話型インタプリタに戻るにはqを押下してください。

arrayオブジェクトを操作する

Numpyにはndarrayクラスが存在します。これは行列のようなものと考えるとわかりやすいと思います。ndarrayクラスは1つの配列中に異なる型のオブジェクトを混在させることが出来ません。しかし、その分メモリ効率や実行効率がいいものとなっています。

arrayオブジェクトの生成方法の基本はarray関数の呼び出しで行います。array関数で生成されたオブジェクトは大抵の場合array型のオブジェクトを返します。それでは実際にarrayオブジェクトを生成してみましょう。

>>> import numpy as np
>>> a = np.array([1,2,3,4,5])
>>> b = np.array([[1.,0.,0.],[0.,1.,0.],[0.,0.,1.]])
>>> a
array([1, 2, 3, 4, 5])
>>> b
array([[1, 0, 0],
      [0, 1, 0],
      [0, 0, 1]])

arrayオブジェクトの生成時にdtypeを指定することでデータ型を指定してオブジェクトを生成することも可能です。

>>> a = np.array([1,2,3,4,5],dtype=float)
>>> a
array([ 1.,  2.,  3.,  4.,  5.])
>>> a.dtype
dtype('float64')

また、生成されたarrayオブジェクトのデータ型はdtypeメソッドを利用することで確認できます。

>>> a.dtype
dtype('int64')
>>> b.dtype
dtype('float64')

pythonのrange関数のように、連続値を生成するarangeという関数もあります。0.0から0.1刻みで10.0までの連続値のarrayオブジェクトを生成してみましょう。

>>> a = np.arange(0.0,10.0,0.1)
>>> a
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9,  1. ,
       1.1,  1.2,  1.3,  1.4,  1.5,  1.6,  1.7,  1.8,  1.9,  2. ,  2.1,
       2.2,  2.3,  2.4,  2.5,  2.6,  2.7,  2.8,  2.9,  3. ,  3.1,  3.2,
       3.3,  3.4,  3.5,  3.6,  3.7,  3.8,  3.9,  4. ,  4.1,  4.2,  4.3,
       4.4,  4.5,  4.6,  4.7,  4.8,  4.9,  5. ,  5.1,  5.2,  5.3,  5.4,
       5.5,  5.6,  5.7,  5.8,  5.9,  6. ,  6.1,  6.2,  6.3,  6.4,  6.5,
       6.6,  6.7,  6.8,  6.9,  7. ,  7.1,  7.2,  7.3,  7.4,  7.5,  7.6,
       7.7,  7.8,  7.9,  8. ,  8.1,  8.2,  8.3,  8.4,  8.5,  8.6,  8.7,
       8.8,  8.9,  9. ,  9.1,  9.2,  9.3,  9.4,  9.5,  9.6,  9.7,  9.8,
       9.9])

生成されたarrayオブジェクトの一部を取得するような場合には、Pythonのlistと同様にスライシングでアクセスすることができます。先程生成したarrayオブジェクトaに対してスライシングでアクセスしてみます。

>>> a[20:40]
array([ 2. ,  2.1,  2.2,  2.3,  2.4,  2.5,  2.6,  2.7,  2.8,  2.9,  3. ,
       3.1,  3.2,  3.3,  3.4,  3.5,  3.6,  3.7,  3.8,  3.9])
>>> a[0:100:5]
array([ 0. ,  0.5,  1. ,  1.5,  2. ,  2.5,  3. ,  3.5,  4. ,  4.5,  5. ,
       5.5,  6. ,  6.5,  7. ,  7.5,  8. ,  8.5,  9. ,  9.5])

他にもarrayオブジェクトにはオブジェクトを多次元化するreshapeメソッドや、多次元arrayを一次元配列化するflattenメソッドやravel関数などもあります。

>>> a = np.arange(16)
>>> a.reshape(4,4)
array([[ 0,  1,  2,  3],
      [ 4,  5,  6,  7],
      [ 8,  9, 10, 11],
      [12, 13, 14, 15]])
>>> np.ravel(a)
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15])

arrayオブジェクトへ数値オブジェクトの演算は、すべての要素に対して行なわれます。また、arrayオブジェクト同士の演算も可能です。arrayオブジェクト同士の演算は各要素同士の演算になることに注意してください。各要素に対してexpやsin等の数学関数を適用する場合にはmathパッケージではなくNumpyパッケージの同名の関数を利用するようにしてください。mathパッケージの関数では、引数にarrayオブジェクトを取ることができないため、エラーとなってしまいますので注意しましょう。

>>> a = np.array([[1,2,3]])
>>> a + 2
array([[3, 4, 5]])
>>> a 2.0
array([[ 2.,  4.,  6.]])
>>> b = np.array([[4,5,6]])
>>> a + b
array([[5, 7, 9]])
>>> a b
array([[ 4, 10, 18]])

統計関連の操作

平均を求めるためにNumpyには、meanとaverageの2つの関数が用意されています。どちらも平均を求める関数ですが、算術平均と加重平均の違いがあります。

普通「平均値」といえば、特にこだわらない限り、算術平均を指します。例では、140cmから190cmの身長を想定して生成した100件の乱数を標本とし、平均を求めています。なお、乱数の生成にはrandint関数を使いました。この関数では生成したいデータの下限と上限、そしてサイズを指定することで範囲に収まるような整数の乱数を生成します。

>>> import numpy as np
>>> height = np.random.randint(140, 190, 100)
>>> height
array([160, 174, 175, 187, 178, 171, 146, 187, 177, 154, 177, 147, 183,
      155, 187, 156, 145, 167, 164, 185, 153, 163, 186, 185, 171, 180,
      163, 164, 178, 161, 158, 163, 146, 176, 178, 142, 175, 171, 155,
      164, 189, 167, 141, 162, 172, 151, 177, 162, 145, 140, 160, 169,
      186, 160, 141, 183, 167, 160, 177, 156, 145, 149, 186, 149, 150,
      154, 156, 167, 173, 189, 177, 176, 167, 177, 176, 186, 181, 164,
      166, 161, 181, 168, 180, 156, 165, 143, 150, 140, 161, 148, 162,
      170, 171, 161, 174, 148, 157, 187, 180, 160])
>>> np.mean(height)
165.83000000000001

算術平均を紹介する時にあわせて紹介されることが多いのが「中央値」「標準偏差」です。中央値とは、その値以下の標本とその値以上の標本がちょうど同数になる分布を2分する値のことです。また、標準偏差とはデータのばらつきをみる尺度の1つです。平均値と標準偏差がわかれば、データがどのような分布であるかがある程度明かになります。Numpyで中央値を求めるにはmedian関数を、標準偏差を求めるにはstd関数を利用します。先程の標本から中央値と標準偏差を求めてみましょう。

>>> np.median(height)
165.5
>>> np.std(height)
13.599305129307155

他にも、総和を求めるsum関数、arrayオブジェクトから最大値、最小値を求めるamax, amin関数などがあります。

>>> np.sum(height)
16583
>>> np.amax(height)
189
>>> np.amin(height)
140

ここでは紹介しきれないくらいにNumpyの機能は豊富です。他にも行列や線形代数の計算などもサポートしています。ここで紹介しきれていない機能や使用例は公式ドキュメントで確認できます。

また、英語での公開しかありませんが、Numpy/ScipyのCookBookも公開されているので、参考にしてみてもいいでしょう。

終わりに

今回は、Numpyの導入と実際の使い方に触れました。次回はこのNumpyを使って実際に分布を扱うコードを書いてみます。

おすすめ記事

記事・ニュース一覧