LoginSignup
0
0

More than 1 year has passed since last update.

matplotlibの箱ひげ図でもx軸を間隔尺度にしたい!

Last updated at Posted at 2021-09-09

 分布を含めてデータを一覧したい時、箱ひげ図はかなり強力な武器になります。

 しかし、基本的には箱ひげ図は、各データ間の大小をグラフに表しません(名義尺度)。順序を揃えることはあるかもしれませんが、それでもあくまで順序尺度どまりです。場合によっては、x軸同士の関係も見たいということがあるかもしれません。

やってみる

 まず、以下のようなデータを考えます。あるゲームのランキングを国別にまとめたものです。

image.png

 コードは次のような感じになります。(以下、importとかは省略)

fig,ax = plt.subplots()
ax.boxplot(distributions)
ax.set_xticklabels(countries)
plt.show()

 例えば、国別に人口データあった場合、x軸を人口にしたいと考えます。boxplotでは、positionsを指定することによってできます。

fig,ax = plt.subplots()
ax.boxplot(distributions, positions=populations) //positions
plt.show()

 結果

image.png

 x軸のオーダーが大きすぎるため、箱ひげが針みたいになってしまいました。あと中国の人口がすごすぎて、それがなくとも純粋に見づらいです。箱の太さはデフォルトでは0.5 に指定されているため、データに合わせて調整が必要になりそうです。今回は、人口の方にlogをかけたり標準化をしたりして調整してみます。(箱の太さを調整したい場合、widhtsというパラメータで操作することができます。)

log_populations = np.log(populations)
fig,ax = plt.subplots()
ax.boxplot(distributions,positions=log_populations)
xfloor = math.floor(np.min(log_populations))
xceil = math.ceil(np.max(log_populations))
plt.xlim(xfloor,xceil)
plt.show()

image.png

 見づらい!!

 箱ひげ図の横軸を自由にしてしまうと、このようなオーバーラップがあるから使われなかったのですね。あと、元々は単なる見栄えの問題であったはずの箱の太さが、まるで何か統計的意味を持ってしまうかのように見えてしまいます。これはグラフとしてあまりよくないです。

 ちなみに、分布x分布というデータであった場合、二次元箱ひげ図というのも考案されていますが、同様の問題がある(オーバーラップのリスクが高い)ので実用的ではないようです。

悪あがき

 とりあえずx軸がすごいことになっているので直します。

log_populations = np.log(populations)
fig,ax = plt.subplots()
ax.boxplot(distributions,positions=log_populations)
xfloor = math.floor(np.min(log_populations))
xceil = math.ceil(np.max(log_populations))
ax.set_xticks(range(xceil))
ax.set_xticklabels(range(xceil))
plt.xlim(xfloor,xceil)
plt.show()

image.png

 あと棒も微妙に細くします。

log_populations = np.log(populations)
widths = np.ones(len(distributions))*0.1
fig,ax = plt.subplots()
ax.boxplot(distributions,positions=log_populations,widths=widths)
xfloor = math.floor(np.min(log_populations))
xceil = math.ceil(np.max(log_populations))
ax.set_xticks(range(xceil))
ax.set_xticklabels(range(xceil))
plt.xlim(xfloor,xceil)
plt.show()

image.png

 今更ですが、どのデータがどこの国のものかわかりづらいので、グラフ上にラベルを表示することにします。実はけっこうこれが面倒くさくて、boxplotの命令一発でやるのが難しいので、for文の中で処理することになります。

log_populations = np.log(populations)
fig,ax = plt.subplots()
for d,c,l in zip(distributions,countries,log_populations):
    ax.boxplot(d,positions=[l],widths=[0.1]) # リストで指定することに注意
    pos = (l+0.1,np.median(d))
    ax.annotate(c,pos)
xfloor = math.floor(np.min(log_populations))
xceil = math.ceil(np.max(log_populations))
ax.set_xticks(range(xceil))
ax.set_xticklabels(range(xceil))
plt.xlim(xfloor,xceil)
plt.show()

image.png

 うーん、最大限努力したけど、オーバーラップがある以上、やっぱり見づらい。

結論

 箱ひげ図のx軸を間隔尺度にするのは、技術的には可能ですが、

  • オーバーラップがあると根本的に見づらい
  • 箱の太さに統計的な意味があるように見えてしまう

 というデメリットがあるので、あまり良いソリューションではなさそうです。ラベル別の分布を一覧するなら強力なツールなので、使い分けが重要ですね。

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0