読者です 読者をやめる 読者になる 読者になる

NumPyの使い方(ndarray編)

python 機械学習

NumPyのndarrayの使い方のメモです。

NumPy

NumPyは数学関数ライブラリです。
インストール方法は下記を参照。
pppurple.hatenablog.com

IPythonで使ってみます。

In [1]: import numpy as np

ndarray

ndarrayはN次元配列のオブジェクトです。
pythonの配列操作は遅いのですが、ndarrayは高速処理できるように最適化されています。

array()関数に配列を渡して生成します。

In [6]: data = [1, 2, 3, 10]

In [7]: arr = np.array(data)

In [8]: arr
Out[8]: array([ 1,  2,  3, 10])

2次元配列を渡すと、2次元のndarrayが生成されます。

In [9]: data2 = [[1, 2, 3], [4, 5, 6]]

In [10]: arr2 = np.array(data2)

In [11]: arr2
Out[11]:
array([[1, 2, 3],
       [4, 5, 6]])

次元数、行数、列数

In [12]: arr2.ndim
Out[12]: 2

In [13]: arr2.shape
Out[13]: (2, 3)

零行列の生成

In [15]: np.zeros(10)
Out[15]: array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])

In [16]: np.zeros((5, 5))
Out[16]:
array([[ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])

In [18]: np.zeros((2, 5, 5))
Out[18]:
array([[[ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.]],

       [[ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.]]])

empty()の場合、要素は不定になります。

In [19]: np.empty(10)
Out[19]: array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])

In [21]: np.empty((5, 5))
Out[21]:
array([[ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])

In [22]: np.empty((2, 5, 5))
Out[22]:
array([[[ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.]],

       [[ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.,  0.]]])

arange()で生成。range()と同様の使い方。

In [24]: np.arange(10)
Out[24]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [26]: np.arange(5, 15)
Out[26]: array([ 5,  6,  7,  8,  9, 10, 11, 12, 13, 14])

In [27]: np.arange(0, 10, 2)
Out[27]: array([0, 2, 4, 6, 8])

dtypeでデータ型を表示。int64に推測される。

In [34]: arr
Out[34]: array([ 1,  2,  3, 10])

In [35]: arr.dtype
Out[35]: dtype('int64')

小数点だとfloatに推測される

In [28]: data3 = [0.1, 0.2, 3, 10]

In [31]: arr3 = np.array(data3)

In [32]: arr3
Out[32]: array([  0.1,   0.2,   3. ,  10. ])

In [33]: arr3.dtype
Out[33]: dtype('float64')

astype()でデータ型をキャスト
int⇒float

In [36]: float_arr = arr.astype(np.float64)

In [37]: float_arr
Out[37]: array([  1.,   2.,   3.,  10.])

In [38]: float_arr.dtype
Out[38]: dtype('float64')

float⇒int

In [40]: arr2 = np.array([1.1, 2,2, -3.3, 10.1])

In [41]: arr2
Out[41]: array([  1.1,   2. ,   2. ,  -3.3,  10.1])

In [42]: arr2.astype(np.int32)
Out[42]: array([ 1,  2,  2, -3, 10], dtype=int32)

str⇒float

In [45]: str = np.array(['1.1', '2.2', '-3.3', '10.1'], dtype=np.string_)

In [46]: str
Out[46]:
array([b'1.1', b'2.2', b'-3.3', b'10.1'],
      dtype='|S4')

In [49]: str.astype(np.float64)
Out[49]: array([  1.1,   2.2,  -3.3,  10.1])

In [50]: str.astype(float)
Out[50]: array([  1.1,   2.2,  -3.3,  10.1])
スカラー演算

四則演算では各要素同士が演算される。

In [51]: arr = np.array([[1, 2, 3], [4, 5, 6]])

In [52]: arr
Out[52]:
array([[1, 2, 3],
       [4, 5, 6]])

In [53]: arr * arr
Out[53]:
array([[ 1,  4,  9],
       [16, 25, 36]])

In [54]: arr - arr
Out[54]:
array([[0, 0, 0],
       [0, 0, 0]])

In [55]: 1 / arr
Out[55]:
array([[ 1.        ,  0.5       ,  0.33333333],
       [ 0.25      ,  0.2       ,  0.16666667]])

In [56]: arr ** 2
Out[56]:
array([[ 1,  4,  9],
       [16, 25, 36]])
ndarrayの要素の操作

ndarrayの要素の操作は、pythonの配列操作とほとんど同じ。

要素の参照

In [57]: arr = np.arange(10)

In [58]: arr
Out[58]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [59]: arr[0]
Out[59]: 0

In [60]: arr[5]
Out[60]: 5

In [61]: arr[4:9]
Out[61]: array([4, 5, 6, 7, 8])

要素の変更

In [62]: arr[4:9] = 100

In [63]: arr
Out[63]: array([  0,   1,   2,   3, 100, 100, 100, 100, 100,   9])

配列スライス

In [64]: arr = np.arange(10)

In [65]: arr_slice = arr[4:9]

In [66]: arr
Out[66]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [67]: arr_slice
Out[67]: array([4, 5, 6, 7, 8])

スライスされた要素はコピーではなく、もとのndarrayを参照している。

In [68]: arr_slice[0] = 1000

In [69]: arr_slice
Out[69]: array([1000,    5,    6,    7,    8])

In [70]: arr
Out[70]: array([   0,    1,    2,    3, 1000,    5,    6,    7,    8,    9])

In [71]: arr_slice[:] = 9999

In [72]: arr_slice
Out[72]: array([9999, 9999, 9999, 9999, 9999])

In [73]: arr
Out[73]: array([   0,    1,    2,    3, 9999, 9999, 9999, 9999, 9999,    9])

多次元配列の要素の参照

In [74]: arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

In [75]: arr2
Out[75]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [76]: arr2[0]
Out[76]: array([1, 2, 3])

In [77]: arr2[1]
Out[77]: array([4, 5, 6])

In [78]: arr2[2][2]
Out[78]: 9

In [79]: arr2[2, 2]
Out[79]: 9

In [80]: arr3 = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])

In [81]: arr3
Out[81]:
array([[[ 1,  2,  3],
        [ 4,  5,  6]],

       [[ 7,  8,  9],
        [10, 11, 12]]])

In [88]: arr3[0, 0]
Out[88]: array([1, 2, 3])

In [89]: arr3[0, 1]
Out[89]: array([4, 5, 6])

In [90]: arr3[0, 1, 0]
Out[90]: 4

In [91]: arr3[0, 1, 2]
Out[91]: 6

多次元配列の要素の更新

In [80]: arr3 = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])

In [81]: arr3
Out[81]:
array([[[ 1,  2,  3],
        [ 4,  5,  6]],

       [[ 7,  8,  9],
        [10, 11, 12]]])

In [82]: arr3[0]
Out[82]:
array([[1, 2, 3],
       [4, 5, 6]])

In [84]: arr3[0] = 100

In [85]: arr3
Out[85]:
array([[[100, 100, 100],
        [100, 100, 100]],

       [[  7,   8,   9],
        [ 10,  11,  12]]])

多次元配列のスライス

In [92]: arr
Out[92]: array([   0,    1,    2,    3, 9999, 9999, 9999, 9999, 9999,    9])

In [93]: arr[1:4]
Out[93]: array([1, 2, 3])

In [95]: arr[4:9]
Out[95]: array([9999, 9999, 9999, 9999, 9999])

In [96]: arr2
Out[96]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [97]: arr2[:2]
Out[97]:
array([[1, 2, 3],
       [4, 5, 6]])

In [98]: arr2[1:]
Out[98]:
array([[4, 5, 6],
       [7, 8, 9]])

In [99]: arr2[:2, 1:]
Out[99]:
array([[2, 3],
       [5, 6]])

In [100]: arr2[:]
Out[100]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [101]: arr2[:, :1]
Out[101]:
array([[1],
       [4],
       [7]])

ブールインデックス参照
配列のインデックスにbool値の配列を与え、配列を参照することが出来る。

In [102]: chars = np.array(['A', 'B', 'C', 'D', 'E', 'F', 'G'])

In [103]: chars
Out[103]:
array(['A', 'B', 'C', 'D', 'E', 'F', 'G'],
      dtype='<U1')

In [104]: data = np.random.randn(7, 4)

In [105]: data
Out[105]:
array([[ 0.70412496, -1.22371325,  1.1306193 , -0.9790867 ],
       [ 0.05970562,  0.02306688,  0.24999045, -0.6384993 ],
       [-1.64262671, -0.27073472,  1.72457652,  0.57444572],
       [ 0.17607953, -0.40248292,  0.01224238, -0.62754326],
       [-1.63882673, -0.90119505,  0.48003654, -0.7851732 ],
       [ 1.41863212, -0.35522151,  0.34824733,  1.2513504 ],
       [-1.71087056,  1.15355688,  0.64256637,  0.20287022]])

下記のbool値の配列(3番目だけtrue)が得られる場合、
dataのインデックスに与えることで、3番目の要素を参照できる。

In [106]: chars == 'C'
Out[106]: array([False, False,  True, False, False, False, False], dtype=bool)

In [107]: data[chars == 'C']
Out[107]: array([[-1.64262671, -0.27073472,  1.72457652,  0.57444572]])

In [108]: data[chars == 'C', 2:]
Out[108]: array([[ 1.72457652,  0.57444572]])

下記のbool値の配列(3番目以外true)が得られる場合、
dataのインデックスに与えることで、3番目以外の要素を参照できる。

In [109]: chars != 'C'
Out[109]: array([ True,  True, False,  True,  True,  True,  True], dtype=bool)

In [110]: data[chars != 'C']
Out[110]:
array([[ 0.70412496, -1.22371325,  1.1306193 , -0.9790867 ],
       [ 0.05970562,  0.02306688,  0.24999045, -0.6384993 ],
       [ 0.17607953, -0.40248292,  0.01224238, -0.62754326],
       [-1.63882673, -0.90119505,  0.48003654, -0.7851732 ],
       [ 1.41863212, -0.35522151,  0.34824733,  1.2513504 ],
       [-1.71087056,  1.15355688,  0.64256637,  0.20287022]])

In [111]: data[~(chars == 'C')]
(data[-(chars == 'C')]はdeprecated)
Out[111]:
array([[ 0.70412496, -1.22371325,  1.1306193 , -0.9790867 ],
       [ 0.05970562,  0.02306688,  0.24999045, -0.6384993 ],
       [ 0.17607953, -0.40248292,  0.01224238, -0.62754326],
       [-1.63882673, -0.90119505,  0.48003654, -0.7851732 ],
       [ 1.41863212, -0.35522151,  0.34824733,  1.2513504 ],
       [-1.71087056,  1.15355688,  0.64256637,  0.20287022]])

bool値の配列であればよいので、下記の様に条件の結合も可能

In [113]: mask = (chars == 'C') | (chars == 'F')

In [114]: mask
Out[114]: array([False, False,  True, False, False,  True, False], dtype=bool)

In [115]: data[mask]
Out[115]:
array([[-1.64262671, -0.27073472,  1.72457652,  0.57444572],
       [ 1.41863212, -0.35522151,  0.34824733,  1.2513504 ]])

bool値の配列であればよいので、下記の様な式でも参照可能

In [116]: data[data < 0] = 0

In [117]: data
Out[117]:
array([[ 0.70412496,  0.        ,  1.1306193 ,  0.        ],
       [ 0.05970562,  0.02306688,  0.24999045,  0.        ],
       [ 0.        ,  0.        ,  1.72457652,  0.57444572],
       [ 0.17607953,  0.        ,  0.01224238,  0.        ],
       [ 0.        ,  0.        ,  0.48003654,  0.        ],
       [ 1.41863212,  0.        ,  0.34824733,  1.2513504 ],
       [ 0.        ,  1.15355688,  0.64256637,  0.20287022]])

代入も可能

In [122]: data[chars == 'D'] = 9

In [123]: data
Out[123]:
array([[ 0.70412496,  0.        ,  1.1306193 ,  0.        ],
       [ 0.05970562,  0.02306688,  0.24999045,  0.        ],
       [ 0.        ,  0.        ,  1.72457652,  0.57444572],
       [ 9.        ,  9.        ,  9.        ,  9.        ],
       [ 0.        ,  0.        ,  0.48003654,  0.        ],
       [ 1.41863212,  0.        ,  0.34824733,  1.2513504 ],
       [ 0.        ,  1.15355688,  0.64256637,  0.20287022]])

ファンシーインデックス参照
配列のインデックスに整数の配列を与え、配列を参照する。

In [124]: arr = np.empty((8, 4))

In [125]: for i in range(8):
   .....:     arr[i] = i
   .....:

In [126]: arr
Out[126]:
array([[ 0.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  1.],
       [ 2.,  2.,  2.,  2.],
       [ 3.,  3.,  3.,  3.],
       [ 4.,  4.,  4.,  4.],
       [ 5.,  5.,  5.,  5.],
       [ 6.,  6.,  6.,  6.],
       [ 7.,  7.,  7.,  7.]])

整数の配列を渡すと、そのインデックスで取得できる。

In [127]: arr[[7, 6, 0, 2]]
Out[127]:
array([[ 7.,  7.,  7.,  7.],
       [ 6.,  6.,  6.,  6.],
       [ 0.,  0.,  0.,  0.],
       [ 2.,  2.,  2.,  2.]])

In [128]: arr[-1]
Out[128]: array([ 7.,  7.,  7.,  7.])

In [129]: arr[[-1, -3]]
Out[129]:
array([[ 7.,  7.,  7.,  7.],
       [ 5.,  5.,  5.,  5.]])

2つのインデックス配列を渡すと、1つ目の配列で1次元を参照し、
2つ目の配列で2次元を参照する。

In [131]: arr2 = np.arange(32).reshape((8,4))

In [132]: arr2
Out[132]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23],
       [24, 25, 26, 27],
       [28, 29, 30, 31]])

In [134]: arr2[[1, 2, 3, 4], [0, 2, 3, 1]]
Out[134]: array([ 4, 10, 15, 17])

行列の転置
転置行列

In [137]: arr = np.arange(12).reshape(3, 4)

In [138]: arr
Out[138]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [139]: arr.T
Out[139]:
array([[ 0,  4,  8],
       [ 1,  5,  9],
       [ 2,  6, 10],
       [ 3,  7, 11]])

行列の内積

In [140]: np.dot(arr.T, arr)
Out[140]:
array([[ 80,  92, 104, 116],
       [ 92, 107, 122, 137],
       [104, 122, 140, 158],
       [116, 137, 158, 179]])

行列の入れ替え
transopse()に入れ替える次元を与え、その順序に入れ替える。

In [141]: arr = np.arange(16).reshape((2, 2, 4))

In [142]: arr
Out[142]:
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])

In [143]: arr.transpose((1, 0, 2))
Out[143]:
array([[[ 0,  1,  2,  3],
        [ 8,  9, 10, 11]],

       [[ 4,  5,  6,  7],
        [12, 13, 14, 15]]])

In [8]: arr.transpose((2, 1, 0))
Out[8]:
array([[[ 0,  8],
        [ 4, 12]],

       [[ 1,  9],
        [ 5, 13]],

       [[ 2, 10],
        [ 6, 14]],

       [[ 3, 11],
        [ 7, 15]]])

swapaxes()で次元を入れ替える。
1次元と2次元を入れ替える例は、transpose((0,2,1))と同じ。

In [144]: arr
Out[144]:
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])

In [145]: arr.swapaxes(1, 2)
Out[145]:
array([[[ 0,  4],
        [ 1,  5],
        [ 2,  6],
        [ 3,  7]],

       [[ 8, 12],
        [ 9, 13],
        [10, 14],
        [11, 15]]])

In [23]: arr.transpose((0, 2, 1))
Out[23]:
array([[[ 0,  4],
        [ 1,  5],
        [ 2,  6],
        [ 3,  7]],

       [[ 8, 12],
        [ 9, 13],
        [10, 14],
        [11, 15]]])

終わり。


【参考】
Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理