numpyの関数

(2018-09-23)

ndarrayの生成

ndarrayはnumpyの多次元の配列を表すオブジェクトで、[start:stop:step, …]の indexでアクセスできる。

x = np.array([[1, 2, 3, 4], [2, 4, 6, 8]])
print(x[0, 1]) # 2
print(x[0,1:-1]) # [2 3]
print(x[:,2]) # [3 6]
print(x[:,::2]) # [[1 3] [2 6]]
print(x[1,::-1]) # [8 6 4 2]

arrayやiteratableオブジェクトからndarrayを生成する。

print(np.array([1, 2, 3])) # [1 2 3]

def generate():
    for x in range(3):
        yield x
x = np.fromiter(generate(), dtype=float)
print(x) # [ 0.  1.  2.]

引数で渡したshapeを特定の値で埋めたndarrayを生成する。

print(np.zeros(5)) # [ 0.  0.  0.  0.  0.]
print(np.ones((2,2))) # [[ 1.  1.] [ 1.  1.]]
print(np.full((2, 3), 2)) # [[2 2 2] [2 2 2]]

Python built-inのrange()のndarray版と、startからstopまで等間隔なndarrayを生成する関数。

print(np.arange(5)) # [0 1 2 3 4]
print(np.linspace(2.0, 3.0, num=5)) # [ 2.    2.25  2.5   2.75  3.  ]

diagonal(対角)は1,それ以外は0の単位行列を生成する。

print(np.identity(3)) # [[ 1.  0.  0.] [ 0.  1.  0.] [ 0.  0.  1.]]
print(np.eye(3)) # [[ 1.  0.  0.] [ 0.  1.  0.] [ 0.  0.  1.]]

ランダム値のndarrayを生成する。

print(np.random.random((2, 2)) # [[ 0.84157926  0.77701369] [ 0.92937916  0.41447905]]
print(np.random.randint(low=5, high=10, size=(2, 2))) # [[9 5] [7 7]]
print(np.random.uniform(low=5, high=10, size=(2,2))) # [[ 9.72222125  6.07259325] [ 7.24174366  9.27801853]]

加工

キャストする。

print(np.array([1, 2, 2.5]).astype(int)) # [1 2 2]

shapeを変更するのと、1次元にする関数。

x = np.arange(4).reshape((2, 2))
print(x) # [[0 1] [2 3]]
print(x.flatten()) # [0 1 2 3]

paddingする。modeで埋まる値が決まる。

print(np.pad(np.zeros((2, 2)), pad_width=1, mode='constant', constant_values=2))
"""
[[ 2.  2.  2.  2.] 
 [ 2.  0.  0.  2.]
 [ 2.  0.  0.  2.]
 [ 2.  2.  2.  2.]]
"""

print(np.pad(np.arange(9).reshape(3,3), pad_width=1, mode='edge'))
"""
[[0 0 1 2 2]
 [0 0 1 2 2]
 [3 3 4 5 5]
 [6 6 7 8 8]
 [6 6 7 8 8]]
"""

対角の値を返したり、対角行列にしたりする。

x = np.arange(9).reshape((3,3))
print(np.diag(x)) # [0 4 8]
print(np.diag(np.diag(x))) # [[0 0 0] [0 4 0] [0 0 8]]
print(np.diag(np.diag(np.diag(x)))) # [0 4 8]

print(np.diagonal(x)) # [0 4 8]
print(np.diagonal(np.diagonal(x))) # diag requires an array of at least two dimensions

ソートとシャッフル。argsort()とargpartition()はindexを返す。 argpartition()はkth番目の値で分けるもの(下の例だと4番目に小さいindex 0)で、パーティション内の順序は保証されないが、n番目のindexだけ欲しい場合はargsort()より速い。 random.permutation()はPandasの行をシャッフルするときにも使える。

Pandasの操作 - sambaiz-net

x = np.random.random((3, 3))
print(np.sort(x)) 
"""
[[ 0.14366067  0.41558783  0.7584969 ] 
 [ 0.1395897   0.78905376  0.89709119]
 [ 0.3235212   0.82675995  0.95140141]]
"""

x2 = np.array([3, 1, 2, 1, 4, 5])
print(np.argsort(x2)) # [1 3 2 0 4 5]
print(np.argpartition(x2, 3)) # [3 2 1 0 4 5]

print(np.random.permutation(np.arange(5))) # [3 1 0 4 2]

repeat()は各値を繰り返し、tile()は敷き詰める。unique()はユニークな値にする。

x = np.arange(4).reshape(2,2)
print(np.repeat(x, 2)) # [0 0 1 1 2 2 3 3]
print(np.repeat(x, 2, axis=1)) # [[0 0 1 1] [2 2 3 3]]

print(np.tile(x, (3,2)))
"""
[[0 1 0 1] 
 [2 3 2 3]
 [0 1 0 1]
 [2 3 2 3]
 [0 1 0 1]
 [2 3 2 3]]
"""

x2 = np.repeat([np.repeat(np.arange(3), 2)], 2, axis=0)
print(x2) #  [[1 1 2 2 3 3] [1 1 2 2 3 3]]
print(np.unique(x2)) # [1 2 3]

ローリングする。

print(np.roll(np.arange(8).reshape(4, 2), 2, axis=0)) # [[4 5] [6 7] [0 1] [2 3]]

縦横に結合する。

x = np.arange(4).reshape((2, 2))
y = np.identity(2)
print(np.vstack((x, y))) 
'''
[[ 0.  1.] [ 2.  3.] 
 [ 1.  0.] [ 0.  1.]]
'''

print(np.hstack((x, y))) 
'''
[[ 0.  1.  1.  0.] 
 [ 2.  3.  0.  1.]]
'''

分割する。array_split()はちょうど分けられなくてもエラーにしない。

print(np.split(np.arange(7), 3)) # ValueError: array split does not result in an equal division
print(np.array_split(np.arange(7),3)) # [array([0, 1, 2]), array([3, 4]), array([5, 6])]

座標の値からndarrayを生成する。

x, y = np.meshgrid(np.linspace(0,1,5), np.linspace(0,1,5))
print(x)
'''
[[ 0.    0.25  0.5   0.75  1.  ]
 [ 0.    0.25  0.5   0.75  1.  ]
 [ 0.    0.25  0.5   0.75  1.  ]
 [ 0.    0.25  0.5   0.75  1.  ]
 [ 0.    0.25  0.5   0.75  1.  ]]
'''
print(y)
'''
[[ 0.    0.    0.    0.    0.  ]
 [ 0.25  0.25  0.25  0.25  0.25]
 [ 0.5   0.5   0.5   0.5   0.5 ]
 [ 0.75  0.75  0.75  0.75  0.75]
 [ 1.    1.    1.    1.    1.  ]]
'''

uint8のndarrayをバイナリの値に変換するのと、その逆。

x = np.unpackbits(np.array([[8], [23]], dtype=np.uint8), axis=1)
print(x) # [[0 0 0 0 1 0 0 0] [0 0 0 1 0 1 1 1]]
print(np.packbits(x, axis=1)) # [[ 8] [23]]

比較

0でないindexを返す。booleanのndarrayからTrueを抽出するのにも使える。 where()の第1引数は条件式で、第2引数と第3引数を渡すとそれぞれTrueとFalseの場合に置換される。

x = np.array([[1,0,0], [0,2,0], [1,1,0]])
print(np.nonzero(x)) # (array([0, 1, 2, 2]), array([0, 1, 0, 1])) => [0, 0], [1, 1], [2, 0], [2, 1]
print(np.where(x)) # (array([0, 1, 2, 2]), array([0, 1, 0, 1]))
print(x[np.nonzero(x)]) # [1 2 1 1]

print(x > 1) # [[False False False] [False  True False] [False False False]]
print(x[np.nonzero(x > 1)]) # [2]

print(np.where(x == 1, x, 0)) # [[1 0 0] [0 0 0] [1 1 0]]

一致する場合はTrueを返す。allclose()は誤差を許容する。

x = [1e10,1e-8]
y = [1.00001e10,1e-9]
print(x == y) # False
print(np.allclose(x, y)) # True
print(np.array_equal(x, y)) # False

o = np.ones(3)
o2 = np.ones(4)
print(o == o2) # comparison failed
print(np.array_equal(o, o2)) # False

和、積、差集合と排他的論理和。

x = [1, 3, 4, 3]
y = [3, 1, 2, 1]
print(np.union1d(x, y)) # [1 2 3 4]
print(np.intersect1d(x, y)) # [1 3]
print(np.setdiff1d(x, y)) # [4]
print(np.setxor1d(x, y)) # [2 4]

AND,OR,NOT,XORしたbooleanの値を返す。all()とany()はarrayに対するANDとOR。

x = [True, False, True]
y = [False, False, True]
print(np.logical_and(x, y)) # [False False  True]
print(np.all([x, y, np.repeat([True], 3)], axis=0)) # [False False  True]
print(np.logical_or(x, y)) # [ True False  True]
print(np.any([x, y, np.repeat([True], 3)], axis=0)) # [ True  True  True]
print(np.logical_not(x)) # [False  True False]
print(np.logical_xor(x, y)) # [ True False False]

正数の出現回数をカウントする。

print(np.bincount([0, 1, 2, 1, 2, 6, 1])) # [1 3 2 0 0 0 1]

計算

和と内積(a・b)。和は+でも計算できるが、通常のarrayに使うと後ろに結合されてしまうのに注意。 “@“はmatmul()と同じで数値との積は計算できない。 “*“はmultiply()で、要素ごとの積が返る。

x = np.arange(4).reshape((2, 2))

print([0, 1, 2] + [1, 2, 3]) # [0, 1, 2, 1, 2, 3]
print(x + x) # [[0 2] [4 6]]
print(np.add(x, x)) # [[0 2] [4 6]]

print(np.dot(np.ones((2,2)), np.ones((2,3)))) # [[ 2.  2.  2.] [ 2.  2.  2.]]
print(np.matmul(np.ones((2,2)), np.ones((2,3)))) # [[ 2.  2.  2.] [ 2.  2.  2.]]
print(np.ones((2,2)) @ np.ones((2,3))) # [[ 2.  2.  2.] [ 2.  2.  2.]]
print(np.ones((2,2)) * np.ones((2,3))) # operands could not be broadcast together with shapes (2,2) (2,3) 

print(np.dot(np.ones((2,2)), 2)) # [[ 2.  2.] [ 2.  2.]]
print(np.matmul(np.ones((2,2)), 2)) # Scalar operands are not allowed, use '*' instead
print(np.ones((2,2)) @ 2)  # Scalar operands are not allowed, use '*' instead

平方根を返す。emathの方は複素数が返る。

print(np.sqrt([4, 0, -4])) # [  2.   0.  nan]
print(np.emath.sqrt([4, 0, -4])) # [ 2.+0.j  0.+0.j  0.+2.j]

三角関数と逆三角関数。

from math import pi
x = np.linspace(-pi, pi, num=5)
print(np.sin(x)) # [ -1.22464680e-16  -1.00000000e+00   0.00000000e+00   1.00000000e+00  1.22464680e-16]
print(np.cos(x)) # [ -1.00000000e+00   6.12323400e-17   1.00000000e+00   6.12323400e-17 -1.00000000e+00]
print(np.tan(x)) # [  1.22464680e-16  -1.63312394e+16   0.00000000e+00   1.63312394e+16 -1.22464680e-16]

x2 = np.linspace(-1, 1, num=5)
print(np.arcsin(x2)) # [-1.57079633 -0.52359878  0.          0.52359878  1.57079633]
print(np.arccos(x2)) # [ 3.14159265  2.0943951   1.57079633  1.04719755  0.        ]
print(np.arctan(x2)) # [-0.78539816 -0.46364761  0.          0.46364761  0.78539816]

指数と、eが底の自然対数(ln(x))。

x = [0.1, 1, 2]
print(np.exp(x)) # [ 1.10517092  2.71828183  7.3890561 ]
print(np.log(x)) # [-2.30258509  0.          0.69314718]

minより小さな値はminに、maxより大きな値はmaxにする。log()の引数に0が渡るのを避けることができる。

x = np.arange(2)
np.log(x) # RuntimeWarning: divide by zero encountered in log
x2 = np.clip(x, 1e-10, x)
print(x2) # [  1.00000000e-10   1.00000000e+00]
np.log(x2) # ok

最小、最大、合計、平均。argmin()とargmax()はindexを返し、average()は重みを付けられる。average以外はx.min()のように呼ぶこともできる。

x = np.arange(4).reshape((2, 2))
print(np.min(x)) # 0 
print(np.max(x)) # 3
print(np.argmax(x)) # 3
print(np.sum(x)) # 6
print(np.mean(x)) # 1.5
print(np.average(x, weights=np.array([[0, 1], [4, 1]]))) # 2.0 <= (1 * 1 + 2 * 4 + 3 * 1) / (1 + 4 + 1) 

累積和と前の値との差。

x = np.arange(9).reshape((3, 3))
print(np.cumsum(x, axis=1)) # [[ 0  1  3] [ 3  7 12] [ 6 13 21]]
print(np.diff(x, axis=1)) # [[1 1] [1 1] [1 1]]

切り上げ、切り捨てと絶対値。floor(-2.5)は-3.0になり、trunc(-2.5)は-2.0になる。 copysign()は第2引数の符号を第1引数にコピーする。 exercisesではnp.copysign(np.ceil(np.abs(Z)), Z)のようにabsしてから元に戻すために使われていた。

x = np.random.uniform(low=-5, high=5, size=(2,2))
print(x) # [[ 2.19861752 -4.22997748] [ 0.15346107  0.62893343]]
print(np.ceil(x)) # [[ 3. -4.] [ 1.  1.]]
print(np.floor(x)) # [[ 2. -5.] [ 0.  0.]]
print(np.trunc(x)) # [[ 2. -4.] [ 0.  0.]]
print(np.abs([-2, 0, 2])) # [2 0 2]
print (np.copysign([1, -2, -1], [-2, 1, -1])) # [-1.  2. -1.]

行列式(determinant)を計算する。

print(np.linalg.det(np.arange(4).reshape((2, 2)))) # -2.0 <= 0 * 3 - 1 * 2

パーセンタイルを返す。

print(np.percentile(np.arange(16).reshape((4,4)), 90)) # 13.5

1次元の畳み込み。第2引数をずらしながら掛けていく。 畳み込みニューラルネットワークでも使う2次元の畳み込みの関数はnumpyにはないが、scipyのsignal.convolve2d()が使える。

TensorFlow チュートリアル2(Deep MNIST for Experts) - sambaiz-net

print(np.convolve([3, 6, 9], [0, 1, 0.5])) # [0.  1.  2.5 4.  1.5] <= [(0*3), (0*6+1*3), (0*9+1*6+0.5*3), (1*9+0.5*6), (0.5*9)]

from scipy import signal
print(signal.convolve2d(np.arange(9).reshape((3,3)), np.eye(2)))
'''
[[  0.   1.   2.   0.]
 [  3.   4.   6.   2.]
 [  6.  10.  12.   5.]
 [  0.   6.   7.   8.]]
'''

その他

その前の関数でreduceする。

x = np.arange(4).reshape((2,2))
print(np.add.reduce(x)) # [2 4] <= default axis value is 0
print(np.add.reduce(x, axis=1)) # [1 5]

ランダムに選ぶ。選ばれる確率pを渡すことができる。

x = np.arange(5)
print(np.random.choice(x, 10)) # [3 3 0 4 1 2 0 4 2 1]
print(np.random.choice(x, 10, p=(x / np.sum(x)))) # [3 4 3 4 3 1 3 1 3 3]

フラットなindexをそのshapeでのindexに変換する。

x = np.arange(9).reshape(3,3)
idx = np.unravel_index(5, x.shape)
print(idx) # (1, 2)
print(x[idx]) # 5

線形補間(interpolation)した値を返す。

x = np.arange(100)
y = np.sin(0.1 * x)
x2 = [10.5, 20.2, 30.4, 60.3, 80.9]
y2 = np.interp(x2, x, y)

import matplotlib.pyplot as plt
plt.plot(x, y)
plt.plot(x2, y2, 'o')
plt.show()

元のグラフと補完補間した点