機械学習 はじめよう

第6回 Numpyの導入

この記事を読むのに必要な時間:およそ 4.5 分

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を使って実際に分布を扱うコードを書いてみます。

著者プロフィール

恩田伊織(おんだいおり)

1979年生まれの埼玉県出身。数学と関数型言語,SFとボードゲーム好きなプログラマー。好きな言語はRubyとLISP。現在は航空管制の基盤開発に従事している。

Twitter:http://twitter.com/Iori_o