pythonメニュー

Python numpyモジュール

ディープラーニングの実装で、配列や行列の計算を多く使いますが、 NumPy(ナムパイ)の配列クラスに、これらの操作を容易にする機能が提供されています。

NumPy(ナムパイ)の基本的な使い方

>>> import numpy
>>> x=numpy.array([1,2,3]) # [1,2,3]の配列の引数で、NumPyオブジェクトを生成する。 
>>> print(x)
[1 2 3]
>>> x
array([1, 2, 3])
>>> x.size # 要素数取得 x.shape[0] や len(x) でも同じ結果が得られる
3
>>> type(x)
<class 'numpy.ndarray'>
>>> x.dtype # z内の内部配列の要素の型を、dtypeで確認しています。
dtype('int32')
>>> y=numpy.array([4,5,6])
>>> x+y     # NumPyオブジェクトの加算で、要素毎に加算した新しいNumPyオブジェクトを生成
array([5, 7, 9], dtype=int32)
>>> z=x+y
>>> z
array([5, 7, 9], dtype=int32)
>>> print(z)
[5, 7, 9]
>>> x.tolist() # NumPyから配列を得る
[1, 2, 3]
>>>
次の先頭行のimport numpy as np の記述で「numpyをnpとして読み込み、NumPyに関するメソッドをnpを参照して使えるようにする」記述です。
以後、このページのソースコードはimport numpy as npがされているという前提のコードです。
import numpy as np
def test():
   x=np.array([ 1, 2, 3])
   y=np.array([ 4, 5, 6])
   print(x+y)	# 表示結果:[5 7 9]
   print(x*y)	# 表示結果:[ 4 10 18]
   print(y-x)	# 表示結果:[3 3 3]
   print(y/x)	# 表示結果:[ 4.   2.5  2. ]
   print(x*2)	# 表示結果:[2 4 6]		これはブロードキャスト演算と呼ぶ

test()
NumPyを使うと、一括した比較や抽出配列の合計も容易に可能です。
>>> x=np.array([ 1, 3, 5])
>>> y=np.array([ 6, 4, 2])
>>> z=np.r_[x, y]   # xとyの'numpy.ndarray'を連結
>>> z
array([1, 3, 5, 6, 4, 2])
>>> np.argmax(z) #最も大きな要素の添え字を取得
3
>>> z > 2  #一括した比較
array([False,  True,  True,  True,  True, False], dtype=bool)
>>> z[ z > 2 ]
array([3, 5, 6, 4])
>>>
>>> np.sum(x) # 配列の合計
9
>>> np.sum(x + y) # 1+6 + 3+4 + 5+2
21
>>> np.sum(x * y) # 1*6 + 3*4 + 5*2
28
>>>
>>> z
array([1, 3, 5, 6, 4, 2])
>>> w= z < 4 # 比較結果の配列を生成
>>> w
array([ True,  True, False, False, False,  True], dtype=bool)
>>> w.astype(np.int) # astypeの引数で指定した型のNumPy配列を生成 (配列要素全体の型変換に使われる。)
array([1, 1, 0, 0, 0, 1])
>>>

NumPy(ナムパイ)とリストの違い

リストにおいて、appendメソッドを使って配列を追加できます
a=[]
a.append([1,2,3])
a.append([4,5])
print(a)		# [[1, 2, 3], [4, 5]]
ですが、Numpyオブジェクトにはappend命令がありません。
Numpyクラスのappendはありますが、これは連結オブジェクトの生成機能です。
import numpy as np
a=np.array([]) # 空で型指定をしないと、'numpy.float64'型になる。
a=np.append(a, [1,2,3])
a=np.append(a, [4,5])
print(a)		# [1. 2. 3. 4. 4.] このすべての要素が'numpy.float64'型になる。
(リスト要素は、異なる型が記憶できますが、全てがnumpyは同じ型で、「a=np.array([], np.int)」で作ればすべてintです。)

上記リスト操作と同じように、配列の追加を行う場合、次のようにnp.emptyで次元を指定して初期化しておく必要があります。(下記のどちらでもOK)
import numpy as np
a=np.empty((0,3), int)# 3つ要素の配列を要素とした2次配列
a=np.append(a, [[1, 2, 3]], axis=0)
a=np.append(a, [[4, 5, 0]], axis=0)
print(a)		# [[1 2 3] [4 5 0]]
import numpy as np
a=np.empty((0,3), int)# 3つ要素の配列を要素とした2次配列
a=np.append(a, np.array([[1, 2, 3]]), axis=0)
a=np.append(a, np.array([[4, 5, 0]]), axis=0)
print(a)		# [[1 2 3] [4 5 0]]
numpyの配列の要素は同じでなければならないので、「a=np.append(a, [[4, 5]], axis=0)」や「a=np.append(a, np.array([[4, 5]]), axis=0)」のような操作はエラーです。
なお、 axis=0を指定しないと一次元に平坦化されて連結されるので一次配列になってしまう。
つまり、次元を保ったまま配列を追加するには引数axisを指定しなければならない。
axis=0で新たな行として追加(縦に連結)、axis=1で新たな列として追加(横に連結)される。 存在しない次元(軸)を指定するとエラー。



多次元Numpy生成の注意

1次元の配列追加の例を示します。
import numpy as np
a = np.array([],int)
a = np.append(a, [1,2])
a = np.append(a, [3,4])
a = np.append(a, [5,6])
print( a.shape, a) # 出力:(6,) [1 2 3 4 5 6]
さて、左下の生成方法は上記と同じ結果で、2次元のNumpyになりません。(右下と同等にはなりません。)
import numpy as np
a = np.array([],int)
a = np.append(a, np.array([1,2]))
a = np.append(a, np.array([3,4]))
a = np.append(a, np.array([5,6]))
print( a.shape, a) # 出力:(6,) [1 2 3 4 5 6]
import numpy as np
a = np.array([ [1,2],[3,4] ,[5,6] ])
print( a.shape, a)
# 出力:(3, 2) [[1 2]
 [3 4]
 [5 6]]

右上のような、(3, 2)の配列を作る場合、次のようにするとできます。(左右は同じ結果になりました。)
a=np.empty( (0,2) , int)
print( a.shape, a) # 出力:(0, 2) []
a = np.append(a, np.array([[1,2]]) ,axis=0)
a = np.append(a, np.array([[3,4]]) ,axis=0)
a = np.append(a, np.array([[5,6]]) ,axis=0)
print( a.shape, a, type(a[0]) 
# 出力:(3, 2) [[1 2]
 [3 4]
 [5 6]] 
a=np.empty( (0,2) , int)
print( a.shape, a) # 出力:(0, 2) []
a = np.append(a, [[1,2]] ,axis=0)
a = np.append(a, [[3,4],[5,6]] ,axis=0)
    # 上のように2つ追加することも可能です。
print( a.shape, a, type(a[0]) )
# 出力:(3, 2) [[1 2]
 [3 4]
 [5 6]] 
右の記述の方が簡単ですね。
なお注意として、初期で(0,2)の指定が必要なこと、この場合2個の要素の配列の配列を、axis=0でappendしなければなりません。
このような構造のNumpy配列を動的に生成したい場合、個人的には次のように、
1次元で生成して、使う時にreshapeで形状を変更する手法が簡単と感じました。
import numpy as np
a = np.array([],int)
a = np.append(a, [1,2])
a = np.append(a, [3,4])
a = np.append(a, [5,6])
print( a.shape, a) # 出力:(6,) [1 2 3 4 5 6]
a=a.reshape(2,3)
print( a.shape, a) # 出力:(2, 3) [[1 2 3] [4 5 6]]
a=a.reshape(3,2)
print( a.shape, a) # 出力:(3, 2) [[1 2] [3 4] [5 6]]



NumPy(ナムパイ)のN次配列

1次元配列
def test():
   A=np.array([ 1, 2, 3])
   print(A)					# 表示結果:[1 2 3] 
   print( "np配列要素型:",  A.dtype  )  		# 表示結果:np配列要素型: int32  
   print( "np配列の次元数:",np.ndim(A)  ) 	# np配列の次元数: 1 
   print( "np配列の形状:",  np.shape(A)  ) 	# 表示結果:np配列の形状: (3,)  
   print( "np配列の形状:",  A.shape  ) 		# 表示結果:np配列の形状: (3,)  
   print( "np配列の形状:",  A.shape[0]  )  	# 表示結果:np配列の形状: 3 len関数を使って「len(A)」も同じ結果です。

test()
b=np.array([ 1, 2, 3, 4, , 1.5])
上記の006行は7行のA.shapeと同じで、3つ要素である結果を得ています。(3つで構成する形状です。)
この形状の結果は「(3,)」で、これは一次配列でも多次元配列と同じ統一的な表現で、数だけを使う場合に「 A.shape[0]」を利用できます。 次の2次元の表示と、比較してください。

2次元配列
def test():
   A=np.array( [ [1,2], [3,4], [5,6] ] ) # 2次配列で、Numpyを生成すると、個々の内部要素もNumpy配列になります。( type(A)もtype(A[0])も'<class 'numpy.ndarray'>')
   print(A)					# 表示結果:[1 2 3] 
   print( "np配列要素型:",  A.dtype  )  		# 表示結果:np配列要素型: int32  
   print( "np配列の次元数:",np.ndim(A)  ) 	# np配列の次元数: 2 
   print( "np配列の形状:",  np.shape(A)  ) 	# 表示結果:np配列の形状: (3, 2)  
   print( "np配列の形状:",  A.shape  ) 		# 表示結果:np配列の形状: (3, 2)  
   print( "np配列の形状:",  A.shape[0]  )  	# 表示結果:np配列の形状: 3 len関数を使っても同じ結果が得られます
   print( "通常配列変換:",  A.tolist()  )  	# 表示結果:通常配列変換: [[1, 2], [3, 4], [5, 6]]
   print( "1次np配列へ変換:",  A.flatten()  )  	# 表示結果:1次np配列へ変換: [1 2 3 4 5 6]

test()
上記1次元配列と2次元配列を比較しましょう。
008行で 通常配列(listクラス)に変換する例、009行で 2次元を1次元のNumPy配列に変換する例を示しています。

初期生成、部分削除、連結、配列形状の変換の例
import numpy as np
a = np.arange(12) # 12個の要素の1次元配列を生成。
a # 出力結果: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
a=np.delete(a, [0,1,2]) # 第2引数の添え字が示す要素を削除する(listでなくて 1つのint指定も可)。
#  この例と同にように削除が連続要素であれば、range(0,3)でも可能
a # 出力結果: array([ 3,  4,  5,  6,  7,  8,  9, 10, 11])

np.delete(a, range(0,3)) # (aは変更していない)出力結果: array([ 6,  7,  8,  9, 10, 11])
a # 出力結果: array([ 3,  4,  5,  6,  7,  8,  9, 10, 11])
a=np.append(a, [12,13]) # リストを連結
a # 出力結果: array([ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13])
a=np.insert(a, 0, [0,1,2]) # 第2引数が0で先頭が挿入位置になる挿入。(listでなくて 1つの挿入したいデータ要素指定も可能)。
a # 出力結果: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13])
a=np.delete(a, range(len(a)-2, len(a))) #numpy配列の最後2つを削除する例
a array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

b = np.reshape(a, (3, 4)) # 3×4の2次元配列に変形
b # 出力結果: array([[ 0,  1,  2,  3], [ 4,  5,  6,  7],[ 8,  9, 10, 11]])

c=b.tolist()  # npでなく通常の配列(list)へ変換 
c # 出力結果: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]

d=b.flatten() # 1次配列へ変換 
d # 出力結果: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

e = np.random.choice(100,10) # 乱数を 0から100未満で10個生成
e # 出力結果例: array([86, 46, 95, 99, 25, 97, 17, 53, 83, 60])

f = np.arange(5, 10.1, 0.5) # 5から10までの0.5刻みnumpy配列生成
f # 出力結果例: array([  5. ,   5.5,   6. ,   6.5,   7. ,   7.5,   8. ,   8.5,   9. ,  9.5,  10. ])
f.tolist() # list「つまり配列」を取得 出力結果例: [5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0]
なお、int型で、空のnumpyを生成する表現は、次の通りです。→ np.array([], int)
また、指定の要素数をゼロで初期化する場合は次の通りです。→ np.zeros(10)

numpy 乱数初期化の実験

numpyには、一様分布の乱数生成(0.0以上、1.0未満のnumpy.random.rand()、任意の範囲の整数のnumpy.random.randint()、
正規分布の乱数生成用で、任意の平均、標準偏差で生成するnumpy.random.normal()、
二項分布の乱数生成用のnumpy.random.binomial()、
ベータ分布の乱数生成用のnumpy.random.beta()
ガンマ分布の乱数生成用のnumpy.random.gamma()、
カイ二乗分布の乱数用のnumpy.random.chisquare() などと、たくさん用意されています。
これらを使用する作品の運用前で、毎回で時間のパラメタによる乱数が生成されると、作品を検証がむずかしいことがあります。
そのような場合、時間のパラメタによらないように検証の場合だけ乱数生成の種を定数で指定すると便利です。
乱数の種(シード)を指定するメソッドがseedです。以下ではその挙動の実験を行うコードです。
これによる乱数の生成パターンが同じになることが確認できます。
import numpy as np
np.random.seed(123) # 乱数の生成に使う種(シード)を設定
print( np. random .randint( 10, size=5)) # 出力結果:[2 2 6 1 3]
print( np. random .randint( 10, size=5)) # 出力結果:[9 6 1 0 1]
print( np. random .randint( 10, size=5)) # 出力結果:[9 0 0 9 3]
np.random.seed(123) # 乱数の生成に使う種(シード)を設定
print( np. random .randint( 10, size=5)) # 出力結果:[2 2 6 1 3]
print( np. random .randint( 10, size=5)) # 出力結果:[9 6 1 0 1]
print( np. random .randint( 10, size=5)) # 出力結果:[9 0 0 9 3]
種(シード)の値が同じであれば、それから続く乱数の生成パターンで、同じ出力結果が得られるはずです。

NumPy(ナムパイ)の次元操作 (axisとndim)

以下で、numpyのn次配列の要素が、numpyになっていることを検証しています。
この時、配列の次元数(int)を ndim のメンバで確認しています。
(また shape の形状メンバ「tuple:タプル型」で確認しています。)
a = np.array([1,2])
a  # 出力: array([1, 2])
b = np.array([3,4])
b  # 出力: array([3, 4])
ab = np.array([ a, b ]) #  aとbを要素にするnumpy
ab # 出力: array([[1, 2],       [3, 4]])
a[0] # 出力: array([1, 2])

ab = np.array([ [1,2], [2,3] ]) # np.array([ a, b ])と同じ内容の配列であることを検証
ab # 出力: array([[1, 2],       [3, 4]])
a[0] # 出力: array([1, 2])

ab.ndim # 次元の確認 2
ab.shape # 形の確認 (2, 2)
ab[0].ndim # 次元の確認 1
ab[0].shape  # 形の確認 (2,)

a.ndim # 次元の確認 1
a[0].ndim # なお、0次元配列であるがエラーにはならない。出力: 0

z = np.array([ab,ab,ab,ab])  #3次元配列
z # 出力: array([[[1, 2],  [2, 3]],    [[1, 2],  [2, 3]],    [[1, 2],  [2, 3]],    [[1, 2],  [2, 3]]])
z.ndim # 次元の確認 3
z.shape # 形の確認 (4, 2, 2)
さて, numpyのsum関数で、合計が次のように得られます。
a = np.array([ [[1,2], [4,5], [6,7]],  [[10,20], [40,50], [60,70]] ]) 
np.sum(a) # 出力:  275   で、全体の合計
では、配列ごとの合計はどのようにすればよいのでしょうか? このような時に引数で軸(axis)を指定します。
axisで指定する数値は、最も外側の次元を0 として内側にいくほど数値を増やす数の指定法で、対象範囲を指定する表現と言えます。(分りにくい!?)
a = np.array([ [[1,2], [4,5], [6,7]],  [[10,20], [40,50], [60,70]] ]) 
a.shape # 出力: (2, 3, 2)
np.sum(a, axis=0) # 出力:  array(array([[11, 22],       [44, 55],       [66, 77]]))  先頭は、1+10、次の値は、2+20
np.sum(a, axis=1) # 出力:  array([[ 11,  14],       [110, 140]])  先頭は、1+4+6、次の値は、2+5+7
np.sum(a, axis=2) # 出力:  array([[  3,   9,  13],       [ 30,  90, 130]])  先頭は、1+2、次の値は、4+5 
もう一つの例を示します。
a = np.array([ [1,2,4,5,6,7],  [10,20,40,50,60,70] ]) 
a.shape # 出力: (2, 6)
np.sum(a) # 出力:  275   で、全体の合計
np.sum(a, axis=0) # 出力:  array([11, 22, 44, 55, 66, 77])  先頭は、1+10、次の値は、2+20
np.sum(a, axis=1) # 出力:  array([ 25, 250])  先頭は、1+2+3+4+5+6+7、次の値は、10+20+30+40+50+60+7;0
np.sum(a, axis=2) # 出力:  ValueError: 'axis' entry is out of bounds  のエラーです2次元なので
NumPyの関数で引数にaxis を指定できるものが次のようにたくさんあります。
算術平均のmean、最頻値のmedian、標準偏差のstd、分散のvar、最大値のmax、最小値minなどがあります。


NumPy(ナムパイ)の添え字操作

要素を探して、その添え字を取得するwhere メソッド

bool配列によるインデックスの取り出し機能が基本です。
import numpy as np
a=np.where( [ True, False, False, True] )
print(type(a), a ) # 表示: (array([0, 3], dtype=int64),)

以下は、上記を利用した表現で、 [0, 1, 2, 3 ]内で3で割った余りが0の添え字を求めている。
a=np.where( np.array([ 0, 1, 2, 3 ])  % 3 == 0)
print(type(a), a ) # 表示: (array([0, 3], dtype=int64),)

最大要素がある添え字のargmax、最小要素がある添え字のargminなどがあります。
同様に並び替えた時の添え字を返すargsort()もあります。 条件を満たす要素のインデックスを取得に、np.whereを使います。(検索にも使えます。)
a = np.array([1, 2, 5, 4, 3, 6])
np.where( a >= 5) # 条件を満たす要素の取得 表示:(array([2, 5], dtype=int64),)
idxs=np.where( a >= 5 )[0] # 条件を満たす要素のインデックスを取得
print(idxs)  # [2 5] の表示 
if len(idxs) > 0: 
   a2 = a[idxs[0]:] # a >= 5の条件で見つかった所から最後までのリスト取得

print(a2) # [5 4 3 6]
条件で要素を指定する。
import numpy as np
a=np.array([1,2,5,2,-1,-2,-1,0,3])
print( a )      # 結果:[ 1  2  5  2 -1 -2 -1  0  3]
print( a[a>0] ) # 結果:[1 2 5 2 3]
a[a<0]=0 # 条件要素の変更
print( a )      # 結果:[1 2 5 2 0 0 0 0 3]

NumPy(ナムパイ)のスライス→コロンによる範囲指定

[a:b:c] というような表記で範囲を指定して参照することができる。
[] の中をコロンで区切って、開始インデックス:終了インデックス:ステップ数を書く。
終了インデックスの直前までを意味する。 なお、省略するとすべてを意味する。 
(開始なら0を意味し、終了なら最後の要素までを意味し、ステップ数を省略すると1が使われる) 
この、範囲指定する例を示します。 
Pythonのリストのスライスと同じような範囲指定ができますが、全く違うものです。
Pythonのリストのスライスは、新しいリストを生成しますが、NumPy(ナムパイ)では参照(View)を返します。
また、代入の挙動は違うことに、注意しましょう。
Pythonのリストのスライス代入は、対象要素を、代入リストに置き換える能力で、それによりスライス範囲要素の削除や、リストの挿入操作が可能でした。 (代入はリストのみでスカラーを代入できなかった)
対して、numpy配列は、配列の要素数が変わるような代入はできません。ですが、スカラーも代入可能でスライス範囲要素を代入値にすべて変更できます。
なお配列で代入する場合は、その各要素でスライスの指定範囲の要素を置き換えます。
よって配列要素数とでスライスの指定の要素数が、完全に一致しないと、エラーになります。
a = np.arange(0, 10.1, 2)
a # 出力:  array([  0.,   2.,   4.,   6.,   8.,  10.]) 

a[1:4]=9 # a[1] から a[3] までを9に設定 (Pythonのリストではできない操作。)
a # 出力:  array([  0.,   9.,   9.,   9.,   8.,  10.]) 

a[:4]=2 # 先頭 から a[3] までを2に設定
a # 出力:  array([  2.,   2.,   2.,   2.,   8.,  10.]) 

a[4:]=1 # a[4] から 最後までを1に設定
a # 出力:  array([  2.,   2.,   2.,   2.,   1.,  1.]) 

a[:]=9 # 全てを9に設定
a # 出力:  array([ 9.,  9.,  9.,  9.,  9.,  9.]) 

a=np.arange(0,11,2.5) # rangeは整数のみですが、numpyのarangeは浮動小数点も可能
a # 出力:array([ 0. ,  2.5,  5. ,  7.5, 10. ])

a[1:4] = [9.1, 9.2, 9.3 ] # スライス範囲の置き換え
a # array([ 0. ,  9.1,  9.2,  9.3, 10. ])

a[1:4] = [9.1, 9.2 ] # スライス範囲の置き換え(置き換え要素数が一致しないエラー)
Traceback (most recent call last):
  File "", line 1, in 
ValueError: cannot copy sequence with size 2 to array axis with dimension 3

a = np.arange(1,11)
a # 出力:array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])
b=np.zeros(8,np.float16 )# 0で8個を初期化(ゼロ埋め)
b :# array([0., 0., 0., 0., 0., 0., 0., 0.], dtype=float16)
a[1:9] = b # bのnumpy配列で、部分的な置き換え(int 要素に float を代入しているが可能)
a # 出力:array([ 1,  0,  0,  0,  0,  0,  0,  0,  0, 10])
なお最後の添え字でマイナスを指定すると、後ろの要素からその数の要素を除い配列を表現する。
>>> a=np.array([1,2,3,4,5,6,7])
>>> a
array([1, 2, 3, 4, 5, 6, 7])
>>> a[:-1]
array([1, 2, 3, 4, 5, 6])
>>> a[:-2]
array([1, 2, 3, 4, 5])
>>> a[::-1]
array([7, 6, 5, 4, 3, 2, 1])
>>>

スライスにおいて次元の区切りに「コンマ , 」を使います。
これにより、各次元ごとにコロンで区切った開始インデックスと終了インデックスを書ける。 以下でその例を示す。
>>> xy= np.array([ [0,1],[2,3],[4,5],[6,7],[8,9] ]) # (5, 2) のshapeで生成
>>> xy
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])
>>> xy[0:5, 0:2]  # 上記xyのすべてを表示させた。 
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])
>>> xy[1:-1,] # 1から「後方より1」の範囲で抽出 なおこの例は「 xy[1:-1,0:2] 」と同じで「0:2」を省略した表記
array([[2, 3],
       [4, 5],
       [6, 7]])
>>> xy[1:-1, 0:1]  # 1から「後方より1」の範囲で抽出 
array([[2],
       [4],
       [6]])
>>> xy[1:-1, 1:] # 1から「後方より1」の範囲で抽出 
array([[3],
       [5],
       [7]])
>>> xy[:, 0] # コンマの後がスライス指定でないので、1次元での抽出になる。
array([0, 2, 4, 6, 8]) 
>>> xy[:, 1] # コンマの後がスライス指定でないので、1次元での抽出になる。
array([1, 3, 5, 7, 9]) 
>>>
>>> xy[0:3, 0:2]  
array([[0, 1],
       [2, 3],
       [4, 5]])
>>> xy[0:3, 0:2] = [[91,92],[93,94],[95,96]] # フライス範囲の変更例
>>> xy
array([[91, 92],
       [93, 94],
       [95, 96],
       [ 6,  7],
       [ 8,  9]])
>>>
次に表のイメージから、指定列を抽出する例で示す。
t = np.array( [ [1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15], ] )
t # 全てを表示
#array([[ 1,  2,  3,  4,  5],
#       [ 6,  7,  8,  9, 10],
#       [ 11,  12,  13,  14,  15]])の表示
t[:, :-2] # 先頭列から、後方より2列までを抽出
#array([[1, 2, 3],
#       [6, 7, 8],
#       [11, 12, 13]])の表示
t[:, -2:] # 後方より2列より最後の列までを抽出
#array([[ 4,  5],
#       [ 9, 10],
#       [ 14,  15]])の表示
t[:, -2] # 後方より2列だけを一次元で抽出
#array([ 4,  9, 14])の表示
t[:, -1] # 最終列だけを一次元で抽出
#array([ 5, 10, 15])の表示
>>>

下記は、(3,10)の2次元配列から0〜4列部分を抽出して(3,4)の配列を得ている例です。
a=np.arange(1,3*10+1)
a=a.reshape(3,10)
print(a)
'''
[[ 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]]
'''

a = a[:, :4]
print(a)
'''
[[ 1  2  3  4]
 [11 12 13 14]
 [21 22 23 24]]
'''

3次元配列での例です。
a = np.arange(3*2*4)
a = a.reshape(3,2,4)
print(a)
'''
[[[ 0  1  2  3]
  [ 4  5  6  7]]

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

 [[16 17 18 19]
  [20 21 22 23]]]
'''
print(a[:,-1])
'''
[[ 4  5  6  7]
 [12 13 14 15]
 [20 21 22 23]]
'''

ブールインデックス参照、ファンシーインデックス参照

論理値(True/False)のndarrayを使った配列で、Trueの要素に対応する集合を生成きます。
これは、「ブールインデックス参照」と呼ばれ、以下に例を示します。
a=np.arange(1,9)
print( a )  # [1 2 3 4 5 6 7 8]
b=np.array([True,False,True,True,False,True,False,False])
print( b )
c=a [ b ] # aの要素で、Trueに対応する要素を取り出す。
print( c ) # [1 3 4 6] 
print( a % 3 == 0 )
print( a [ a % 3 == 0 ] ) # aの要素で、3の倍数の要素を取り出す
#  [3 6] 

添え字の配列で、その配列の各要素が指し示す要素を生成できます。
これは「ファンシーインデックス参照」と呼ばれ、以下に例を示します。
a=np.arange(1,9)
print( a ) # [1 2 3 4 5 6 7 8]
a2= a[ [ 7,6,0 ] ] # 添え字で、7と6と0の添え字が示す要素を取り出す。 
# 上記は、a2=a[ np.array([ 7, 6, 0 ]) ] と、添え字配列にndarrayを使うこともできます。
print(a2) # [8 7 1] a[7], a[6], a[0] が表示

2次元配列での例
a=np.arange(0,10*4)
a=a.reshape(4,10)
print(a)
'''
[[ 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 32 33 34 35 36 37 38 39]]'''
a2=a[:,[ 7, 6, 0 ] ]  
# 上記は、a2=a[:,np.array([ 7, 6, 0 ]) ] と、添え字配列にndarrayを使うこともできます。
print(a2)
'''
[[ 7  6  0]
 [17 16 10]
 [27 26 20]
 [37 36 30]]'''

NumPy(ナムパイ)の積と要素アクセス

A=np.array( [ [1,2], [3,4], [5,6] ] )
 
B=np.array( [ 10, 20, 30 ] )
A * B
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (3,2) (3,)
B=np.array( [ 10, 20 ] )
 この要素数2が、上記のように合わないとエラーです。 
A * B
array([[ 10,  40],
       [ 30,  80],
       [ 50, 120]])
for row in A:
   print(row)

[1 2]
[3 4]
[5 6]
for row in A:
   for e in row:
      print(e, " " , end="")

1  2  3  4  5  6  
for x in range(0, A.shape[0], 1):
   for y in range(0, A[x].shape[0], 1):
      print( A[x][y], " " , end="")
1  2  3  4  5  6  

NumPy(ナムパイ)を使った行列演算

2と、2×2の行列の積は次のようにできます。
の積は、
dot関数(ドット積)で算出でき、
となります。
>>> A=np.array([ [1, 2], [3, 4] ])
>>> A.shape
(2, 2)
>>> B=np.array([ [5, 6], [7, 8] ])
>>> B.shape
( 2, 2)
>>> np.dot(A,B)    #ドット積
array([[19, 22],
       [43, 50]])
>>>

2の列数と 2 の行数が一致しなければなりません。
次の 3の列数と 2 の行数が合わないので実行エラーが起きます。
の積はdot関数(ドット積)で算出できません。

>>> A=np.array([ [1, 2, 3], [4, 5, 6] ])
>>> A.shape
(2, 3)
>>> B=np.array([ [1, 2], [3, 4] ])
>>> B.shape
(2, 2)
>>> np.dot(A,B)    #ドット積
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: shapes (2,3) and (2,2) not aligned: 3 (dim 1) != 2 (dim 0)
>>>

上記は、2×3の行列と、、2×2の行列の積はできないのでエラーが生じています。
いまさらですが、2×3の行列とは、「2行」で、各行は「3列」で構成されるということです。


2×3と、3×2の行列の積は次のようにできます。 そして、結果は2×2のサイズになります。
の積は、
dot関数(ドット積)で算出でき、
となります。
>>> A=np.array([ [1, 2, 3], [4, 5, 6] ])
>>> A.shape
(2, 3)
>>> B=np.array([ [1, 2], [3, 4], [5, 6] ])
>>> B.shape
(3, 2)
>>> np.dot(A,B)    #ドット積
array([[22, 28],
       [49, 64]])
>>>


3×2と、2×4の行列の積の例です。 結果は3×4のサイズになります。
の積は、
dot関数(ドット積)で算出でき、
となります。
>>> A=np.array([ [1, 2], [3, 4], [5, 6] ])
>>> A.shape
(3, 2)
>>> B=np.array([ [1, 2, 3, 4], [5, 6, 7, 8]])
>>> B.shape
(2, 4)
>>> np.dot(A,B)    #ドット積
array([[11, 14, 17, 20],
       [23, 30, 37, 44],
       [35, 46, 57, 68]])
>>>


3×2と、2×1の行列の積は次のようにできます。 そして、結果は3×1のサイズになります。
の積は、
dot関数(ドット積)で算出でき、
となります。
>>> A=np.array([ [1, 2], [3, 4], [5, 6] ])
>>> A.shape
(3, 2)
>>> B=np.array([ [1], [2] ])
>>> B.shape
(2, 1)
>>> np.dot(A,B)    #ドット積
array([[ 5],
       [11],
       [17]])
>>>

なお通常の行列演算ではありませんが、
Numpyを使った場合、 3×2と、2の要素数の1次配列の積でも、似た結果が可能です。 この結果は3の1次配列になります。
>>> A=np.array([ [1, 2], [3, 4], [5, 6] ])
>>> A.shape
(3, 2)
>>> B=np.array([ 1, 2 ])
>>> B.shape
(2,)
>>> np.dot(A,B)    #ドット積
array([ 5, 11, 17])
>>>


2の要素数の1次配列と、2×3との積も計算が可能です。 この結果は違いますが、3つの要素がある1次配列になります。
>>> import numpy as np
>>> A=np.array([ 1, 2 ])
>>> A.shape
(2,)
>>> B=np.array( [ [ 1, 2, 3 ], [4, 5 , 6] ] )
>>> B.shape
(2, 3)
>>> np.dot(A, B) #ドット積
array([ 9, 12, 15])
>>>


NumPy(ナムパイ)のイテレータを使った繰り返し

一重ループの操作で、2次リストの全て要素の繰り返しを可能にするnumpy.ndarray用イテレータ(numpy.nditer型)の例です。
idxがタプルになっていることに注目してください。
import numpy as np
a=np.arange(2*3).reshape(2,3)
print(a)
'''
[[0 1 2]
 [3 4 5]]
'''
it=np.nditer(a,flags=['multi_index'])
while not it.finished:
    idx = it.multi_index
    print(idx, a[idx])
    it.iternext()

'''
(0, 0) 0
True
(0, 1) 1
True
(0, 2) 2
True
(1, 0) 3
True
(1, 1) 4
True
(1, 2) 5
False
'''
nditer()の指定ではflags=以外に op_flags=['readwrite']や op_flags=['readonly']があるるようです。
import numpy as np
a=np.arange(2*3*2).reshape(2,3,2)
print(a)
'''
[[[ 0  1]
  [ 2  3]
  [ 4  5]]

 [[ 6  7]
  [ 8  9]
  [10 11]]]
'''
it=np.nditer(a,flags=['multi_index'])
while it.iternext(): # ここで、イテレータを進ませてしまう。
    idx = it.multi_index
    print(idx, a[idx])

'''この構造のループでは先頭要素にアクセスできないことに注意
(0, 0, 1) 1
(0, 1, 0) 2
(0, 1, 1) 3
(0, 2, 0) 4
(0, 2, 1) 5
(1, 0, 0) 6
(1, 0, 1) 7
(1, 1, 0) 8
(1, 1, 1) 9
(1, 2, 0) 10
(1, 2, 1) 11
'''
for

格子点の作成

格子点 を生成するnp.meshgrid関数で、2点格子の例です。これを使うと、格子点の計算が容易になります。

x=np.arange(5)
y=np.arange(10,40,10)
print(x,y)  # [0 1 2 3 4] [10 20 30]
xx,yy=np.meshgrid(x, y)
print(xx)
'''
[[0 1 2 3 4]
 [0 1 2 3 4]
 [0 1 2 3 4]]'''
print(yy)
'''
[[10 10 10 10 10]
 [20 20 20 20 20]
 [30 30 30 30 30]]'''
nn=xx.shape[0]
for ix in range(nn):
    for iy in range(nn):
        print(xx[ix][iy],yy[ix][iy])
'''
0 10
1 10
2 10
0 20
1 20
2 20
0 30
1 30
2 30
'''

NumPy(ナムパイ)型変換

numpyの要素は、全て同じ型(dtypeで指定)です。そしてnumpy要素で使われる型はPython既存の型と異なり、 次のような種類があります。

データ型 dtype型コード 説明 Python既存型
int8 i1 符号あり8ビット整数型 x
int16 i2 符号あり16ビット整数型 x
int32 i4 符号あり32ビット整数型 int
int64 i8 符号あり64ビット整数型 x
uint8 u1 符号なし8ビット整数型 x
uint16 u2 符号なし16ビット整数型 x
uint32 u4 符号なし32ビット整数型 x
uint64 u8 符号なし64ビット整数型 uint
float16 f2 半精度浮動小数点型(符号部1ビット、指数部5ビット、仮数部10ビット) x
float32 f4 単精度浮動小数点型(符号部1ビット、指数部8ビット、仮数部23ビット) x
float64 f8 倍精度浮動小数点型(符号部1ビット、指数部11ビット、仮数部52ビット) float
float128 f16 四倍精度浮動小数点型(符号部1ビット、指数部15ビット、仮数部112ビット) x
complex64 c8 複素数(実部・虚部がそれぞれfloat32) x
complex128 c16 複素数(実部・虚部がそれぞれfloat64) x
complex256 c32 複素数(実部・虚部がそれぞれfloat128) x
bool ? ブール型(True or False) x
unicode U Unicode文字列 str
object O Pythonオブジェクト型 x
上記の型コードで示す末尾の数字は、その型で使うbyte数を意味します。

例えば、np.array([1,2,3]) で生成すると、各要素は'int64'になります。
この表現は、np.array([1,2,3], np.int64)と同じです。
(np.array([1,2,3], np.int)の表現も使えますが、Python2かPython3か、32ビットか64ビットによって異なるでしょう。)
各要素を -128〜127の1byte整数の要素にする場合は、次のような生成表現になります。

np.array([1,2,3], np.int8) 
np.array([1,2,3], dtype='int8') 
np.array([1,2,3], dtype='i1') #(型コードで指定)

上記3通りのどれを使っても同じです。「npオブジェクト」.dtype の表現で型を確認できます。
(各データ型の取り得る値の範囲は、整数int, uintの場合に np.iinfo()、 浮動小数点数の場合は、np.finfo()で確認できる。)

numpy要素の型を一括して、異なる型のnumpyを生成するメソッドが、astype( dtype )です。

a = np.array([1,2,3]) 
print( a.dtype ) 
a = np.array([1,2,3], np.int8) 
print( a.dtype ) 
a2 = a.astype( np.int ) # 全ての要素をnp.intに変換している。(np.int32と指定した方が明確である)
print( a2.dtype )
print( np.iinfo( np.int8 ) ) #iinfo(min=-128, max=127, dtype=int8)
print( np.iinfo( np.int ) ) #iinfo(min=-2147483648, max=2147483647, dtype=int32)

この表現を使うとsin波形の生成は、次 ((0x1ff * np.sin(np.arange(-np.pi, np.pi, 0.1))).astype(np.int16)+0x1ff).tobytes()



numpyの基本的な型は、真偽値 (bool),(符号付き)整数 (int),符号なし整数 (uint),浮動小数点数 (float),複素数 (complex)です。
ただし、bool型を除いたデータ型はそれぞれ異なるサイズがあります。
たとえば、int型なら、numpy.int8,numpy.int16,numpy.int32,numpy.int64 です。
以下は、バイナリ情報の並びが16ビットリトルエンディアンの並びとして、数値演算(ここでは、* 1.0)して、再びバイナリに戻す例を示します。
import numpy as np
buffer1=b"\x06\x00\x06\x00\x03\x00\x02\x00\x03\x00\x03\x00\xfd\xff\xfc\xff\xfb\xff\xfa\xff\xfc\xff\xfe\xff\x00\x00\xfc\xff\xf8\xff"
y1 = np.frombuffer(buffer1, dtype="int16") # bufferのバイナリが、16bit整数(リトルエンディアン)である前提で、1次numpyの配列に変換
y1=y1*1 # 例として *1 の演算
y2=y1.astype(np.int16) # float の要素を、16ビット整数群に変更 
buffer2=b''.join(y2) # バイナリに戻す
print(buffer1)
print(buffer2) # 上記と比較している。



以下で、符号ありバイト列を用意して、その先頭要素が符号ありであれば、符号なしバイトに変換する例を示す。
なお型は「isinstance」関数で判定できる。以前は文字の判別のとき、(str,unicodeなどをorで判定する必要があったが、Python3では「basestring」で判定できる)
a=np.array([1,127,-1, -128], np.int8)
a #出力:array([   1,  127,   -1, -128], dtype=int8)
if isinstance(a[0], np.int8) : #要素の型判定
   a = a.astype(np.uint8)

a #出力:array([  1, 127, 255, 128], dtype=uint8)

以下は、np.int16 の要素のnumpy配列を tobytes()メソッドでバイナリに変換する例です。
この変換で、リトルエンディアンで変換されていることを確認しています。
a=np.array([128, 32767], dtype=np.int16)  
b=a.tobytes()
print(b) # 表示内容:b'\x80\x00\xff\x7f'
a32=np.array([128, 32767]) 
print( a32.dtype)    # 表示内容:int32
print(a32.tobytes()) # 表示内容:b'\x80\x00\x00\x00\xff\x7f\x00\x00'

a16=a32.astype(np.int16) 
print( a16.dtype)    # 表示内容:int16
b16=a16.tobytes()
print(b16) # 表示内容:b'\x80\x00\xff\x7f'