HOWTO · Seaborn
Seaborn BoxPlot
このチュートリアルでは、Python で seaborn モジュールを使用して箱ひげ図を作成する方法を示します
このページの内容
seaborn.boxplot()を使うと、数値データの分布を要約したり、カテゴリ間で値を比較したりできます。Seabornが各軸にどの変数を割り当てるか分かるよう、データ列を明示的に指定します。箱ひげ図は中央値と四分位範囲(IQR)を示します。既定のひげの規則では、ひげは箱から1.5 IQR以内にある最も遠い観測値まで伸び、それより離れた観測値は個別の点として表示されます。
この記事のすべての例は同じ要素を使います。箱はデータの中央半分を覆い、その中の線が中央値、ひげは選択した規則に基づく範囲を示し、ひげの外側の点は個別に描画されます。
1つの分布を箱ひげ図で表示する
測定値をDataFrameの列に格納し、その列をyに割り当てます。こうするとデータの役割が明確になり、グラフの軸にも分かりやすいラベルが付きます。次の例では値を固定しているため、実行するたびに同じ入力データが使われます。
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
data = pd.DataFrame({"Score": [12, 14, 15, 16, 18, 19, 21, 24]})
ax = sns.boxplot(data=data, y="Score")
ax.set_title("Score distribution")
plt.show()
箱の中の線は中央値を示します。箱は第1四分位数から第3四分位数までを表すため、その高さには観測値の中央半分が含まれます。箱が長いほど、データの中央部分のばらつきが大きいことを示します。ひげは選択した規則に基づく範囲を示し、必ずしも最小値や最大値まで届くとは限りません。
カテゴリごとに分布を比較する
カテゴリをxに、数値の測定値をyに割り当てると、各カテゴリに個別の箱が表示されます。このデータセットでは、各箱が1つのQuantityの値におけるPriceを要約します。hue="Product"を追加すると、カテゴリが製品グループに分けられ、同じ数量で製品間を比較しやすくなります。
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
data = pd.DataFrame(
{
"Quantity": [5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8],
"Price": [9, 10, 15, 16, 13, 14, 15, 18, 11, 12, 14, 15, 16, 17, 18, 19],
"Product": ["A", "A", "A", "A", "B", "B", "B", "B"] * 2,
}
)
ax = sns.boxplot(data=data, x="Quantity", y="Price", hue="Product")
ax.set_title("Price by quantity and product")
plt.show()
追加のグループ分けが比較したい内容に役立つ場合にhueを使います。グループが多いと箱が混み合うことがあります。分布を読み取りやすくするには、カテゴリを絞るか、プロットを分けて表示してください。
ストリッププロットで個々の観測値を表示する
箱ひげ図はデータを要約統計量にまとめます。個々の観測値も読者に見せたい場合は、seaborn.stripplot()を重ねます。両方のレイヤーで同じ軸とデータの割り当てを使い、値の近い点が完全に重ならないよう、水平方向に少しジッターを加えます。
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
data = pd.DataFrame({"Score": [12, 14, 15, 16, 18, 19, 21, 24]})
ax = sns.boxplot(data=data, y="Score", color="lightgray")
sns.stripplot(data=data, y="Score", color="darkred", jitter=0.15, ax=ax)
ax.set_title("Scores with individual observations")
plt.show()
箱は引き続き分布の要約を示し、各マーカーはデータの1行を表します。データセットが大きいと点が重なることがあるため、点が密集した領域を読みやすくするには、マーカーのサイズや透明度を調整します。
箱ひげ図をカスタマイズする
関連する値の範囲に注目するにはMatplotlibの軸範囲設定メソッドを使い、箱やひげの境界線の太さはlinewidthで、カテゴリの色はpaletteで調整できます。orientパラメーターはプロットの向きを指定します。たとえば、データの割り当てが適合する場合、orient="h"で横向きのプロットを指定できます。軸範囲を変えると表示される領域だけが変わります。重要な観測値が隠れないよう、範囲と目盛りを分かりやすく設定してください。
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
data = pd.DataFrame(
{
"Quantity": [5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8],
"Price": [9, 10, 15, 16, 13, 14, 15, 18, 11, 12, 14, 15, 16, 17, 18, 19],
"Product": ["A", "A", "A", "A", "B", "B", "B", "B"] * 2,
}
)
ax = sns.boxplot(
data=data,
x="Quantity",
y="Price",
hue="Product",
linewidth=2.5,
palette="Set2",
)
ax.set_ylim(8, 20)
ax.set_title("Customized price comparison")
plt.show()
パレットの色はhueで分けたグループに対応します。横向きの箱ひげ図にするには、カテゴリと測定値の割り当てを入れ替えてorient="h"を設定します。その場合、軸範囲にはset_ylim()ではなくset_xlim()を使います。
catplot()で箱ひげ図を作成する
図全体を扱うインターフェイスには、kind="box"を指定したcatplot()を使います。同じデータの明示的な割り当てを使えます。また、別の変数で比較を分けたい場合は、colやrowでパネルを作成できます。単一のプロットには軸単位のseaborn.boxplot()を使い、複数のパネルに分ける図にはcatplot()が便利です。
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
data = pd.DataFrame(
{
"Quantity": [5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8, 5, 6, 7, 8],
"Price": [9, 10, 15, 16, 13, 14, 15, 18, 11, 12, 14, 15, 16, 17, 18, 19],
}
)
grid = sns.catplot(data=data, x="Quantity", y="Price", kind="box")
grid.set_axis_labels("Quantity", "Price")
grid.fig.suptitle("Price by quantity")
plt.show()
catplot() は図全体を構築するため、単一の軸ではなくグリッドオブジェクトを返します。例のように、ax.set_title() を呼ぶ代わりにグリッドに対してラベルとタイトルを設定してください。
列が見つからないエラーの対処とひげの範囲の設定
すべてのマッピングは DataFrame の列名を指定するため、名前のスペルを間違えると何も描画される前に失敗します。次の呼び出しは、データに含まれない列 Scroe を求めています:
import pandas as pd
import seaborn as sns
data = pd.DataFrame({"Score": [12, 14, 15, 16, 18, 19, 21, 24]})
ax = sns.boxplot(data=data, y="Scroe")
呼び出しは次のエラーで終了します:
ValueError: Could not interpret value `Scroe` for `y`. An entry with this name does not appear in `data`.
列と正確に一致するよう名前を修正すれば(ここでは y="Score")、同じ呼び出しでプロットが描画されます。正しいスペルが分からない場合は data.columns を出力し、そこから名前をコピーしてください。このチェックは x、y、hue のいずれにも同様に適用されます。
ひげは読者が出会うもう 1 つの境界です。スコアに遠く離れた値 60 を追加すると、四分位数はほとんど動きません(第 1 四分位数 15、中央値 18、第 3 四分位数 21)。デフォルトの whis=1.5 では上のひげは 24 で止まり、60 はその外側に孤立した点として描画されます。whis をパーセンタイルのペアとして渡すと、ひげは代わりにデータのそのパーセンタイルまで伸びます:
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
scores = pd.DataFrame({"Score": [12, 14, 15, 16, 18, 19, 21, 24, 60]})
ax = sns.boxplot(data=scores, y="Score", whis=(0, 100))
plt.show()
whis=(0, 100) とすると、ひげは最小値 12 と最大値 60 まで届き、外側に残る点はなくなります。全範囲そのものが伝えたい内容でない限り、デフォルトを優先してください。伸ばしたひげは、極端な値がどれほど異例かを隠してしまいます。また、空の列ではエラーは発生しません。Seaborn は空の軸を返すため、データがパイプライン由来の場合は描画前に行数を確認してください。