Pythonの以下のライブラリを使ってhistgramを描く。
以下のような細かい設定・よく使う設定もなるべく一緒にまとめる。
!python --version
!pip list | grep -E '^(pandas|numpy|scikit-learn|matplotlib|seaborn|plotly|plotly-express|bokeh) '
import os, sys
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly
import bokeh
%matplotlib inline
scikit-learnの load_iris() をDataFrameに格納して使う
詳しいデータの内容は 7.2.2. Iris plants dataset を参照。
df
dft
以上の2つを用意する。
from sklearn.datasets import load_iris
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df.head()
dft = df.copy()
dft['target'] = iris.target
dft['target_name'] = dft.target.replace({i: name for i, name in enumerate(iris.target_names)})
dft.head()
pandasはmatpllotlibを呼び出す。細かい設定をするときの引数はmatplotlibと同じ。
DataFrameに対するhistgramは、DataFrame.hist() と DataFrame.plot.hist() の2種類あり、出力が微妙に異なる。
df.hist()
はカラムごとにグラフを出力するsharex=True
, sharey=True
range=(0, df.max().max())
df.plot.hist()
は全てのカラムを1つのグラフに出力するalpha
を指定することで透明度を変更stacked=True
にすることで積み上げ# v1.0.0から backendを指定できるようになったのでmatplotlibかどうか確認
pd.options.plotting.backend
df.hist()
# rangeを統一する
df.hist(sharex=True, sharey=True, range=(0, df.max().max()))
df.plot.hist()
df.plot.hist(alpha=0.3)
df.plot.hist(stacked=True)
SeriesやgroupbyしたDataFrameに対しても hist()
関数は実装されている。
df['petal length (cm)'].hist()
dft[['petal length (cm)', 'target_name']].groupby('target_name').hist()
ラベル (target_name
)ごとのhistgramは groupby()
や pivot()
を使えばうまく出力できる
dft.groupby('target_name')['petal length (cm)'].hist(range=(0,df.max().max()), alpha=0.3)
dft.pivot(columns='target_name')['petal length (cm)'].hist(range=(0,df.max().max()))
pandasが呼び出しているのは plt.hist()
x
は (n,) array or sequence of (n,) arrays
なので、DataFrameを渡すときは注意# NG
print(df[['petal length (cm)']].shape)
plt.hist(x=df[['petal length (cm)']])
# OK
print(df.loc[:,'petal length (cm)'].shape)
plt.hist(x=df.loc[:,'petal length (cm)'])
label
にラベル名(カラム名)を渡し、
plt.legend()
を実行すると、凡例を出力できる
凡例の位置は調整可能 (参考: https://qiita.com/matsui-k20xx/items/291400ed56a39ed63462)
cols = ['petal length (cm)','petal width (cm)']
print(df.loc[:,cols].T.shape)
plt.hist(x=df.loc[:,cols].T, label=cols)
plt.legend()
histtype
を指定すると、細かい設定をせずに出力できる
typeは {'bar', 'barstacked', 'step', 'stepfilled'}
の4種類ある。
(参考 https://matplotlib.org/3.1.1/gallery/statistics/histogram_multihist.html)
また、複数のグラフを表示したいときは subplots
を使う
(参考 matplotlib.pyplot.subplots)
fig, axes = plt.subplots(nrows=2, ncols=2, sharex=True, sharey=True, figsize=(12, 8))
for htype,ax in zip(['bar', 'barstacked', 'step', 'stepfilled'], axes.flatten()):
ax.hist(iris.data, histtype=htype, label=iris.feature_names, bins=10)
ax.set_title(htype)
ax.legend(loc='upper right')
# fig.show()
savefig()
で保存
fig.savefig('matplotlib_sample.png')
sequence of (n,) arrays
であれば、label
にラベル名を渡すことができる。
異なる場所にあるデータを1つのhistgramに集約させたい場合はplt.hist()
を重ねればよい。
fig, ax = plt.subplots(1,1)
for n in iris.target_names:
# DataFrameでは本来バラバラで渡す必要はないけど、具体例のためにtarget_nameのデータを取り出しています
x= dft.query('target_name=="{}"'.format(n))['petal length (cm)']
ax.hist(x=x, label=n)
ax.legend(loc='upper right')
# fig.show()
fig, ax = plt.subplots(1,1)
x_data = []
for n in iris.target_names:
x_data.append(dft.query('target_name=="{}"'.format(n))['petal length (cm)'])
# listで一気に渡してもよい
ax.hist(x=x_data, label=iris.target_names, histtype='barstacked')
ax.legend(loc='upper right')
# fig.show()
sns.hist()
はない。histgramに適しているのは sns.distplot
kde
(kernel density estimate) がデフォルトで True
になっているkde=False
にするa
が Series, 1d-array, or list
なのでSeriesをそのまま渡しても予想通りの挙動をするだいたいmatplotlibと同じように使えるが、ちょいちょい使い勝手が違うので、sns.set()
して、matplotlib使う方が正直楽なところもある。
sns.set()
sns.distplot(df[['petal length (cm)']], bins=10)
# rangeなど matplotlib側の設定を変えたいときは hist_kws で渡す
sns.distplot(df[['petal length (cm)']], bins=10,kde=False, hist_kws={'range':(0,10)})
seabornでは1次元配列しか受け取れない。
そのため、複数データを1つのhistgramに集約させたい場合はsns.distplot()
を重ねる必要がある。
histtype
は設定できないので、stackしたり、ならべたいなら ラベルごと・複数データに対するhistgram(matplotlib編))
の方法で。
for i in range(4):
sns.distplot(iris.data[:,i],
label=iris.feature_names[i],
kde=False,
bins=10,
hist_kws={'range': [1,10]}
)
plt.legend()
matplotlibと同じ
plt.savefig('seaborn_sample.png')
plotlyはjavascriptベースで、tooltipを自動で設定してくれるのが良い。見た目もデフォルトのままで使える。
kaggleのkernelでもよくみる。
plotlyそのままだと書くコード量が多くなる。 なるべくplotly-expressを使いたい。
細かい調整をしたくなると、結局plotly本体の設定を変更することになる。
histgramについてはだいたい https://plotly.com/python/histograms/ のページで解決する。
(参考 https://qiita.com/inoory/items/12028af62018bf367722)
plotly-expressを使わず、plotlyだけでhistgramを描くにはgo.Figure()
とgo.Histgram()
を使う。
go.Figure()
に go.Histgram()
のリストを渡すことで複数データのhistgramを作成できる。
import plotly
import plotly.graph_objs as go
# offlineで使う
plotly.offline.init_notebook_mode(connected=False)
# 以降、offlineで使う場合は fig.show()をplotly.offline.iplot(fig)に置き換える
fig = go.Figure(data=go.Histogram(x=iris.data[:,0]))
fig.show()
# target_name ごとのhistgramを一緒に表示
data=[
go.Histogram(x=dft.query('target_name=="{}"'.format(n))['petal length (cm)'], name=n)
for n
in iris.target_names
]
fig = go.Figure(data=data)
fig.show()
xbins
で行う。data
はリストでなくても add_trace
で逐一追加することも可能fig = go.Figure()
for i in range(len(iris.feature_names)):
fig.add_trace(go.Histogram(x=iris.data[:,i], name=iris.feature_names[i],
xbins={'start':0, 'end':10, 'size':1}))
fig.show()
plotly.offline.plot(fig, filename='plotly_sample.html')
data=[
go.Histogram(x=iris.data[:,i], name=iris.feature_names[i],
xbins={'start':0, 'end':10, 'size':0.5})
for i
in range(len(iris.feature_names))
]
layout = go.Layout(barmode='overlay')
fig = go.Figure(data=data, layout=layout)
fig.update_traces(opacity=0.3)
fig.show()
data=[
go.Histogram(x=iris.data[:,i], name=iris.feature_names[i],
xbins={'start':0, 'end':10, 'size':0.5},
opacity=0.8)
for i
in range(len(iris.feature_names))
]
layout = go.Layout(barmode='stack')
fig = go.Figure(data=data, layout=layout)
fig.show()
matplotlibと同じように複数グラフを表示できる (参考 https://plotly.com/python/subplots/)
from plotly.subplots import make_subplots
fig = make_subplots(rows=1, cols=2)
fig.add_trace(
go.Histogram(x=iris.data[:,0], name=iris.feature_names[0],
xbins={'start':0, 'end':10, 'size':0.5}),
row=1, col=1
)
fig.add_trace(
go.Histogram(x=iris.data[:,1], name=iris.feature_names[1],
xbins={'start':0, 'end':10, 'size':0.5}),
row=1, col=2
)
fig.update_layout(title_text="plotly.subplot")
fig.show()
plotlyを楽に呼び出して使える
color
にカラム名を渡せば、渡したカラムごとに色分けできるopacity
など)import plotly.express as px
fig = px.histogram(df, x='petal length (cm)')
fig.show()
fig = px.histogram(dft, x='petal length (cm)', color='target_name')
fig.show()
fig = px.histogram(dft, x='petal length (cm)', color='target_name', opacity=0.3)
fig.update_layout(barmode='overlay')
fig.show()
color
など細かい設定には対応していない
fig = make_subplots(rows=1, cols=2)
fig.add_trace(
px.histogram(dft, x='petal length (cm)')['data'][0],
row=1, col=1
)
fig.add_trace(
px.histogram(dft, x='petal width (cm)')['data'][0],
row=1, col=2
)
fig.update_layout(title_text="length and width")
fig.show()
import bokeh
from bokeh.io import output_notebook, show
from bokeh.plotting import figure, output_file, show
output_notebook()
# データの作成
hist, edges = np.histogram(iris.data[:,0], range=(0,10), bins=10)
edges, hist
len(hist), len(edges)
from bokeh.plotting import ColumnDataSource
source = ColumnDataSource(data=dict(
x=edges[:-1],
y=hist,
name=edges[:-1],
))
p = figure(plot_height=350,
title=iris.feature_names[0],
toolbar_location=None,
tools="hover",
tooltips="x: @x y: @y"
)
p.vbar(top='y',x='x', width=0.9, source=source)
p.y_range.start = 0
show(p)