Python

Python seaborn チュートリアル プロット機能 統計的関係の可視化(2)

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

折れ線グラフによる連続性の強調

散布図は非常に効果的であるが、普遍的に最適な視覚化ではない。データセットの特性や、プロットはタスク・課題に合わせて、表現を適応させるべきである。

データセットによって、時間に関係した変数が変化する関数や、同様に連続した変数の変化を理解したい場合、折れ線グラフを描くのが良い選択である。seabornでは、lineplot()関数で実現できるが、直接でもrelplot()でも、 kind=”line “を設定することで実現できる。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

df = pd.DataFrame(dict(time=np.arange(500), value=np.random.randn(500).cumsum()))
g = sns.relplot(x="time", y="value", kind="line", data=df)
g.fig.autofmt_xdate()

plt.show()

lineplot() は、ほとんどの場合 y を x の関数として描画しようとしていることを想定しているため、デフォルトの動作は、プロットする前に x の値でデータをソートする。(これは無効できる。)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

df = pd.DataFrame(np.random.randn(500, 2).cumsum(axis=0), columns=["x", "y"])
sns.relplot(x="x", y="y", sort=False, kind="line", data=df)

plt.show()

集計と不確実性の表現

より複雑なデータセットでは、x変数の同じ値に対して複数の測定値を持つことになる。seabornのデフォルトの動作は、平均値とその周りの95%信頼区間をプロットすることで、各x値での複数の測定値を集約することである。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", kind="line", data=fmri)

plt.show()

信頼区間はブートストラップを使って計算できるが、これは大きなデータセットでは時間がかかる。そのため、信頼区間を無効にできる。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", ci=None, kind="line", data=fmri)

plt.show()

もう一つの良い方法は、特に大きなデータでは、信頼区間の代わりに標準偏差をプロットすることで、各タイムポイントでの分布の広がりを表現することである。

集約を完全にオフにするには、推定パラメータを None に設定する。 これは、データが各ポイントで複数のオブザベーションを持つ場合、奇妙な効果を出すことがある。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", estimator=None, kind="line", data=fmri)

plt.show()

セマンティックマッピングを用いたデータのサブセットのプロット

lineplot() 関数は scatterplot() と同じ柔軟性を持っている。プロット要素の色相、サイズ、スタイルを変更することで、追加変数(最大3つ)を表示できます。これは scatterplot() と同じ API を使用する。

lineplot() でセマンティクスを使用することは、データの集約のされ方を決定することにもなる。例えば、2つのレベルを持つ色相セマンティックを追加すると、プロットは2つの線とエラーバンドに分割され、それぞれがデータのどの部分集合に対応しているかを示すために色付けされる。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", hue="event", kind="line", data=fmri)

plt.show()

線分プロットにスタイルセマンティックを追加すると、デフォルトでは線内のダッシュのパターンが変更される。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", hue="region", style="event", kind="line", data=fmri)

plt.show()

しかし、各観測で使用されたマーカーによってサブセットを識別でき、ダッシュと一緒に、またはダッシュの代わりに使用できる。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", hue="region", style="event", dashes=False, markers=True, kind="line", data=fmri)

plt.show()

散布図と同様に、複数のセマンティクスを使用した折れ線グラフの作成には注意が必要である。時には有益な情報を提供するが、解析や解釈が難しいこともある。しかし、1つの追加変数の変化だけを調べる場合でも、線の色とスタイルの両方を変更すると便利である。これは、白黒に印刷したり、色盲の人が見たときに、プロットをより見やすくできる。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", hue="event", style="event", kind="line", data=fmri)

plt.show()

反復測定データを扱う場合(複数回サンプリングされた単位がある場合)、意味論で区別せずに、各サンプリング単位を別々にプロットすることもできる。これにより、凡例が乱雑になるのを避けることができる。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

fmri = sns.load_dataset("fmri")
sns.relplot(x="timepoint", y="signal", hue="region", units="subject", estimator=None, kind="line", 
            data=fmri.query("event == 'stim'"))

plt.show()

lineplot() でのデフォルトのカラーマップと凡例の扱いも、色相の意味がカテゴリ的か数値的かに依存する。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

dots = sns.load_dataset("dots").query("align == 'dots'")
sns.relplot(x="time", y="firing_rate", hue="coherence", style="choice", kind="line", data=dots)

plt.show()

色相変数が数値であるにもかかわらず、線形のカラースケールではうまく表現できないことがある。ここでは、色相変数のレベルが対数的にスケーリングされる。リストや辞書を渡すことで、各行に特定の色の値を与えることができる。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

dots = sns.load_dataset("dots").query("align == 'dots'")
palette = sns.cubehelix_palette(light=.8, n_colors=6)
sns.relplot(x="time", y="firing_rate", hue="coherence", style="choice", palette=palette, kind="line", data=dots)

plt.show()

または、カラーマップの正規化方法を変更できる。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

dots = sns.load_dataset("dots").query("align == 'dots'")
from matplotlib.colors import LogNorm
palette = sns.cubehelix_palette(light=.7, n_colors=6)
sns.relplot(x="time", y="firing_rate", hue="coherence", style="choice", hue_norm=LogNorm(), kind="line",
            data=dots.query("coherence > 0"))
            
plt.show()

3つ目のセマンティック、サイズで線の幅が変わる。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

dots = sns.load_dataset("dots").query("align == 'dots'")
sns.relplot(x="time", y="firing_rate", size="coherence", style="choice", kind="line", data=dots)

plt.show()

サイズ変数は通常数値だが、カテゴリ変数を線の幅でマッピングすることも可能である。その際には、”太い”線と “細い”線を区別するのは難しいため注意が必要。ただし、線が高周波数の変動を持つ場合には、ダッシュは知覚しにくいため、異なる幅を使用することがより効果的な可能性がある。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

palette = sns.cubehelix_palette(light=.7, n_colors=6)
dots = sns.load_dataset("dots").query("align == 'dots'")
sns.relplot(x="time", y="firing_rate", hue="coherence", size="choice", palette=palette, kind="line", data=dots)

plt.show()

日付データでのプロット

折れ線グラフは、実際の日付と時刻に関連付けられたデータを視覚化するためによく使用される。これらの関数は元のフォーマットでデータを基礎となるmatplotlib関数に渡すので、日付を目盛りラベルでフォーマットするmatplotlibの機能を利用できる。(フォーマットはすべてmatplotlibで行われなければならず、詳細な動作についてはmatplotlibのドキュメントを参照すること)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="darkgrid")

df = pd.DataFrame(dict(time=pd.date_range("2017-1-1", periods=500), value=np.random.randn(500).cumsum()))
g = sns.relplot(x="time", y="value", kind="line", data=df)
g.fig.autofmt_xdate()

plt.show()