What is Seaborn?
Pythonの可視化パッケージにはいくつかありますが、そのうちの一つに Seaborn があります。
代表的なパッケージとしては以下があります。
- Matplotlib: Matplotlib: Python plotting — Matplotlib 3.1.2 documentation
- Seaborn: seaborn: statistical data visualization — seaborn 0.9.0 documentation
- Dash (Plotly): Modern Analytic Apps for the Enterprise – Plotly
- Bokeh: <no title> — Bokeh 1.4.0 documentation
それぞれにユニークな特徴がありますが、Seaborn は 比較的に低級なパッケージである Matplotlib のラッパーになっていて、簡単にキレイなVizをつくれるのがうれしいです。
また、最近のパッケージにはほとんど導入されていると思いますが、列指向の DataFrame を前提に作られているのが特に気に入っています。
BIツールのTableauも列指向のデータが前提ですね。
Seaborn の ドキュメントには列指向データを以下のよう簡潔で分かりやすく表現しています。
(seaborn.lineplot の API reference より抜粋)
Parameters:
data : DataFrame
Tidy (“long-form”) dataframe where each column is a variable and each row is an observation.
データサイエンティストは Tidy なデータは大好物ですが、Messy なデータはちょっと。。。という感じですよね。
ちなみにTidyデータの構造に関する資料は以下のペーパーが気に入ってます。
Lineplot でハマった点
本題ですが、あるIoTデバイスの加速度データを周波数解析し、各周波数帯ごとのスペクトルパワーを可視化した際に、
その凡例が正しく表示されない挙動でハマりました。
前提条件は以下です。
- Seaborn==0.9.0
- 入力データフレーム (df_filter_bank)
(sampling_at: 時刻, Period: 波長(周波数の逆数で、単位はhour), PSD: スペクトルパワー)
上記条件下で以下のコードを実行しました。
df_plot = df_filter_bank.loc[df_filter_bank['Period'].isin([2.0, 4.0, 8.0, 16.0])] fig, ax = plt.subplots(figsize=(20, 8)) sns.lineplot(data=df_plot, x=df_plot.index, y='PSD', hue='Period', ax=ax) fig.show()
上記コードを補足すると、波長が2, 4, 8, 16 時間のデータを抽出し、それらを個別にlineplot で描画するという単純なものです。
結果は以下のようになりました。
Vizの凡例(legend)に注目してください。プロットする波長は4つの組合せ(2, 4, 8, 16 時間)のはずなのに、
結果はなぜか(0, 5, 10, 15, 20)となっています。値が違うどころか、個数すら違います。
hue に指定したデータ型がNumeric が原因なのではと思い、文字列型にcastしたところ、以下のエラーが。。。
AttributeError: 'str' object has no attribute 'view'
解決した方法
以下のGithubのIssueに情報がありました。
詳細はIssueを読んで頂ければ分かると思いますが、数値型データをhueとして使う場合には、一旦Tex形式の文字列にするという割とトリッキーな方法が紹介されてました。
Matplotlib にはTex形式で数式記述ができる機能が公開されていて、それを利用しているんですね。
Writing mathematical expressions — Matplotlib 3.1.2 documentation
実際、実行コードを以下のようにすると正しい挙動になりました。
df_plot = df_filter_bank.loc[df_filter_bank['Period'].isin([2.0, 4.0, 8.0, 16.0])] # 以下を追加 df_plot['Period'] = ["$%s$" % x for x in df_plot['Period']] fig, ax = plt.subplots(figsize=(20, 8)) sns.lineplot(data=df_plot, x=df_plot.index, y='PSD', hue='Period', ax=ax) fig.show()
さいごに
Lineplot をつくる際には hue に数値型データを利用したいことは結構あると思います。Seaborn を上手く改修できるのが一番ですが、この記事ではちゃちゃっと改修するための方法を紹介しました。