NumPy の Test Support における testing.assert_allclose() の詳細解説


testing.assert_allclose() は、NumPy のテストサポートモジュール (numpy.testing) に含まれるアサーション関数であり、2つの配列が指定された許容誤差内で近似的に等しいかどうかを検証します。allclose 関数と類似していますが、デフォルト値が異なる点が特徴です。

構文

numpy.testing.assert_allclose(actual, desired, rtol=1e-7, atol=0, equal_nan=True, err_msg='', verbose=True)

引数

  • verbose: True の場合、比較対象の値もエラーメッセージに含めます (デフォルト: True)
  • err_msg: エラーメッセージ (デフォルト: 空文字)
  • equal_nan: True の場合、NaN も比較対象となります (デフォルト: True)
  • atol: 絶対誤差許容値 (デフォルト: 0)
  • rtol: 相対誤差許容値 (デフォルト: 1e-7)
  • desired: 比較対象の配列
  • actual: 検証対象の配列

動作

  1. actualdesired の形状が一致していることを確認します。
  2. 各要素について、以下の式で計算される差が許容誤差以内であることを確認します。
abs(actual[i] - desired[i]) <= atol + rtol * abs(desired[i])
  1. 条件を満たさない要素があれば、AssertionError を発生させます。

デフォルト値と allclose との違い

  • atol: allclose はデフォルト値を設定していません。
  • rtol: allclose のデフォルト値は 1e-9 です。
  • verbose が True の場合、エラーメッセージには比較対象の値も含まれます。
  • NaN は、equal_nan が True の場合のみ比較対象となります。
  • actual または desired のいずれかがスカラーの場合、もう一方の配列の各要素と比較されます。

import numpy as np
import numpy.testing as npt

actual = np.array([1.00001, 1.0001])
desired = np.array([1.0, 1.0])

npt.assert_allclose(actual, desired)  # テスト成功

この例では、actualdesired の差が rtolatol で指定された許容誤差以内であるため、テストは成功します。

import numpy as np
import numpy.testing as npt

actual = np.array([1.001, 1.001])
desired = np.array([1.0, 1.0])

try:
  npt.assert_allclose(actual, desired)
except AssertionError as e:
  print(e)  # AssertionError: Not equal to tolerance rtol=1e-07, atol=0

この例では、actualdesired の差が rtolatol で指定された許容誤差を超えているため、テストは失敗し、AssertionError が発生します。

testing.assert_allclose()` の利点

  • エラーメッセージが詳細な情報を含みます。
  • NaN の扱い方を制御できます。
  • 許容誤差を柔軟に設定できます。
  • テストコードを簡潔に記述できます。
  • 浮動小数点演算の誤差の影響を受ける可能性があります。
  • 許容誤差の設定が適切でない場合、誤った結果となる可能性があります。


import numpy as np
import numpy.testing as npt

# 例 1: 配列同士の比較
actual = np.array([1.00001, 1.0001])
desired = np.array([1.0, 1.0])

npt.assert_allclose(actual, desired)  # テスト成功

# 例 2: スカラー値との比較
actual = np.array([1.0, 1.0])
desired = 1.0

npt.assert_allclose(actual, desired)  # テスト成功

# 例 3: 許容誤差の設定
actual = np.array([1.001, 1.001])
desired = np.array([1.0, 1.0])

# rtol と atol を調整することで、許容誤差を変化させます。
npt.assert_allclose(actual, desired, rtol=1e-6, atol=1e-9)  # テスト成功

# 例 4: NaN の扱い
actual = np.array([1.0, np.nan])
desired = np.array([1.0, np.nan])

npt.assert_allclose(actual, desired, equal_nan=True)  # テスト成功

# 例 5: エラーメッセージの確認
actual = np.array([1.001, 1.001])
desired = np.array([1.0, 1.0])

try:
  npt.assert_allclose(actual, desired)
except AssertionError as e:
  print(e)  # AssertionError: Not equal to tolerance rtol=1e-07, atol=0


手動による比較

def my_allclose(actual, desired, rtol=1e-7, atol=0):
    diff = np.abs(actual - desired)
    error = np.maximum(diff, rtol * np.abs(desired))
    return np.all(error <= atol)

actual = np.array([1.00001, 1.0001])
desired = np.array([1.0, 1.0])

if not my_allclose(actual, desired):
    raise AssertionError('Arrays are not close')

長所

  • 許容誤差の計算方法を完全に制御できる
  • コードの可読性が高い

短所

  • testing.assert_allclose() の持つ便利な機能 (NaN の扱い、詳細なエラーメッセージなど) が利用できない
  • 冗長なコードを書く必要がある
  • pandas.testing.assert_allclosetesting.assert_allclose() と同様の機能を提供しますが、Pandas モジュールに依存するため、NumPy だけでは利用できません。
  • scipy.allclosetesting.assert_allclose() とほぼ同じ機能を提供しますが、SciPy モジュールに依存するため、NumPy だけでは利用できません。

長所

  • testing.assert_allclose() と同様の使い方ができる

短所

  • NumPy 以外のデータ型を扱う場合に不都合が生じる可能性がある
  • 追加のライブラリをインストールする必要がある

カスタムアサーションの作成

def assert_allclose_with_custom_message(actual, desired, rtol=1e-7, atol=0, err_msg=''):
    diff = np.abs(actual - desired)
    error = np.maximum(diff, rtol * np.abs(desired))
    if not np.all(error <= atol):
        raise AssertionError(err_msg)

actual = np.array([1.00001, 1.0001])
desired = np.array([1.0, 1.0])
err_msg = '期待値と計算値が許容誤差を超えています。'

assert_allclose_with_custom_message(actual, desired, err_msg=err_msg)

長所

  • 独自のロジックを追加できる
  • エラーメッセージを完全に制御できる

短所

  • テストコードの保守が難しくなる可能性がある
  • コードの可読性が低下する可能性がある

最適な代替方法の選択

状況によって最適な代替方法は異なります。

  • 独自のロジックを追加したり、エラーメッセージを完全に制御したい場合は、カスタムアサーションを作成する必要があります。
  • SciPy や Pandas を既に利用している場合は、それぞれのライブラリに用意されている allclose 関数を活用できます。
  • 許容誤差の計算方法を完全に制御する必要がある場合は、手動による比較を行う必要があります。
  • コードの可読性と簡潔性を重視する場合は、testing.assert_allclose() をそのまま使用する方が良いでしょう。

testing.assert_allclose() は強力なツールですが、状況によっては代替手段の方が適切な場合があります。上記で紹介した代替方法を理解し、状況に応じて最適な方法を選択してください。

  • テストコードを書く際には、常に適切な許容誤差を設定することが重要です。許容誤差が小さすぎると、誤検知が発生する可能性があります。逆に、許容誤差が大きすぎると、誤差を見逃してしまう可能性があります。
  • 使用している NumPy のバージョンによって、testing.assert_allclose() の動作が異なる場合があります。詳細は NumPy のドキュメントを参照してください。