ワーニングも大切に

今日はPythonの話をしたいと思います。

import warnings
warnings.filterwarnings('ignore')

確かに実行の都度、既知のワーニングが出るのはうざったくなりますね。しかし、ワーニングの存在にも当然意味があって、その一つにはプログラマが気づかないミスを救ってくれるというありがたいもの。例えばこれ。

SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

意訳すると、
コピーを伴うセッティングのワーニング:
DataFrameからのスライスに値をセットしようとしているよ。
値の設定時には.locを使おうね。

このワーニングは次のコードを実行させたときに出てきます。

import pandas as pd
df = pd.DataFrame({'a': [1,2,3], 'b': [4,5,6], 'c': [7,8,9]})
df_a = df[['a', 'b']]
df_a['b'] = [11, 12, 13]
print(df_a)
# a b
# 0 1 11
# 1 2 12
# 2 3 13
print(df)
# a b c
# 0 1 4 7
# 1 2 5 8
# 2 3 6 9

df[[‘a’, ‘b’]] で抜き出したときにはコピーになります。なので、df_aに代入した値はdfには反映されていません。一方、次のコードでもワーニングが出ますが、事情は異なります。

import pandas as pd
df = pd.DataFrame({'a': [1,2,3], 'b': [4,5,6], 'c': [7,8,9]})
df_b = df[:2]
df_b['b'] = [21, 22]
print(df_b)
# a b c
# 0 1 21 7
# 1 2 22 8
print(df)
# a b c
# 0 1 21 7
# 1 2 22 8
# 2 3 6 9

スライスで抜き出したときには参照渡しになります。つまりdf_bに代入した値はdfに反映されています。

この挙動に注意を促すべく、それぞれご親切にワーニングを出してくれているのです。コードを書いていると、特に異なる言語を同時期に使っているようなときには、どっちがどうだったか瞬時に思い出せなかったりします。挙動に自信があればじゃんじゃん使ってもよいが、他人もみる可能性のあるコードであったり、自分でも後から迷ったりする可能性があったりするのであれば、あえてワーニングが出るようなコーディングをするべきではないのです。前者であれば、明示的にコピーして変数を作成すれば良いし、後者であれば、スライスを作らずに.locを使って値を代入すればできます。

warnings-ignoreでワーニングを非表示にすることは思わぬバグを生みます。基本的に使用は避けるべきです。なんの断りもなくただ単にうざったいからという理由でコードの最初にrnings-ignoreを書いていたりする本を見かけることがあるけど、もっての外で、そんな本は買ってはいけません。pythonは型指定をする必要がなく、そのおかげで簡潔なコードを書くことができる大変便利な言語です。この利点に乗じてブラックボックスに追いやるようなコーディングは慎んだ方が良いでしょう。

h.ichijo