plotly入門

Python Plotly入門⑤ ヒストグラム(Histogram)

2021年6月14日

今回はデータ分析の際にもっとも多く使うグラフの一つであるヒストグラムの作成方法を解説したいと思います。

plotlyを使うと、以下のようなインタラクティブなヒストグラムを1行や2行程度の簡単なコードで作成することが可能です。

公式HPの解説はこちらです。

Plotly Expressを使ったヒストグラムの作成

では、まずPlotly Expressを使ったヒストグラムの作成方法について簡単に解説します。

以下のようなデータを持っているとします。

Date	    スノーピーク
2019-06-04	-0.025937
2019-06-05	0.031803
2019-06-06	0.009315
2019-06-07	0.009946
2019-06-10	0.012662
  ...	      ...

plotly.expressをインポートします。

import plotly.express as px

あとは以下の1行でヒストグラムを描くことができます。

px.histogram(df, x='スノーピーク')

まず一つ目の引数には表示するpandasのデータフレームを渡します。

そして、xに表示したい列を渡します。

非常に簡単ですね。

これだけで以下のようなヒストグラムが表示されます。

カーソルを当てることで、各ビンの閾値や度数も見ることができます。

binの設定

デフォルトのビンだと結構少ないことも多いですよね。

そういった場合は、nbinsを指定します。

px.histogram(df, x='スノーピーク', nbins=80)

すると少し細かくなります。

複数データのヒストグラム

各正解ラベルごと特徴量の分布の違いを見るときなど、複数のデータを一つのヒストグラムに表示したい場合はよくあると思います。

その場合は以下のように書きます。

px.histogram(df_vertical, x='return', color='name', barmode='overlay')

plotly.expressを使う場合は表示したいデータを一つの列に設定してやる必要があります。

つまり、上記のdf_verticalという変数は以下のようにreturn列にすべてのリターンが入っており、name列で銘柄が分類されている形になっています。

                return         name
Date		
2021-05-28	0.009943	スノーピーク
2021-05-27	0.005626	スノーピーク
2021-05-26	-0.005594	スノーピーク
2021-05-25	0.047820	スノーピーク
2021-05-24	-0.008054	スノーピーク
...	...	...
2019-06-07	-0.006207	ANA
2019-06-06	0.005702	ANA
2019-06-05	-0.007290	ANA
2019-06-04	-0.017684	ANA
2019-06-03	0.012185	ANA

あと、注意点としてはbarmode="overlay"としないと1つ目のデータの上に2つ目のデータが積み重なってしまいます

これはクリティカルな間違いになってしまいますので気を付けましょう。

その結果、以下のようなヒストグラムが出来上がります。

密度ベースのヒストグラムを作成する

データの数が違う場合、以下のように度数だけを比較してもよくわかりません。

そういった場合に、密度で表示する必要がありますね。

その場合は、以下のようにhistnorm="probability"を引数として追加します(matplotlibではdensity=Trueですね)。

px.histogram(df_vertical_sub, x='return', color='name', 
       barmode='overlay', histnorm='probability')

こうすることにより、以下のように密度で表示されます。

スノーピークの方が歪度が大きいな、といった比較が可能になります。

box plotの追加

上に参考情報としてbox plot(箱ひげ図)を描画することができます

px.histogram(df_vertical, x='return', color='name', 
             barmode='overlay', histnorm='probability',
             marginal='box')

引数にmarginal="box"を追加します。

すると以下のようになります。

他にも、violin(violin plot)、rug(rug plot)などが指定できます。

plotly.graph_objectsを使ったヒストグラムの作成

続いて、plotly.expressではなくplotly.graph_objectsを使ってヒストグラムを作成する方法を解説します。

以下のようなデータがあるとします。

Date	       スノーピーク	   ANA
2019-06-04	-0.025937	-0.012038
2019-06-05	0.031803	0.018002
2019-06-06	0.009315	0.007344
2019-06-07	0.009946	-0.005670
2019-06-10	0.012662	0.006245
...	...	...
2021-05-25	0.008119	-0.007957
2021-05-26	-0.045638	0.029076
2021-05-27	0.005626	0.026111
2021-05-28	-0.005594	0.010444
2021-05-31	-0.009845	-0.002067

potly.graph_objectsでは、Histogram()を使います。

まず、potly.graph_objectsをインポートします。

import plotly.graph_objects as go

以下のようにgo.Histogram()でヒストグラムのデータを作成し、go.Figure()の引数として渡してやります。

data = go.Histogram(x=df['スノーピーク'], nbinsx=80)
fig = go.Figure(data)
fig.show()

ビンの数の設定はnbinsxで指定します(覚えにくいですよね…)。

複数データの表示

次に複数のデータのヒストグラムを作成します。

これも線グラフや散布図と同じで、データをリストの形で渡してやることで可能ですが、ここではadd_traceを使って行います。

データをどんどん追加していけるので便利です。

fig = go.Figure()
fig.add_trace(go.Histogram(x=df['スノーピーク'], nbinsx=80, 
                           opacity=0.5, name='スノーピーク',
                           histnorm='probability'))
fig.add_trace(go.Histogram(x=df['ANA'], nbinsx=80, 
                           opacity=0.5, name='ANA',
                           histnorm='probability'))
fig.update_layout(barmode='overlay')
fig.show()

以下のようなヒストグラムになります。

update_layoutでbarmodeをoverlayと指定しています。

これがないと、以下のグラフのように重ならないヒストグラムになります。

こちらの方がよければ、barmodeを指定しなくても大丈夫です。

なお、add_traceでは各データ個別の設定だけを行い、共通の設定については以下のようにupdate_tracesでまとめて行うことで、個別に設定する必要がなくなります。

fig = go.Figure()
fig.add_trace(go.Histogram(x=df['スノーピーク'], name='スノーピーク'))
fig.add_trace(go.Histogram(x=df['ANA'], name='ANA'))
fig.update_traces(nbinsx=80, opacity=0.5, histnorm='probability')
fig.update_layout(barmode='overlay')
fig.show()

binの設定

ビンの数を設定する場合はnbinsxでしたが、ここではビンの範囲、刻みを指定して作成します。

例えば、大きな外れ値があるデータだと以下のようになってしまいます。

もちろん、これで異常値に気づくことができますが、異常値でない場合は、そのほかの部分の分布が見たくなる場合もあります。

その場合は、xbinsに辞書形式でstart、end、sizeを指定することで対応できます。

fig = go.Figure()
fig.add_trace(go.Histogram(x=df['スノーピーク'], name='スノーピーク'))
fig.add_trace(go.Histogram(x=df['ANA'], name='ANA'))
fig.update_traces(xbins=dict(start=-0.15,
                             end=0.15,
                             size=0.005),
                  opacity=0.5)
fig.update_layout(barmode='overlay')
fig.show()

これでうまく、外れ値は一番上もしくは一番下のビンに入れてくれます(python側でデータをいじる必要がありません)。

その他

マーカーの色を変えたり、タイトルを付けたり、x軸、y軸のラベルを設定する方法は線グラフや散布図などと可能です。

好みに応じて、やりすぎないように肉付けしましょう。

fig = go.Figure()
fig.add_trace(go.Histogram(x=df['スノーピーク']*100, 
                           marker=dict(color='#6495ed'),
                           name='スノーピーク'))
fig.add_trace(go.Histogram(x=df['ANA']*100, 
                           marker=dict(color='#ff7f50'),
                           name='ANA'))
fig.update_traces(xbins=dict(start=-15,
                             end=15,
                             size=0.25),
                  opacity=0.5,
                  histnorm='probability'
                  )
fig.update_layout(barmode='overlay',
                  title='スノーピーク vs ANA',
                  xaxis=dict(title='日次リターン(%)'),
                  yaxis=dict(title='density'))
fig.update_layout(legend=dict(yanchor="top",
                              y=0.95,
                              xanchor="right",
                              x=0.97))
fig.show()

fig.update_layout(legend=dict(...))として凡例の場所を変えています。

レイアウトの設定については別途詳しく解説したいと思いますが、xanchor、yanchorで原点を決め、そこから相対的な位置を指定します。

plotly.figure_factoryを使った分布のプロット

plotly.figure_factoryを使うと分布に対してカーネル密度推定を使ってフィッティングした結果を表示してくれます。

まず、plotly.figure_factoryをインポートします。

import plotly.figure_factory as ff

figure_factoryのcreate_displotというメソッドを呼び出します。

1つ目の引数はデータで、リストの形で渡してやります。

2つ目の引数はデータ名です。

あとは、bins_sizeでビンのサイズを指定しています。

fig = ff.create_distplot([df for c in df.columns], df.columns, bin_size=.0025)
fig.show()

これだけで、以下のようなグラフが作成されます。

色を変えたりすることも当然可能です。

この場合はそれほどメリットは感じられないかもしれませんが、状況によっては分布のプロットがあった方が比較しやすいですね。

まとめ

今回はplotlyによるヒストグラムの作成方法を見てきました。

私はこれ以外にはあまり凝った使い方をしないので基本的な使い方の解説だけでしたが、他にも便利な設定があれば随時更新していきたいと思います。

次は棒グラフです!

-plotly入門
-, ,