【NumPy入門】np.vectorizeでPython関数を簡単にユニバーサル関数化!

こんにちは!インストラクターのフクロウです!NumPyにはホントにたくさんの関数があります。これを全部使いこなすのは少し難しいですし、NumPyの機能だけでは実装できない処理もあるはずです。

そんなときに役に立つのがnp.vectorize関数。Pythonの関数を簡単にNumPyの関数にしてくれます!この記事で使い方を学んで使ってみてください!

目次

np.vectorizeの使い方

np.vectorizeの基本的な使い方

np.vectorizeは、Pythonの関数を配列に適用できるように変換する関数です。NumPyにおいて、配列のすべての要素に一括で処理を適用できる関数のことをユニバーサル関数といいます。

np.vectorizeでユニバーサル関数にできる関数は、スカラー値や文字列が引数になっているものです。では、Pythonで実装したsigmoid関数を、np.vectorizeでユニバーサル関数化してみましょう。

import numpy as np
import math

# ①ターゲットのPython関数
def py_sigmoid(x):
    return 1/ (1+math.exp(-x))

# ②forループでユニバーサル関数っぽくしたもの
def vpy_sigmoid(X):
    result = np.zeros_like(X)
    for i in range(len(X)):
        result[i] = py_sigmoid(X[i])
    return result

# ③np.vectorizeでユニバーサル関数を作ったもの
vsigmoid = np.vectorize(py_sigmoid)

# ④NumPy関数で作ったユニバーサル関数
def np_sigmoid(x):
    return 1/ (1+np.exp(-x))

①はスカラーを受け取って、スカラーを返す関数です。

>>> X = np.linspace(-10,10, 10)

>>> py_sigmoid(X)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-a145f0f92b5a> in <module>()
----> 1 py_sigmoid(X)

<ipython-input-2-bcf4ceeeadd2> in py_sigmoid(x)
      1 def py_sigmoid(x):
----> 2     return 1/ (1+math.exp(-x))
      3 
      4 def vpy_sigmoid(X):
      5     result = np.zeros_like(X)

TypeError: only size-1 arrays can be converted to Python scalars

この関数を配列のすべての要素に適用するには、普通に考えるとfor文を使うことになります。それが②ですが、np.vectorizeを使うと一行で再現することができます。

では、これらの関数がちゃんと動作するか見てみましょう。

>>> vpy_sigmoid(X)

array([4.53978687e-05, 4.18766684e-04, 3.85103236e-03, 3.44451957e-02,
       2.47663801e-01, 7.52336199e-01, 9.65554804e-01, 9.96148968e-01,
       9.99581233e-01, 9.99954602e-01])

>>> vsigmoid(X)

array([4.53978687e-05, 4.18766684e-04, 3.85103236e-03, 3.44451957e-02,
       2.47663801e-01, 7.52336199e-01, 9.65554804e-01, 9.96148968e-01,
       9.99581233e-01, 9.99954602e-01])

>>> np_sigmoid(X)

array([4.53978687e-05, 4.18766684e-04, 3.85103236e-03, 3.44451957e-02,
       2.47663801e-01, 7.52336199e-01, 9.65554804e-01, 9.96148968e-01,
       9.99581233e-01, 9.99954602e-01])

どの書き方の関数でも、同様にすべての要素にsigmoid関数の計算ができていることがわかりますね。今回はsigmoidなのでNumPyの機能だけでキレイに書き下せますが、難しい場合には非常に便利ですね。

何よりfor文を書かずにNumPyっぽくプログラムがかけるのがいいですね!

np.vectorizeの速度比較

さて、Pythonの関数を気軽にユニバーサル関数にできるnp.vectorizeですが、実行速度はどうでしょうか。ipythonやjupyterなどの環境で、プログラムの実行時間を測る%timeit機能を使って測ってみましょう!

sample = np.linspace(-100,100, 1000)

%timeit vpy_sigmoid(sample)
%timeit vsigmoid(sample)
%timeit np_sigmoid(sample)

[Output]

357 µs ± 2.84 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
244 µs ± 2.73 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
15.3 µs ± 170 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

for文で書いたvpy_sigmoidよりは、<np.vectorizeで書いたvsigmoidの方が速いですね!でも実は、すべてNumPy関数で書いたものは桁違いの速さ(15.3 µs )です。

NumPyでかける関数はできるだけNumPyで書いてしまって、速度があまり必要でない関数やNumPyで書くのが難しい関数はnp.vectorizeで書くと良さそうです。

まとめ

この記事では、Python関数を簡単にNumPyのユニバーサル関数にする機能、np.vectorize関数を紹介しました。NumPyの関数は独特なので、最初から使いこなすのは難しいかもしれません。

そんなとき、np.vectorize関数を使うことで、手軽に欲しい機能が実装できます!簡単なので是非試して見てくださいね!

この記事を書いた人

【プロフィール】
DX認定取得事業者に選定されている株式会社SAMURAIのマーケティング・コミュニケーション部が運営。「質の高いIT教育を、すべての人に」をミッションに、IT・プログラミングを学び始めた初学者の方に向け記事を執筆。
累計指導者数4万5,000名以上のプログラミングスクール「侍エンジニア」、累計登録者数1万8,000人以上のオンライン学習サービス「侍テラコヤ」で扱う教材開発のノウハウ、2013年の創業から運営で得た知見に基づき、記事の執筆だけでなく編集・監修も担当しています。
【専門分野】
IT/Web開発/AI・ロボット開発/インフラ開発/ゲーム開発/AI/Webデザイン

目次