HOWTO · NumPy

NumPy で関数をマップする方法

numpy.vectorize() または map() と lambda を使って、Python 関数を NumPy 配列のすべての値に適用します。各アプローチの仕組みと使い分けを説明します。

このページの内容

NumPy 配列の各要素にスカラー値を受け取る Python 関数を適用するには、関数を numpy.vectorize() で包むか、Python の map() と lambda を使って結果を配列に変換します。どちらも既存のスカラー処理を再利用したい場合に便利です。同等の処理を NumPy の配列演算で実行できるなら、通常はそちらが適しています。

numpy.vectorize() で関数を要素ごとに適用する

numpy.vectorize() を使うと、一度に1つの値を受け取る関数を配列に対して呼び出せます。ラップした関数を要素ごとに適用し、その結果を配列として返します。既存の Python の処理がスカラー向けに書かれていて、それを配列データに使いたい場合に便利です。

次の例では、入力値を2乗するスカラー関数をラップし、5つの整数に適用します。

import numpy as np

def square(value):
    return value ** 2

values = np.array([1, 2, 3, 4, 5])
square_each = np.vectorize(square)
result = square_each(values)

print(result)

ここで square は通常の Python 関数のままです。np.vectorize() は、配列を渡せる呼び出しインターフェースを提供します。これは利便性のためのラッパーであり、性能を最適化するものではありません。関数をコンパイル済みの NumPy 演算に変換するわけではないためです。NumPy がすでに対応している計算なら、たとえば values ** 2 と書くほうが簡潔で、NumPy の配列演算を直接利用できます。スカラー処理を流用することでコードが明確になる場合や、再利用しやすくなる場合に numpy.vectorize() を使いましょう。

lambda 関数を使って map() を適用する

Python 組み込みの map() は、イテラブルの各要素に関数を1回ずつ適用します。lambda を使うと、小さな関数をその場で簡潔に定義できます。入力が NumPy 配列の場合、map() は変換後の値を返すイテレーターを生成します。そのイテレーターを list() でリストにし、さらに np.array() に渡すと配列を作成できます。

次の例では、lambda で同じ値を2乗し、map() の結果を NumPy 配列に変換します。

import numpy as np

values = np.array([1, 2, 3, 4, 5])
mapped_values = map(lambda value: value ** 2, values)
result = np.array(list(mapped_values))

print(result)

lambda は配列の各値を個別に受け取り、map() は返された2乗値を順番に生成します。イテレーターをリストに変換すると、要素がすべて取り出されます。その後、np.array() がそれらの値から配列を作成します。この方法は、短いスカラー処理を map() の呼び出し箇所の近くに書きたい場合に便利です。処理が長い場合は、読みやすさと保守性のために名前付き関数を定義し、lambda の代わりにその関数を map() に渡しましょう。

既存のスカラー関数を配列向けのインターフェースで使いたい場合は numpy.vectorize() を選びます。短い変換をその場で定義したい場合、特に変換後のイテレーターを配列にする前に使いたい場合は、lambda と map() を選びます。すべての値を2乗するような処理では、意図する計算を表せるなら values ** 2 のような NumPy の式を使うのが適切です。これらは Python の処理を適用する方法の違いを示すものであり、どちらかの方法がより高速だという根拠にはなりません。