python でグラフを可視化する時,matplotlib
使いづらくないですか?覚えにくいし,毎回ググってる気がします.
あとデザインもダサいので全然好きになれません.(デザインに関してはseaborn を使えば綺麗ですが,結局matpotlibで書くことになるので覚えづらいことには変わりないです・・・)
ただしmatplotlib
は画像の表示 には強いです.そういう時は僕も使います.
プロmatplotliberの方がこの記事を見てくださって,「お前は何もわかっていない.こんなに素晴らしくグラフをかけるんじゃ」って言われたら素直に土下座します.煽り気味のタイトルで本当に申し訳ないです.
そんなこんなで今回は,割と覚えやすくて ,デザイン もよく,3Dの作図 にも強い可視化ライブラリ,plotly を紹介します.
いきなりですがplotly ではこんな作図ができます.
Note: おそらくスマホ ではうまく表示されませんのでPCで確認お願いします!
ご覧の通り,マウスホバー で詳細を表示できたり,グラフを動かせたり ,3Dの作図 もかなりいい感じにできるのでみなさんも使ってみてください.
Usage
Basic Charts
Scatter Charts (散布図)
Line Charts (折れ線グラフ)
Bar Charts (棒グラフ)
Statistical and Seaborn-style Charts
Error Bars (誤差付き折れ線グラフ)
Box Plots (箱ひげ図)
Histograms (ヒストグラム)
2d Histograms (二次元ヒストグラム)
2d Density Plots
Scientific Charts
Heatmaps
Dendrograms (階層クラスタ)
実践(暇できたら適当にやっていきます.)
目次に書いたもの以外でもたくさん機能はあるのですが,あんまり使わなそうだなぁと個人的に思ったものは紹介していません.DocumentにGoです.
また最後に実践編 として分析例をいくつか載せていく予定です.実践編は随時追加予定なので自分のやりたい分析と近いものがあれば参考にしてみてください.
最後に注意事項.
以下で表示しているグラフは全て画像なので,動かせないので注意してください
もちろんみなさんのローカル環境ではグリグリ動かせるグラフができますのでご安心を.
あと最後の最後におまけなんですが,atom
のhydrogen
を使えばatom
内で分析がゴリゴリできます.
実は僕jupyter
もそこまで好きじゃないんで,同士がいたら使ってみてくださいね.
まずはinstall.pipで簡単にいけます.
$ pip install plotly
この記事を見ている多くの方は既にinstallしていると思いますが,pandas
やらjupyter
やらまぁその辺は入れといてください.
※ ここから下は,plotlyの基本的な書き方の説明です.コードを読む方が早いって方は読まなくて大丈夫です.
さて肝心の作図の方法ですが,だいたいのグラフは以下の流れで作成できます.
オフラインで動くように設定する.
trace
を作成する.
layout
を定義する.
iplot
, もしくはplot
で作図する.
1個ずつ言葉を確認していきましょう.
まず結構重要なオフラインの設定です.
plotly はアカウントを作って,サーバー上にグラフを保存することができます.一番最初に掲載した,3Dの動くグラフもサーバー上に保存されているグラフをお借りしているものです.
しかし僕の場合はオフラインで事足ります.というかほとんどのユーザーはオフラインで満足なはず.ですので以下のようにimport
しましょう.
import plotly.offline as offline
offline.init_notebook_mode()
ここの仕組みについてはあまり考える必要ないと思います.僕も知りません.
お次はtrace
です.
trace
は作図で一番重要なデータや作図方法の情報が入ったものです.具体的な例を示します.
import plotly.offline as offline
import plotly.graph_objs as go
trace = go.Scatter(
x = np.array(setosa[columns[1 ]]),
y = np.array(setosa[columns[2 ]]),
name = "setosa" ,
mode = "markers" ,
marker = dict (size=10 , color="rgba(255, 0, 255, 0.5)" ))
ここではScatter
(散布図)を使いtrace
を作っています.見てわかるように,この時点でx
やy
などにデータを与えています.また点の大きさや色なども指定していますね.plotlyではこのtrace
を基本単位として扱います.
次はlayout
について.
先ほどはデータ点そのものについて色や大きさなどを指定しました.layout
ではグラフのタイトルや軸の名前など,ひとつ粒度の大きい部分のデザインを定義していきます.具体的な例は以下です.
layout = go.Layout(
title='Iris sepal length-width' ,
xaxis=dict (title='sepal legth(cm)' ),
yaxis=dict (title='sepal width(cm)' ),
showlegend=True )
最後にiplot
です.
iplot
とplot
の違いはjupyter
内で作図をするかどうかの違いなので,基本的にiplot
を使います.
先ほど作った,trace
とlayout
を辞書で囲んであげてiplotします.ちなみに辞書で情報を整理されたものを,plotlyではfigureと呼んでいるみたいです.
fig = dict (data=data, layout=layout)
offline.iplot(fig, filename="example" )
以上が主な作図方法の流れです.
Simple Scatter Plots
散布図です.1個目なのでIrisデータ使いましょう.
まずはラベルなしでplotしてみます.
教師なし学習とかを想像しながら見てくださいね.
グラフはこんな感じになります.
サンプルコード
Usageでも紹介した通り,
trace
を作成する.
layout
を定義する.
iplot
, もしくはplot
で作図.
の流れです.
Style Scatter Plots
次はラベルつき でplotしてみます.
教師データを意識してください.
versiclor
とvirginica
がガッツリ混ざっていますね.3種類に分類するとき,この特徴量だけでは足りないことが見て取れます.
サンプルコード
Usageでも紹介した通り,
trace
を作成する.
layout
を定義する.
iplot
, もしくはplot
で作図.
の流れです.
import plotly.offline as offline
import plotly.graph_objs as go
offline.init_notebook_mode()
from sklearn.datasets import load_iris
import pandas as pd
iris = load_iris()
columns = ["label" ] + iris.feature_names
label = iris.target.reshape([150 ,1 ])
labeled = np.hstack([label,iris.data])
df = pd.DataFrame(labeled, columns=columns)
setosa = df[df["label" ] == 0 ]
versicolor = df[df["label" ] == 1 ]
virginica = df[df["label" ] == 2 ]
trace0 = go.Scatter(
x = np.array(setosa[columns[1 ]]),
y = np.array(setosa[columns[2 ]]),
name = "setosa" ,
mode = "markers" ,
marker = dict (size=10 , color="rgb(255, 0, 255)" ))
trace1 = go.Scatter(
x = np.array(versicolor[columns[1 ]]),
y = np.array(versicolor[columns[2 ]]),
name = "versicolor" ,
mode = "markers" ,
marker = dict (size=10 , color="rgb(255, 165, 0)" ))
trace2 = go.Scatter(
x = np.array(virginica[columns[1 ]]),
y = np.array(virginica[columns[2 ]]),
name = "virginica" ,
mode = "markers" ,
marker = dict (size=10 , color="rgb(127, 255, 212)" ))
layout = go.Layout(
title='Iris sepal length-width' ,
xaxis=dict (title='sepal legth(cm)' ),
yaxis=dict (title='sepal width(cm)' ),
showlegend=True )
data = [trace0, trace1, trace2]
fig = dict (data=data, layout=layout)
offline.iplot(fig, filename="Iris-labeled-scatter" , image="png" )
折れ線グラフは時系列データを扱うときに使います.
基本的には散布図と同様にScatter
を使い,mode
にline
を与えるだけです.
サンプルコード
Usageでも紹介した通り,
trace
を作成する.
layout
を定義する.
iplot
, もしくはplot
で作図.
の流れです.
import plotly.offline as offline
import plotly.graph_objs as go
import numpy as np
N = 100
random_x = np.linspace(0 , 1 , N)
random_y0 = np.random.randn(N)+5
random_y1 = np.random.randn(N)
random_y2 = np.random.randn(N)-5
trace0 = go.Scatter(
x = random_x,
y = random_y0,
mode = 'markers' ,
name = 'markers'
)
trace1 = go.Scatter(
x = random_x,
y = random_y1,
mode = 'lines+markers' ,
name = 'lines+markers'
)
trace2 = go.Scatter(
x = random_x,
y = random_y2,
mode = 'lines' ,
name = 'lines'
)
data = [trace0, trace1, trace2]
offline.iplot(data, filename='scatter-mode' , image="png" )
棒グラフはカテゴリカル分布の作図や,
それぞれのクラスに属するデータ数を可視化するときに使います.
以下の例では,手書き数字データセット のdigitsを用いてそれぞれの数字にいくつのデータがあるか調べています.
今回の例ではほとんど同数なので問題ありませんが,
データ数に偏りがあった場合は重み付け などしないといけませんからね.
この棒グラフの可視化も分析には重要なstepです.
サンプルコード
Usageでも紹介した通り,
trace
を作成する.
layout
を定義する.
iplot
, もしくはplot
で作図.
の流れです.
import plotly.offline as offline
import plotly.graph_objs as go
offline.init_notebook_mode()
from sklearn.datasets import load_digits
import pandas as pd
import numpy as np
digits = load_digits()
label = digits.target
N = label.shape[0 ]
freq = np.zeros(10 )
for i in range (10 ):
count = N - np.count_nonzero(label - i)
freq[i] = count
trace = go.Bar(
x = [_ for _ in range (10 )],
y = freq,
marker = dict (color="rgba(255, 165, 0, 0.7)" ))
layout = go.Layout(
title = "digits" ,
xaxis = dict (title="number" ),
yaxis = dict (title="number of data" ),
annotations=[
dict (x=xi, y=yi, text=str (int (yi)), showarrow=False )
for xi, yi in zip ([_ for _ in range (10 )], freq)
]
)
data = [trace]
fig = dict (data=data, layout=layout)
offline.iplot(fig, filename='sample-bar-digits' , image="png" )
Error Barsとは誤差付き折れ線グラフのことです.ここで紹介しているのは厳密に言うとBasic Continuous Error Bars ですが,まあ気にしないでください.多分こっちの方が使います.
使いどころはベイズ 線形回帰 などがパッと思いつくところです.ベイズ 線形回帰だと確率が見えないから微妙かな.まぁいつか 何かで実践して載せるつもりです.いつか ね!
以下の図とサンプルコードは本家のDocumentをoffline ver. に書き換えただけのほぼ同じものです.
サンプルコード
trace
を作成する.
layout
を定義する.
iplot
, もしくはplot
で作図.
の流れです.
import plotly.offline as offline
from plotly.graph_objs import *
offline.init_notebook_mode()
x = [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ]
x_rev = x[::-1 ]
y1 = [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ]
y1_upper = [2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 ]
y1_lower = [0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]
y1_lower = y1_lower[::-1 ]
y2 = [5 , 2.5 , 5 , 7.5 , 5 , 2.5 , 7.5 , 4.5 , 5.5 , 5 ]
y2_upper = [5.5 , 3 , 5.5 , 8 , 6 , 3 , 8 , 5 , 6 , 5.5 ]
y2_lower = [4.5 , 2 , 4.4 , 7 , 4 , 2 , 7 , 4 , 5 , 4.75 ]
y2_lower = y2_lower[::-1 ]
y3 = [10 , 8 , 6 , 4 , 2 , 0 , 2 , 4 , 2 , 0 ]
y3_upper = [11 , 9 , 7 , 5 , 3 , 1 , 3 , 5 , 3 , 1 ]
y3_lower = [9 , 7 , 5 , 3 , 1 , -.5 , 1 , 3 , 1 , -1 ]
y3_lower = y3_lower[::-1 ]
trace1 = Scatter(
x=x+x_rev,
y=y1_upper+y1_lower,
fill='tozerox' ,
fillcolor='rgba(0,100,80,0.2)' ,
line=Line(color='transparent' ),
showlegend=False ,
name='Fair' ,
)
trace2 = Scatter(
x=x+x_rev,
y=y2_upper+y2_lower,
fill='tozerox' ,
fillcolor='rgba(0,176,246,0.2)' ,
line=Line(color='transparent' ),
name='Premium' ,
showlegend=False ,
)
trace3 = Scatter(
x=x+x_rev,
y=y3_upper+y3_lower,
fill='tozerox' ,
fillcolor='rgba(231,107,243,0.2)' ,
line=Line(color='transparent' ),
showlegend=False ,
name='Fair' ,
)
trace4 = Scatter(
x=x,
y=y1,
line=Line(color='rgb(0,100,80)' ),
mode='lines' ,
name='Fair' ,
)
trace5 = Scatter(
x=x,
y=y2,
line=Line(color='rgb(0,176,246)' ),
mode='lines' ,
name='Premium' ,
)
trace6 = Scatter(
x=x,
y=y3,
line=Line(color='rgb(231,107,243)' ),
mode='lines' ,
name='Ideal' ,
)
data = Data([trace1, trace2, trace3, trace4, trace5, trace6])
layout = Layout(
paper_bgcolor='rgb(255,255,255)' ,
plot_bgcolor='rgb(229,229,229)' ,
xaxis=XAxis(
gridcolor='rgb(255,255,255)' ,
range =[1 ,10 ],
showgrid=True ,
showline=False ,
showticklabels=True ,
tickcolor='rgb(127,127,127)' ,
ticks='outside' ,
zeroline=False
),
yaxis=YAxis(
gridcolor='rgb(255,255,255)' ,
showgrid=True ,
showline=False ,
showticklabels=True ,
tickcolor='rgb(127,127,127)' ,
ticks='outside' ,
zeroline=False
),
)
fig = Figure(data=data, layout=layout)
offline.iplot(fig, filename= 'shaded_lines' , image="png" )
有名な図ですけど,自分で作図したことはほとんどないです.
これも本家のDocumentをoffline に書き換えただけです.申し訳ない.
サンプルコード
trace
を作成する.
layout
を定義する.
iplot
, もしくはplot
で作図.
の流れです.
import plotly.offline as offline
import plotly.graph_objs as go
offline.init_notebook_mode()
import numpy as np
y0 = np.random.randn(50 )
y1 = np.random.randn(50 )+1
trace0 = go.Box(
y=y0,
name = 'Sample A' ,
marker = dict (
color = 'rgb(214, 12, 140)' ,
)
)
trace1 = go.Box(
y=y1,
name = 'Sample B' ,
marker = dict (
color = 'rgb(0, 128, 128)' ,
)
)
data = [trace0, trace1]
offline.iplot(data)
きました,定番のヒストグラム です.めっちゃ使います.
棒グラフと似てますけど違いますからねー.
まずは正規分布 から適当にデータをサンプリングして最もシンプルなヒストグラム を生成してみましょう.
こんな感じになります.
若干きもい ヒストグラム になっちゃいました.
サンプルコード
import plotly.offline as offline
import plotly.graph_objs as go
import numpy as np
x = np.random.randn(500 )
data = [go.Histogram(x=x)]
offline.iplot(data, filename='basic histogram' )
しかし,分析しているときは何かしらのデータを比較 していることも多いですよね.
1つのデータごとに1つずつヒストグラム を作るのはダサい です.
ってことで多分こういうグラフの方が一般的に使うのかなと思います.
若干ずらして表示してくれるので見やすいですね.
サンプルコード
import plotly.offline as offline
import plotly.graph_objs as go
offline.init_notebook_mode()
import numpy as np
x1 = np.random.randn(500 )
x2 = np.random.randn(500 ) + 1
trace1 = go.Histogram(
x = x1,
name = "data1" ,
marker = dict (color='#FFD7E9' ),
opacity = 0.75
)
trace2 = go.Histogram(
x = x2,
name = "data2" ,
marker = dict (color='#EB89B5' ),
opacity = 0.75
)
layout = go.Layout(
title = "two histograms" ,
xaxis = dict (title="value" ),
yaxis = dict (title="Count" ),
bargap=0.2 ,
bargroupgap=0.1
)
fig = dict (data=[trace1, trace2], layout=layout)
offline.iplot(fig, filename='basic histogram' , image="png" )
2つのヒストグラム を使って作図します.次の図は2次元正規分布 を無理やり離散に書き換えたもの と考えるとわかりやすいかもしれません.
カウントした総数で正規化 すればこのままの状態で確率分布になります.
こういうグラフ見てると周辺化 したくなってきますよね.
サンプルコード
import plotly.offline as offline
import plotly.graph_objs as go
offline.init_notebook_mode()
import numpy as np
x = np.random.randn(500 )
y = np.random.randn(500 ) + 1
trace = go.Histogram2d(
x = x,
y = y,
name = "data1" ,
opacity = 0.75 ,
colorscale="YIGnBu"
)
layout = go.Layout(
title = "2d histograms" ,
xaxis = dict (title="data1" ),
yaxis = dict (title="data2" ),
)
fig = dict (data=[trace], layout=layout)
offline.iplot(fig, filename='2d_histogram' , image="png" )
2D Histogramと似てますが,こちらは連続データ を扱うときに使います.
irisデータ に含まれるsetosaのsepal lengthとsepal widthを使って分布を確認してみましょう.
ちょっとデータが少ないですね.しかもこの多次元データは2次元正規分布 に従うというより,正の相関を持ったデータっぽいですね.
多次元正規分布 の作図として適してないかもしれませんが,まぁこういうことも作図して初めてわかると きもあるよってことで許してください.
サンプルコード
import plotly.offline as offline
import plotly.figure_factory as ff
offline.init_notebook_mode()
from sklearn.datasets import load_iris
import pandas as pd
iris = load_iris()
columns = ["label" ] + iris.feature_names
label = iris.target.reshape([150 ,1 ])
labeled = np.hstack([label,iris.data])
df = pd.DataFrame(labeled, columns=columns)
setosa = df[df["label" ] == 0 ]
x = setosa['sepal length (cm)' ]
y = setosa['sepal width (cm)' ]
colorscale = ['#7A4579' , '#D56073' , 'rgb(236,158,105)' , (1 , 1 , 0.2 ), (0.98 ,0.98 ,0.98 )]
fig = ff.create_2d_density(
x, y, colorscale=colorscale,
hist_color='rgb(0, 128, 222)' , point_size=3 ,
)
offline.iplot(fig, filename="2d-density" , image="png" )
お次はヒートマップです.3種類の変数の関係性を見たいときに使います.
Qiitaのこちらの記事 がseabornに含まれているわかりやすいデータを用いているので,こちらと同様にグラフを作ってみましょう.
色の濃さは乗客数 を表しているので,乗客数と年月の相関を確認することができます.パッと見ただけで,12月は帰省などで多いのかな?や,1955年付近には何があったのだろう?と分析の目処を立てることができますね.
また模様の違いがはっきり出ている方が,その変数は特徴量として大きな情報を持っていると判断することもできます.つまり特徴量選択の際にも使うことができます.
サンプルコード
主に階層的クラスタリング で使うDendrograms,いわゆる系統樹 の紹介です.階層的クラスタリング ってなんやねんって方は,こちら を参考にして見てください.
ヒートマップと組み合わせて用いることが多いのですが,そこに関してはseaborn の方が簡単にできるような気がしてます.とりあえずここで紹介するのは基本的なDendrograms ってことで許してください.
一応階層クラスタリング を簡単に説明すると,それぞれのデータごとに"キョリ"を計算し,近いものから同じグループとして結合していく手法です."キョリ"の計算方法は色々あるので,それは別の記事で書こうかと.できたらリンク貼りますねー.
結果的にはこんな図ができます.
サンプルコード
系統樹 はfigure_factory
を用いて作図するのですが,Layout
を扱う際に,若干の注意が必要です.コメントで書いておきましたので,そちらを参考にして見てください.
import plotly.offline as offline
import plotly.figure_factory as ff
import numpy as np
X = np.random.rand(10 , 10 )
names = ['Jack' , 'Oxana' , 'John' , 'Chelsea' , 'Mark' , 'Alice' , 'Charlie' , 'Rob' , 'Lisa' , 'Lily' ]
fig = ff.create_dendrogram(X, orientation='left' , labels=names)
fig["layout" ].update({"title" :"dendrograms example" , 'width' :800 , 'height' :800 })
"""
Note
figは辞書型です.
import plotly.graph_objs as go
layout = go.Layout(title="dendrograms example")
fig["layout"] = layout
などとすることでタイトルを記入できますが,こうすると軸がめちゃくちゃになってしまいます.
これは create_dendrogram のメソッド内でlayoutを最初から整えてくれているからです.
上のように代入してしまうと,layoutが初期化されてしまうわけですね.
以上のことから,
基本的にはfigure_factoryを扱う際は,
updateを使い,自分の定義したいものだけ加えていくのが最善だと思います.
"""
offline.iplot(fig, filename='dendrogram_with_labels' , image="png" )
実践編
暇できたら書く
まとめ
少なくともmatplotlibよりは覚えやすいし,デザイン的にかっこいいグラフが作れると僕は思っています.
またplotlyの真髄は3Dの作図なので,3Dグラフのまとめもすぐに書きますね.
以上です.