7.3 より複雑なデータを把握するには
しかし, 例えば,
x
,y
のヒストグラムを, 棒グラフのように並べるのではなくオーバーレイさせたい. さらに変数z
でグループ分けして個別に描きたい- ラインプロットを
z
, でグループ分けして個別に描きたい - 散布図を,
z
,w
の違いが分かるように色分けして描きたい.
と言うふうにより細かく分けてデータを見たい時, pandas
のプロット機能だけでは困難です. pandas
のグラフは matplotlib
を使って描かれているため, matplotlib
を使えば細かい調整も可能です. これは, 例えばmatplotlib
より「便利な」グラフツールとしてよく紹介される seaborn
にも見られる傾向です. seaborn
の傾向として, 2つ以上の複数列のデータを同時にプロットする際には便利であることが多いですが, 一方でグループ化の機能や細かい調整となると, やはり書くのが大変になります.
そこで, plotnine
を紹介します. たとえばヒストグラムの場合, 以下のように書くことができます. 最初に読み込みと, 画像をpdfで出力する際に日本語を文字化けせず埋め込むための設定をします18.
import seaborn as sns
from plotnine import *
theme_set(
theme_grey(base_family="Noto Serif CJK JP")
)
plotnine
でグループごとのグラフを描くには, データフレームをロング形式にする必要があります.
ggplot(df.melt(id_vars=['z', 'w']),
aes(x='value', group='variable', fill='variable')
) + geom_histogram(
bins=10, position='identity', alpha=.5
) + facet_wrap('z', scales='free_y') + labs(
title='plotnine によるヒストグラム')
同様のことを pandas
, seaborn
, matplotlib
を使って書くと, おそらく seaborn
と matplotlib
を組み合わせて書くのが一番簡単です19. しかし, これは参照透過性の点でよくありません. また, ヒストグラムのビン幅および位置がずれます. 同じビンに調整するとさらに記述が長くなるため今回は省略します.
fig, axes = plt.subplots(ncols=df['z'].unique().shape[0], sharex=True)
for c in ['x', 'y']:
for ind_z, z in enumerate(df['z'].unique()):
sns.distplot(df.loc[lambda d: d.z==z, c],
bins=10, kde=False, label=c, ax=axes[ind_z])
fig.suptitle('seaborn によるヒストグラム')
plt.legend()
それぞれの描き方で作成したグラフは図 7.1のようになります.


図 7.1: (左) plotnine
によるグラフ (右) seaborn
によるグラフ
(2), (3) についても plotnine
とそれ以外を比較してみます.
(2) では, pandas
は色分けができませんが, 一方で行インデックスをx軸に暗黙に指定できました. plotnine
や seaborn.lineplot()
では後者ができないため, 入力データの加工が必要になります. seaborn
は FacetGrid
を利用することになります. seaborn
は不具合が多いため, plotnine
の結果のみ 図 7.2 に掲載します.
ggplot(df.reset_index().melt(id_vars=['index', 'z', 'w']),
aes(x='index', y='value', group='variable', color='variable')
) + geom_line() + facet_wrap('z')
sns.FacetGrid(data=df.reset_index().melt(id_vars=['index', 'z', 'w']),
col='z', hue='variable'
).map(sns.lineplot, 'index', 'value').add_legend()

図 7.2: plotnine
による折れ線グラフ
(3) もまた, pandas
のプロットでは大変なので seaborn
を使います. 出力結果は図7.3です. なお, 本稿で使用している seaborn
のバージョンでは不具合により変数名を指定できないため, 冗長な書き方になります.
ggplot(df, aes(x='x', y='y', color='z', shape='w')) + geom_point()
sns.scatterplot(x='x', y='y',
hue=df.z.values.tolist(),
style=df.z.values.tolist(), data=df)


図 7.3: plotnine
(上) と seaborn
(下) による散布図
これは,
plotnine
のテーマの多くがデフォルトでフォントをDejaVu Sans
で上書きしてしまうためです. よって,None
を指定することでrcParams
に設定した日本語フォントを上書きしないようにしています. ここでは Ubuntu の標準日本語フォントであるNoto Serif CJK JP
を指定していますが, Windows ならYu Gothic
, Mac ならHiragino Sans
などが標準フォントの1つです.↩︎seaborn.FacetGrid()
という分割してグラフを描くための関数がありますが, さらにヒストグラムを色分けするという動作をseaborn
が想定していないため使えません.↩︎