はじめに・前提
numpyにかかるバグ?っぽい挙動を発見したので、その共有記事です。
本内容については、Github issuesとして共有済みです(2024.11.9現在返信待ち)。
前提となる実行環境は以下のとおりです。
結論
下記のようなプログラムを書くと、numpyでマスクした値が外れるようです。
import numpy as np a3 = np.array([[-9999, 8, -9999], [1, 100, 2], [-9999, -9999, 2]]) # a3.shapeは、3.3 a3 = np.ma.masked_where(a3 == -9999, a3) # -9999をマスクする b3 = np.array([[-9999, 8, -9999], [1, 100, 2], [-9999, -9999, 2]]) # b3.shapeは、3.3 b3 = np.ma.masked_where(b3 == -9999, b3) # -9999をマスクする print(a3) # [[-- 8 --] [1 100 2] [-- -- 2]] print(b3) # [[-- 8 --] [1 100 2] [-- -- 2]] x3 = np.zeros(((2, 3, 3))) # a3やb3を含むためのnumpy.ndarrayを定義 x3[0, :, :] = a3 x3[1, :, :] = b3 print(x3) """ マスクしたはずの値に対して、マスクが外れる! [[[-9.999e+03 8.000e+00 -9.999e+03] [ 1.000e+00 1.000e+02 2.000e+00] [-9.999e+03 -9.999e+03 2.000e+00]] [[-9.999e+03 8.000e+00 -9.999e+03] [ 1.000e+00 1.000e+02 2.000e+00] [-9.999e+03 -9.999e+03 2.000e+00]]] """
低次元配列を複数定義し、その低次元配列を高次元配列で覆うように書き換えると、マスクが外れるようです。
ただし、
a = np.array([3, 4, -9999, 8, -9999]) a = np.ma.masked_where(a == -9999, a) c = np.zeros(len(a)) c = a # [3 4 -- 8 --] マスクが維持される! print(c)
のように同次元系の配列の場合、マスクは外れないようです。。。
マスクされていることが前提の統計処理等はよく気をつけたほうがいいですね。
numpy.ma.core.MaskedArrayとは
値をマスクするときに使われるnumpyのマスクメソッドです。
欠損・異常値処理において役に立つモジュールです。
a = np.array([3, 4, np.nan, 8, np.nan]) print(a.mean()) # nan a = np.ma.masked_where(np.isnan(a), a) print(a) # [3.0 4.0 -- 8.0 --] print(a.mean()) # 5.0
numpy.ndarrayとは
numpyで多次元配列を定義するために、使われます。
numpyユーザーの中でも最もよく使われるもののひとつではないかと思います。
a3 = np.array([[-9999, 8, -9999], [1, 100, 2], [-9999, -9999, 2]])
高次元の配列も簡単に定義することが可能です。
追記 2024.11.23
上記バグについて、numpy側からフォローがあったので共有します。
結論、
x3 = np.zeros(((2, 3, 3)))
ではなく、
x3 = np.zeros(((2, 3, 3))) x3 = np.ma.asarray(x3)
とするとよいとのことでした。
私の環境下でも改善が確認できたので、共有します。