Numpyのwarningを例外処理にしてロギング

numpyのfloating-point errorはデフォルトではwarningを出す。
http://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html


ここの情報によると、
http://stackoverflow.com/questions/10519237/python-how-to-avoid-numpy-runtimewarning-in-function-definition
numpy.errstateでRuntimeWarningをFloatingPointErrorにするのが、良さそうだ。

np.errstateの挙動はこんな感じ。

In [3]: with np.errstate(all='raise'):
   ...:     np.array([1.0])/0
   ...:
---------------------------------------------------------------------------
FloatingPointError                        Traceback (most recent call last)
<ipython-input-3-34478ac4bed1> in <module>()
      1 with np.errstate(all='raise'):
----> 2     np.array([1.0])/0
      3

FloatingPointError: divide by zero encountered in divide

例外として捉える。

#!/usr/bin/env python

import numpy as np

try:
    with np.errstate(all='raise'):
        np.array([1.0])/0
except FloatingPointError as exc:
    print exc

他に、WarningをErrorして捉える方法は例えばここら
http://stackoverflow.com/questions/15933741/how-do-i-catch-a-warning-in-python-like-its-an-exception-not-just-for-testing
に書いている。warnings.filterwarnings('error')を使う。

#!/usr/bin/env python

import numpy as np
import warnings

warnings.filterwarnings('error')

try:
    np.array([1.0]) / 0
except RuntimeWarning as exc:
    print exc

少し用途は違いそうだけど、warnings.catch_warnings(record=True)というのもある。
https://docs.python.org/2/library/warnings.html#testing-warnings

例外の内容はsys.exc_info()に記録される。
https://docs.python.org/2/library/sys.html
例外の捉え方
https://docs.python.org/2.7/tutorial/errors.html
sys.exc_info()の出力を文字列に変換する方法などがここに書いている。
http://melpystudio.blog82.fc2.com/blog-entry-87.html
traceback.format_exception()も便利なようだ。これは、logging.exception('')の文字列出力と同じのようだ。
http://stackoverflow.com/questions/4508849/how-to-log-python-exception

ロギングに関してはここが参考になる。
http://stackoverflow.com/questions/4508849/how-to-log-python-exception
https://docs.python.org/2/library/logging.html

まとめ

#!/usr/bin/env python

import numpy as np
import sys
import traceback
import warnings
import logging

logging.basicConfig(filename='test.log',level=logging.DEBUG)

def test_filterwarnings():
    warnings.filterwarnings('error')

    try:
        np.array([1.0]) / 0
    except RuntimeWarning as exc:
        print exc

def test_errstate():
    try:
        with np.errstate(all='raise'):
            np.array([1.0])/0
    except FloatingPointError as exc:
        print exc
        logging.exception('') # saved to test.log
        exc_type, exc_value, exc_traceback = sys.exc_info()
        print ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback))

test_filterwarnings()
test_errstate()

Numpyのinfとnan

logを使って、nanとinfを出す。

In [4]: np.log([-1.])
/opt/local/bin/ipython:1: RuntimeWarning: invalid value encountered in log
  #!/opt/local/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
Out[4]: array([ nan])

In [5]: np.log([-0.])
/opt/local/bin/ipython:1: RuntimeWarning: divide by zero encountered in log
  #!/opt/local/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
Out[5]: array([-inf])

np.errstateを使って例外にするとFloatingPointErrorになる。

In [3]: with np.errstate(all='raise'):
    np.log([-1])
   ...:
---------------------------------------------------------------------------
FloatingPointError                        Traceback (most recent call last)
<ipython-input-3-23ac75103728> in <module>()
      1 with np.errstate(all='raise'):
----> 2     np.log([-1])
      3

FloatingPointError: invalid value encountered in log

In [4]: with np.errstate(all='raise'):
   ...:     np.log([0])
   ...:
---------------------------------------------------------------------------
FloatingPointError                        Traceback (most recent call last)
<ipython-input-4-c940e768b715> in <module>()
      1 with np.errstate(all='raise'):
----> 2     np.log([0])
      3

FloatingPointError: divide by zero encountered in log