概要
pythonの科学計算モジュールnumpyの関数vectorizeの使い方にハマったので自分のためのメモ
ちなみに、今回は画像処理において入力画像のヒストグラム作成を例にとって本記事を投稿。
numpy.vectorizeの目的
pythonの関数のうち引数に値をとるものにリストを突っ込めるように関数を変換する関数がvectorizeである。 入力のarrayの各値を引数として計算してくれるようになり、返り値はベクトル化される。
numpy.vectorizeの使い方
まず返り値がリストでない関数を用意する。
myfunc.py
def myfunc(a,b):
return a+b
print myfunc("hoge","Hoge")
出力は以下のようになる。
"hogeHoge"
このmyfuncにベクトルを突っ込むことを考える。
myfunc.py
def myfunc(a,b):
return a+b
list = ["hoge","fuga"]
print myfunc(list,"Hoge")
出力は次のようになってほしい。
["hogeHoge","fugaHoge"]
しかし、実際は
TypeError: can only concatenate list (not "str") to list
となる。もともとリストを引数とするように定義されていないからである。
しかし、myfuncをnumpy.vectorizeでベクトル化することで期待通りの出力を得られる。
vfunc=numpy.vectorize(myfunc)
print vfunc(list,"Hoge")
出力は
["hogeHoge","fugaHoge"]
とリストが返ってくる。これで関数のベクトル化が達成できた。
実践例
もっと実践的な例を残しておく。画像処理で入力画像のヒストグラムをつくる関数をつくる。
import numpy as np
import cv2
from matplotlib import pyplot as plt
# ヒストグラム作成用の関数
def img_hist(src,bins_array):
x = np.where(src==bins_array,1,0)
count = np.count_nonzero(x)
return count
# ベクトル化
vhist = np.vectorize(img_hist)
vhist.excluded.add(0) # 0番目の引数は固定のベクトルとしてそのまま関数に渡す
# ソースファイルとヒストグラムのbinを用意
src = cv2.imread("origin/LENNA.pgm",flags=0)
bins_array = np.arange(256)
# ヒストグラムを作成
hist_array=vhist(src,bins_array)
# ヒストグラムを可視化
plt.plot(bins_array,hist_array)
plt.show()
入力画像は定番のこれ
結果として以下のようなヒストグラムが得られる。
まとめ
- numpy.vectorizeの使い方を整理できた。
- なかなか便利で色々応用できるはず。
forループをなるべく使わずにプログラミングできる。 - 追記(5年前の記事ですがいまだにたまにLGTM等の通知がくるので注意喚起の意味も込めて): numpy.vectorize は便利ですが、for文と比較してパフォーマンス面で優れているわけではないようです。(参考: https://numpy.org/doc/stable/reference/generated/numpy.vectorize.html Notesの部分)
- 本記事を執筆した当時の私は「pythonだしfor文は悪!」のような短絡的な思考をしていたなあと思われます。何事も用法容量を守って正しく使いましょう(自戒)