DATA-SCIENCE

Pythonの可視化パッケージ Seaborn の Lineplot の凡例でハマったこと

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データの構造に関する資料は以下のペーパーをご参照いただくと分かり易いと思います。
https://vita.had.co.nz/papers/tidy-data.pdf

 

Lineplot でハマった点

あるIoTデバイスの加速度データを周波数解析し、各周波数帯ごとのスペクトルパワーを可視化した際に、その凡例が正しく表示されない挙動でハマりました。前提条件は以下です。

  • Seaborn==0.9.0
  • 入力データフレーム (df_filter_bank)

f:id:gri-blog:20200123195817p:plain
(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 で描画するという単純なものです。
結果は以下のようになりました。

f:id:gri-blog:20200123200454p:plain

Vizの凡例(legend)に注目してください。プロットする波長は4つの組合せ(2, 4, 8, 16 時間)のはずなのに、結果はなぜか(0, 5, 10, 15, 20)となっています。値が違うどころか、個数すら違います。

hue に指定したデータ型がNumeric が原因なのではと思い、文字列型にcastしたところ、以下のエラーが…

AttributeError: 'str' object has no attribute 'view'

 

解決した方法

以下のGithubのIssueに情報がありました。
github.com

詳細は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() 

 

f:id:gri-blog:20200123212657p:plain

 

さいごに

Lineplot をつくる際には hue に数値型データを利用したいことは結構あると思います。Seaborn を上手く改修できるのが一番ですが、この記事では手早く改修するための方法をご紹介しました。皆さんもSeabornを活用される際に、参考にしてください。

 

この記事をシェアする