HOWTO · Seaborn
外れ値のないシーボーン箱ひげ図
showfliers=False を使って外れ値マーカーのない Seaborn 箱ひげ図を作成し、Seaborn が外れ値を判定する 1.5 x IQR ルールを理解し、代わりに外れ値の削除や上限処理が正当化される場合を確認します。
このページの内容
この記事は、箱ひげ図と外れ値とは何か、そして外れ値のマーカーのない Seaborn 箱ひげ図を作成する方法を示すことを目的としています。ほとんどの場合、正しい答えはデータを削除することではなく、マーカーを非表示にすることです。以下のセクションではその両方を示し、実際に値を削除または上限処理することが正当化される場合を説明します。
外れ値のマーカーを表示せずに Seaborn の箱ひげ図を作成する
箱ひげ図は、その四分位数で分布を要約します。箱は第 1 四分位数(Q1)から第 3 四分位数(Q3)までを占め、その中に中央値があり、ひげは外れ値とは見なされない最も極端な値まで伸びます。ひげの外側の点は、外れ値マーカー(flier)として個別に描かれます。
Seaborn ライブラリにすでにプリロードされている tips データセットを使用します。必要なパッケージをインポートし、データを見てみましょう。このデータセットは、いくつかの列を持つレストランに関するものです。
import seaborn as sb
import matplotlib.pyplot as plt
import pandas as pd
TIPS = sb.load_dataset("tips")
TIPS.head()
デフォルトで total_bill 列をプロットすると、右側にいくつかの flier が表示されます。
sb.boxplot(x=TIPS["total_bill"])
plt.show()
出力:
外れ値のマーカーなしで同じプロットを作成するには、showfliers=False を渡します。
sb.boxplot(x=TIPS["total_bill"], showfliers=False)
plt.show()
出力:
Seaborn が外れ値として表示するものを理解する
Seaborn(Matplotlib を介して)は、点が四分位数から 1.5 × IQR を超えて外側にある場合に、その点を外れ値としてフラグ付けします。ここで IQR は Q3 − Q1 です。ひげは、それらのフェンスの内側にある最も極端なデータポイントまで到達します。その外側にあるものはすべて flier として描かれます。
このルールは、total_bill について describe() 関数 で再現できます。この関数は、この列について Q1 = 13.35、中央値 = 17.80、Q3 = 24.13 を報告します。したがって IQR は 10.78 で、フェンスは 13.35 − 1.5 × 10.78 = −2.82 と 24.13 + 1.5 × 10.78 = 40.30 です。244 件の請求のうち 9 件が上側のフェンスの上にあります(最大値は 50.81)。そして、その 9 つの点がまさに最初のプロットの flier です。それらはデータエラーではないことに注意してください — レストランの記録の中で最も大きな請求であるというだけです。
showfliers=False で外れ値のマーカーを非表示にする
showfliers=False は、描かれるものだけを変更します。箱、中央値、ひげは、外れ値を含む完全なデータから、以前とまったく同じように計算されます。flier マーカーが単にレンダリングされないだけです。また、プロットは遠く離れた点に合わせて伸びることがなくなるため、箱とひげが読みやすくなります。
外れ値が有効なデータであり、目的がプレゼンテーションである場合は、このオプションを選択してください — たとえば、少数の極端な値がプロットの残りを圧縮してしまう場合などです。データセットや統計は何も変わらないため、追加で正当化したり開示したりすることは何もありません。
分析上必要な場合に限り外れ値を削除または上限処理する
場合によっては、画像だけでなく分析そのものを変更しなければならないことがあります。センサーの不具合、データ入力エラー、あるいは少数の極端な値によって歪められるモデルなどです。その場合にのみ値を変更すべきであり、その後に報告する統計は、変更されたデータに基づいて計算し、その旨を記述しなければなりません。
外れ値を削除するには、Seaborn が使用するのと同じフェンスでフィルタリングしてください(四分位値そのものでフィルタリングしないでください — Q1 と Q3 の間の範囲でフィルタリングすると、有効なデータの 4 分の 1 が両側で破棄されます)。
q1 = TIPS["total_bill"].quantile(0.25)
q3 = TIPS["total_bill"].quantile(0.75)
iqr = q3 - q1
filtered = TIPS[(TIPS["total_bill"] >= q1 - 1.5 * iqr) & (TIPS["total_bill"] <= q3 + 1.5 * iqr)]
sb.boxplot(x=filtered["total_bill"])
plt.show()
代わりに外れ値を上限処理(ウィンザー化)するには — すべての行を保持しながら、極端な値をフェンスまで引き寄せます — clip を使用します。
capped = TIPS["total_bill"].clip(lower=q1 - 1.5 * iqr, upper=q3 + 1.5 * iqr)
sb.boxplot(x=capped)
plt.show()
出力:
どちらの操作もデータを変更します。削除すると 9 件の最大の請求が完全に取り除かれ、上限処理するとそれらが 40.30 に書き換えられます。これらの値に不信感を抱く理由や、それらを制限する理由がある場合に使用してください — そして、単によりクリーンなチャートが欲しかっただけなら、showfliers=False に戻って、データはそのままにしておいてください。