Python実践データ分析100本ノック ~31 - 40本目~
Python実践データ分析100本ノックの読書記録の続きです。
前々回:Python実践データ分析100本ノック ~11 - 20本目~
前回 :Python実践データ分析100本ノック ~21 - 30本目~
今回は、これまで集計してきたデータをもとにクラスタリングをしていきます。
ノック32 突然のSettingWithCopyWarning
もはやこの書籍のコードではおなじみとなったSettingWithCopyWarningです。しかし、今回は原因が検討も付かず解決に時間がかかりました。
発生した箇所はこちらのラベル値を代入する部分です。
customer_clustering["cluster"] = clusters.labels_
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
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
customer_clustering["cluster"] = clusters.labels_
実は、この部分の書き方には問題がありませんでした。
ノック32の最初のコードに問題がありました。
customer_clustering = customer[["mean", "median", "max", "min", "membership_period"]]
この書き方に対して、値を入れてデータフレームを編集していこうとするとSettingWithCopyWarningが発生するそうで、上記の書き方に一番近い書き方で警告が表示されないようにするなら、以下のように記述します。
customer_clustering = customer[["mean", "median", "max", "min", "membership_period"]].copy()
.copy()を付けるだけでOKです。
私の場合は、普段、必要な列を指定して抽出するのではなく、不要な行をdropしていたため、このような警告に遭遇したことがありませんでした。
ノック36の過去6ヶ月の来店数計算でも同様に、スライスしたデータフレームに加工を加えようとするため、同様の警告が発生しました。
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
return super().rename(
この警告がなかなか不親切で、renameの書き方に問題があったのかと最初は探ったのですが、実は、その一行前のlocで指定行を取り出したところに、inplaceをtrueにして、renameするのがよくなかったようです。
対処パターンは2種類で、
①ノック32と同様に、copy()を使う
tmp = uselog_months.loc[uselog_months["年月"]==year_months[i]].copy()
②inplaceを使わないで、新たに代入し直す
tmp = tmp.rename(columns={"count":"count_pred"})
自分は、割と2のほうが書き慣れている気がしました。
他の本で読んだ気がするのですが、ひとつのデータフレームを書き換え続けるのでは無く、加工後のデータフレームを新しく用意するほうがpandas的には推奨されるようです。
イメージとしては、データ分析するときに、元データは直接変更しないよね、みたいな感覚です。
ノック37 多重配列みたいな書き方してSettingWithCopyWarning
predict_data["period"][i] = delta.years*12 + delta.months
値はちゃんと取れますが、警告がでます。
前の章でやったように、正しいilocの使い方で抽出してあげると警告は出ません。
predict_data.iloc[i, predict_data.columns.get_loc('period')] = delta.years*12 + delta.months
所感
警告を読み解くことで、pandasの理解が深まっている気がします。しかし、そもそもこれまで自分の書き方だと、SettingWithCopyWarning警告なんて出なかったので、新しい学びになっているか微妙なところです。
動けばいい、ってこともあるのですが、個人ブログじゃないので、その辺はpandasの記述ルールに則って書いて欲しい気がします。今は大丈夫でもライブラリのアップデートで推奨されない書き方だと警告では無くエラー扱いになる、なんてこともあるので、警告されている意図はちゃんと把握するようにしたいと思いました。
参考記事
「pandas の SettingWithCopyWarning で苦労した話」
https://qiita.com/HEM_SP/items/56cd62a1c000d342bd70
いつもありがとうございます! いただいたサポートは開発費(サーバー運用費)などに使わせていただきます!