[NumPy] ユニバーサル関数

[NumPy] ユニバーサル関数

ユニバーサル関数

 配列 (ndarrayオブジェクト) のすべての要素を操作して配列を返す関数を ユニバーサル関数 (universal function) とよびます。たとえば、numpy.sin() は受け取った配列のすべての要素について正弦値を計算します。

# NumPyをインポート
import numpy as np

# 円周率
pi = np.pi

# 配列の定義
x = [pi/3, pi/2, pi]

print(np.sin(x))
[8.66025404e-01 1.00000000e+00 1.22464680e-16]

 
 NumPy には他にも以下のようなユニバーサル関数が用意されています。

 ・絶対値 numpy.abs(), numpy.fabs()
 ・平方根 numpy.sqrt()
 ・指数関数 numpy.exp()
 ・対数関数 numpy.log(), numpy.log10(), numpy.log2()
 ・三角関数 numpy.sin(), numpy.cos(), numpy.tan()
 ・最大値・最小値 numpy.max(), numpy.min()
 ・角度の単位変換 numpy.rad2deg(), numpy.deg2rad()
 

Python関数のユニバーサル化

 numpy.frompyfunc() に Python の関数を渡すと、ユニバーサル関数に変換されます

 numpy.frompyfunc(func, nin, nout)

 func には任意の関数オブジェクトを渡します。
 nin は元の関数の引数の個数、nout は返り値の個数です。

 次のサンプルコードでは bin() をユニバーサル関数に変換します。
 bin() は数値を 2 進数表記の文字列に変換する組み込み関数です。

# NumPyをインポート
import numpy as np

# binをユニバーサル関数に変換
ubin = np.frompyfunc(bin, 1, 1)

# 配列を用意
num = np.array([1, 2, 3, 4, 5])

# numの要素を2進数表記に変換
x = ubin(num)

print(x)
['0b1' '0b10' '0b11' '0b100' '0b101']

 

出力の指定

 すべてのユニバーサル関数 (ufunc) は out 引数で出力を指定することができます。

# NumPyをインポート
import numpy as np

# x = [0 1 2 3 4 5 6 7 8 9]
x = np.arange(10)

# 初期化されていない配列を用意
y = np.empty(10)

# xの各要素の平方根を計算してyに格納
np.sqrt(x, out = y)

print(y)
[0.         1.         1.41421356 1.73205081 2.
 2.44948974 2.64575131 2.82842712 3.        ]

 

ユニバーサル関数のメソッド

numpy.ufunc.reduce()

 numpy.ufunc.reduce()は、配列の指定した軸に沿った要素について、同じ演算を連続的に作用させて1つの値に集約させるメソッドです。

 ufunc.reduce(a, axis=0, dtype=None, out=None,
 keepdims=False, initial)

 このメソッドは numpy.add() や numpy.maximum() などの二項演算関数オブジェクトに対して使用することができます。

import numpy as np

# a = [[1 2 3],
#      [4 5 6],
#      [7 8 9]]
a = np.arange(1, 10).reshape(3, 3)

# 配列aの要素を0軸に沿って加算集約
b = np.add.reduce(a)

# 配列aの要素を1軸に沿って減算集約
c = np.subtract.reduce(a, axis = 1)

# 配列aの要素を1軸に沿って乗算集約(次元は保持)
d = np.multiply.reduce(a, axis = 1, keepdims = True)

print("b = {}".format(b))
print("c = {}".format(c))
print("d = {}".format(d))
b = [12 15 18]
c = [ -4  -7 -10]
d = [[  6]
 [120]
 [504]]

 

numpy.ufunc.accumulate()

 numpy.ufunc.accumulate() は、ufunc() による累積演算結果を返すメソッドです。

 ufunc.accumulate(array, axis=0, dtype=None, out=None)

 array が 1 次元配列 [p0 p1 p2]、ufunc が numpy.add であった場合、戻り値は
 

[p0 p0 + p1 p0 + p1 + p2]

となります。

import numpy as np

# 1次元配列を定義
a = np.array([1, 2, 3, 4, 5])

# 加算による累積配列
b = np.add.accumulate(a)

print(b)
[ 1  3  6 10 15]

 第 1 引数 array が多次元配列である場合、引数 axis で累積方向を指定することができます。

import numpy as np

# a = [[1 2 3],
#      [4 5 6],
#      [7 8 9]]
a = np.arange(1, 10).reshape(3, 3)

# 配列aの要素を0軸に沿って加算累積
b = np.add.accumulate(a)

# 配列aの要素を1軸に沿って減算累積
c = np.subtract.accumulate(a, axis = 1)

print("配列b\n{}\n".format(b))
print("配列c\n{}".format(c))
配列b
[[ 1  2  3]
 [ 5  7  9]
 [12 15 18]]

配列c
[[  1  -1  -4]
 [  4  -1  -7]
 [  7  -1 -10]]

 

numpy.ufunc.at()

 numpy.ufunc.at() は特定のインデックスの要素に関数を作用させるメソッドです。

 ufunc.at(a, indices, b=None)

 たとえば、ufunc が add である場合、配列 a のうち、第 2 引数 indices で指定した要素に配列 (またはスカラー) b を加算します。

import numpy as np

# 1次元配列を定義
a = np.array([1, 2, 3, 4, 5])

# 配列aの2番目と4番目の要素に1を加える
np.add.at(a, [1, 3], 1)

print(a)
[1 3 3 5 5]

 at()メソッドは破壊的操作(元の配列を書き換える操作)であることに注意してください。

 同じインデックスを複数回指定することもできます。

import numpy as np

# 1次元配列を定義
a = np.array([1, 2, 3, 4, 5])

# 配列aの最初の要素に1を3回加えて、5番目の要素に1を1回加える
np.add.at(a, [0, 0, 0, 4], 1)

print(a)
[4 2 3 4 6]

 

numpy.ufunc.outer()

 numpy.ufunc.outer() は要素間の演算表を作成します。
 たとえば、numpy.multiply.outer() は乗算表を返します。

import numpy as np

# x = [1 2 3 4 5 6 7 8 9]
x = np.arange(1, 10)

# 九九の表を作成
y = np.multiply.outer(x, x)

print(y)
[[ 1  2  3  4  5  6  7  8  9]
 [ 2  4  6  8 10 12 14 16 18]
 [ 3  6  9 12 15 18 21 24 27]
 [ 4  8 12 16 20 24 28 32 36]
 [ 5 10 15 20 25 30 35 40 45]
 [ 6 12 18 24 30 36 42 48 54]
 [ 7 14 21 28 35 42 49 56 63]
 [ 8 16 24 32 40 48 56 64 72]
 [ 9 18 27 36 45 54 63 72 81]]