Python

Python seaborn チュートリアル プロット機能 データの分布を可視化 (1)

原文のドキュメントはこちらから。

データを分析、モデル化の初期段階では、変数の分布を理解する必要がある。分布を可視化することで、多くの重要な疑問の答えを見つけることができる。(観測値・結果はどの程度の範囲をカバーするか、中心の傾向、傾きはあるか、二峰性・様相性はあるか、外れ値の存在、他の変数で定義された部分集合でも変化するかなど)

分布モジュールには、前述の疑問の答えるように設計されたいくつかの関数がある。軸レベルの関数は、histplot()、kdeplot()、ecdfplot()、およびrugplot()である。これらは、図レベルのdisplot()、 jointplot()、およびpairplot()関数の中にまとめられている。

分布の可視化はいくつかの異なるアプローチがあり、それぞれに利点と欠点があるため、要素を理解し、特定の目的に最適なアプローチを選択できるようにすることが重要である。

一変量ヒストグラムのプロット

分布を可視化するための最も一般的なアプローチはヒストグラムである。これは displot() のデフォルトのアプローチで、 histplot() と同じ基礎となるコードを使用している。ヒストグラムは、データ変数を表す軸が離散的なビンの集合に分割され、各ビン内にあるオブザベーションのカウントが、対応するバーの高さを使って表示される棒グラフである。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm")

plt.show()

このプロットは、flipper_length_mm変数について説明している。例えば、最も一般的なフリッパーの長さは約195mmである事がわかる。分布は二峰性のように見えるので、この1つの数値はデータをよく表していない。

ビンサイズの選択

ビンのサイズは重要なパラメータである。間違ったビンのサイズを使用すると、データの重要な特徴を不明瞭にする、ランダムな分散から見かけの特徴を作成するなど、誤解を招く可能性がある。デフォルトでは、displot() / histplot() は、データの分散とオブザベーションの数に基づき、デフォルトのビン・サイズを選択する。しかし、自動アプローチは、データの構造に関する特定の仮定に依存するため、過度に依存すべきではない。分布の印象が、異なるビン・サイズの間で一貫していることを常にチェックするべきである。サイズを直接選択するには、binwidthパラメータを設定する。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm", binwidth=3)

plt.show()

他の状況では、サイズよりもビンの数を指定した方が意味がある可能性がある。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm", bins=20)

plt.show()

デフォルトのビンのサイズで失敗する一つの例として、変数が比較的小さな整数値を取る場合がある。この場合、デフォルトのビンの幅が小さすぎ、分布の中に隙間ができることがある。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

tips = sns.load_dataset("tips")
sns.displot(tips, x="size")

plt.show()

1つのアプローチは、配列をbinsに渡し正確なビンを指定することが考えられる。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

tips = sns.load_dataset("tips")
sns.displot(tips, x="size", bins=[1, 2, 3, 4, 5, 6, 7])

plt.show()

これはdiscrete=Trueと設定することでも実現できる。データセット内の一意の値を、対応する値を中心にしたバーで表現するビンブレークを選択する。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

tips = sns.load_dataset("tips")
sns.displot(tips, x="size", discrete=True)

plt.show()

ヒストグラムのロジックを使用して、カテゴリカル変数の分布を可視化ができる。離散ビンは、カテゴリ変数に対して自動的に設定されるが、軸のカテゴリ性を強調するためにバーをわずかに “縮小” するのも便利である。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

tips = sns.load_dataset("tips")
sns.displot(tips, x="day", shrink=.8)

plt.show()

他の変数に対する条件付け

変数の分布を理解した場合、次のステップとして、分布の特徴がデータセット内の他の変数間で異なるかを確認することがある。例えば、上で見たフリッパーの長さの二峰性の分布は何を表すか。displot() と histplot()は、hueを使った条件付き部分集合のサポートを提供している。ある変数をhueに代入すると、ユニークな値に対して別々のヒストグラムを色で区別し描画する。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm", hue="species")

plt.show()

デフォルトでは、異なるヒストグラムを「重ねて」描画し、場合によって区別が難しい場合がある。1つのオプションとして、ヒストグラムの視覚的表現を棒グラフから「ステップ」グラフに変更することができる。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm", hue="species", element="step")

plt.show()

また、各棒グラフを重ねる代わりに、棒グラフを「重ねる」ことも、垂直方向に移動させることもできる。このプロットでは、完全なヒストグラムのアウトラインは、単一の変数だけでプロットと一致する。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm", hue="species", multiple="stack")

plt.show()

積層ヒストグラムは、変数間の部分と全体の関係を強調するが、他の特徴を不明瞭にすることができる(例えば、Adelieの分布のモードを決定するのは困難である)。もう1つのオプションは、棒を「かわす」ことで、棒を水平方向に移動させ、その幅を狭くする。これにより、重なりがなく、バーの高さが同等であることが保証される。これは、カテゴリカル変数のレベル数が少ない場合にのみ有効である。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm", hue="sex", multiple="dodge")

plt.show()

displot()は図レベルの関数であり、FacetGrid上に描画されるので、2番目の変数を色相ではなく(あるいは色相に加えて)colやrowに代入することで、個々の分布を別々のサブプロットに描画することも可能。これは、各サブセットの分布をよく表すが、直接比較を描くのがより難しくなる。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm", col="sex", multiple="dodge")

plt.show()

これらのアプローチはどれも完璧ではないが、比較のタスクにより適したヒストグラムの代替品をすぐに可視化できる。

正規化ヒストグラム統計量

実行前に注意すべきもう1つのポイントは、サブセットがオブザベーションの不均等な数を持つとき、カウントの観点からそれらの分布を比較することは理想的とは断定できない。1つの解決策として、stat パラメーターを使用してカウントを正規化することが挙げられる。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm", hue="species", stat="density")

plt.show()

デフォルトでは、正規化は分布全体に適用されるため、単に棒グラフの高さを再スケーリングすることとなる。common_norm=Falseと設定することで、各サブセットは独立して正規化される。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm", hue="species", stat="density", common_norm=False)

plt.show()

密度正規化は、バーの面積の合計が1になるようにバーをスケーリングする。その結果、密度軸は直接解釈できない。もう1つのオプションは、棒グラフの高さの和が1になるように正規化することである。 これは、変数が離散的な場合に最も理にかなっているが、すべてのヒストグラムのオプションである。

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

penguins = sns.load_dataset("penguins")
sns.displot(penguins, x="flipper_length_mm", hue="species", stat="probability")

plt.show()