pandasの行のマスクはbool型を明示する


言いたいことはタイトルのままだけど、ちょっとだけ整理したのでまとめておく。

発生したトラブル

毎日値が変動する数百のデータがあり、その監視を行う必要ができた。
ただし、一度値が0になったらその後は監視しなくても良かったため、pandasで次のような表を作ってgit管理することにより、監視状況の確認をできるようにした。

設定 チェック完了フラグ
2 True
1 False
0 None

例えば最新のログが上記のような形式になっていた場合、次に監視するのはチェック完了フラグがFalse(まだ条件を満たしていない)とNone(今まで監視していなかった)のした2つの行になる。

これを抜き出そうとして、if None:if False:と同じになるからと横着したらエラーを吐いた。

コード

出たエラーと対処法もまとめて表記。

import pandas as pd

f = pd.DataFrame([[2, True], [1, False], [0, None]], columns=["value", "checked"])

print(f)
print("-----")

# print(f[~f["checked"]])
# TypeError: bad operand type for unary ~: 'NoneType'

# print(f[f["checked"]])
# ValueError: Cannot mask with non-boolean array containing NA / NaN values

# print(f[f["value"]])
# KeyError: "None of [Int64Index([2, 1, 0], dtype='int64')] are in the [columns]"

print(f[~f["checked"].astype(bool)])

一番最初のコメントアウトが横着した結果。「~はNoneを含む入力には使えない」とのことだった。

二番目のコメントアウトはそれを踏まえた確認。「NA(None)を含むようなbool型ではない配列はマスクには使えない」とのこと。

なお、だからといって3つめのコメントアウトのようにbool型じゃない配列を入れたら今度は列のマスク用だと受け取るようだ。
(これを踏まえると、2番目の「マスク」って「列のマスク」である可能性がある)

正しくは、一番最後の行のようにastype関数で変換してやることだった。
それであれば下記のような結果が出力された

   value checked
0      2    True
1      1   False
2      0    None
-----
   value checked
1      1   False
2      0    None