バイオリン図で数値データの分布を可視化する

今更ながらデータの分布を比較する図法「バイオリン図(violin plot)」の存在を知りました。

バイオリン図とは

f:id:mickey24:20190621232457p:plain

↑のような図です。数値データの分布の可視化や比較に使います。データ分布の描画にはカーネル密度推定が用いられています。

Matplotlibではviolinplot()関数を使うことで描画できます。

matplotlib.pyplot.violinplot(
    dataset,
    positions=None,
    vert=True,
    widths=0.5,
    showmeans=False,
    showextrema=True,
    showmedians=False,
    points=100,
    bw_method=None,
    *,
    data=None)

バイオリン図と箱ひげ図を比較してみる

似たような目的で用いられる図として「箱ひげ図(box plot)」があります。ここでは試しに数値データの分布をバイオリン図と箱ひげ図で描画して比較してみましょう。

まずは分布比較用として3種類の人工データ(単峰性、二峰性、一様分布)を作ってみます。

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(24)

data = [
    # 単峰性
    np.random.normal(scale=2, size=1000),
    # 二峰性
    np.r_[
        np.random.normal(loc=-2, size=500),
        np.random.normal(loc=2, size=500),
    ],
    # 一様分布
    np.random.uniform(-5, 5, size=1000),
]

各データのヒストグラムを個別に描画して分布を確認してみます。

_, axes = plt.subplots(nrows=len(data), ncols=1, figsize=(5, 10))
for i, x in enumerate(data):
  axes[i].hist(x, bins='auto')
plt.show()

f:id:mickey24:20190621232437p:plain

想定通りの分布のデータが作られたことが確認できました。

では、箱ひげ図で各データの分布を比較してみます。

plt.boxplot(data)
plt.show()

f:id:mickey24:20190621232508p:plain

二峰性や一様分布などの特徴が完全に消え、あたかも各分布が同じ特徴を持った分布であるかのように見えます。そもそも多峰性の分布や異なる形の分布を箱ひげ図で比較すること自体よくないですが、ある程度データの分布の形を仮定したまま箱ひげ図から描き始めてしまうと、今回のような図によって誤解を招く可能性があるので気をつけましょう。

今度はバイオリン図で分布を図示してみます。

plt.violinplot(data, showmedians=True)
plt.show()

f:id:mickey24:20190621232457p:plain

箱ひげ図と違い、各データの分布がそのまま図に現れているため、より正確な比較ができます。強いて言えば、カーネル密度推定により一様分布の両端が実際よりも滑らかに描画されているため、カーネル密度推定が苦手とする形の分布を扱う場合は気をつけたほうが良いでしょう。

バイオリン図の欠点

バイオリン図の欠点について考えてみます。

  • データ分布はカーネル密度推定プロットによって滑らかに描画されるため、実際にはデータが存在しない範囲にもあたかもデータが存在しているかのように見えることがある。
  • ひとつのバイオリン図内にある各カーネル密度推定プロットの面積は同一ではない。値が取りうる範囲が大きかったりデータが一様に分布していると、描画されるカーネル密度推定プロットの面積が大きくなるため錯覚が起こる可能性がある。
  • 知名度が低い(Wikipedia談)。しかし割と直感的に分かりやすい図法ではあると思われるので、知名度が低くても人から理解されにくいということはなさそう?

まとめ

数値データの分布を可視化・比較したい場合は、バイオリン図を使ってみましょう。単峰性のデータかつ四分位数や外れ値が重要な場合は箱ひげ図でもいいかもしれませんが、単峰性データの歪み具合を見たい程度であればバイオリン図にしてしまってもいいのではないかと思います。

参考文献