グラフにして図示し、データを可視化することはデータの分析において基本であり重要な手段であります。
ここでは主にpylabモジュールを使用したグラフ作成について解説、出題を行います。
レポートや研究活動などでも有効に活用できるツールなので是非とも学んでもらいたいです。
pylabはmatplotlibを使用する最も一般的なツールです。グラフの作成などを行う本体がmatplotlibであり、pylabはそのインターフェイスであるといえます。
ipython notebookなどの開発環境上でpylabをimportすると、GUIバックエンドのサポートが有効になった状態(ざっくり言えば使っているマシーンとソフトが入出力の処理を見えないところで行ってくれる状態)で起動します。
この状態で使うことを前提にした解説を行います。
インストール方法について、使用するうえで前提となるモジュールがいくらかありますが
Anaconda環境では基本的なモジュールは自動的にインストールされているはずなので、あまり気にする必要はないかもしれません。
matplotlibの使い方はこのほかにも多数ありますが、ここでは触れません。
上ではpylabをimportするとマシーンのGUIが自動的に有効になると説明したが、サーバー上ではipython notebookでの指定をする必要があります。
ここではimportと同時に%matplotlib inlineと書く方法に統一します。
pylabを解説しているので、%pylab inlineというマジックコマンドについて注意しておきます。
確かに、このようにpylabモジュールを使うことも可能です。(今後廃止される可能性もあります。)しかし、このように書くとpylabとnumpyという2つのモジュールがトップレベルimportされた状態(from モジュール名 import $*$を実行した状態)になります。便利ではあるのですが、いくらかの組み込み関数などが上書きされてしまうなどの事態を引き起こします。たとえば、組み込み関数にsum()という関数がありますが、numpyの関数にもsum()という関数があり、組み込み関数のsum()がnumpyのsum()として上書きされ、組み込み関数のほうが使えなくなるという具合です。このような不具合を避けるためにも%matplotlib inlineをお勧めします。
このように書くと、作成したグラフが実行したラインの直下に表示されます。
また、自分でローカル環境を構築した場合は%matplotlib inlineと書かないと別ウィンドウで図が表示されるはずです。
%matplotlib inline
import pylab as pl
#make list type data
data = [1,2,3,4,5,6]
plot1 = pl.plot(data)
#display graph in other environment
#pl.show()
たったこれだけのコードで簡単にグラフを作ることができました。
まずは、pylabモジュールをimportします。モジュール名で呼び出すのは大変なのでplというエイリアスで呼び出せるようにしておきます。
その後、リスト型のデータをdataとして作り、pylabのplot関数にデータを渡すと、グラフが作成され、pl.show()と書くと表示されます。
ただし、ipython notebookでは、pl.show()と書かなくてもグラフが表示されますので、このマニュアルではコメントアウトしています。
その他の環境では、pl.show()を実行することで図を表示します。
グラフを観察すると、データとして与えたリストからインデックスをx軸としてグラフを作成していることがわかります。
datax = range(5)
datay = [1,5,3,2,4]
plot2 = pl.plot(datax,datay)
#display graph in other environment
#pl.show()
ここまでに作った2つの線を、同時に表示することも可能です。
自動的に線の色や表示する範囲が調整されていることにも注目してください。
# make plot1
data = [1,2,3,4,5,6]
plot1 = pl.plot(data)
# make plot2
datax = range(5)
datay = [1,5,3,2,4]
plot2 = pl.plot(datax,datay)
#display graph in other environment
#pl.show()
リスト型のデータを作成する際に長くなると、手書きするのは難しくなる。また、range()などの関数で単純に作れないようなデータは自分で作成する必要があります。
そこで、「リスト内包表記」について触れておきます。
$y=x^3$のデータを作るためのコードを下に書きます。比較してみましょう。
data=[]
for i in range(10):
data.append(i**3)
print (data) #if python2.x : print data
data = [i**3 for i in range(10)]
print (data) #if python2.x : print data
リスト内包表記を使うと、3行必要だったデータを作る部分を1行で簡潔に書くことができます。
append()を使わないので、より高速にデータを作成できます。
$y=x^2$ のグラフをx=1からx=10範囲で作成せよ。
#please write your answer here
以下の点を通るような2つの直線をプロットしなさい。
line1 => (0,0),(1,5),(2,5),(3,3),(4,6),(5,1),(6,6)
line2 => (0,0),(1,2),(2,2),(3,3).(4,3),(5,4),(6,4)
#please write your answer here
このままではグラフがあまりに殺風景なので、レポートなどには使えません。グラフのタイトルや軸ラベル、凡例などを加えることでより実用的なグラフを作りましょう。 どれも簡単なのでまとめて紹介します。
グラフにタイトルをつけるときはtitle("graph title")を使います。 文字の大きさやタイトルと付ける場所などは以下の要素を指定することで指定可能です。
指定する名前 | 指定できる内容 | 備考 |
---|---|---|
fontsize | 文字の大きさを指定 | ポイントを実数値を入力 |
fontweight | 文字の太さを指定 | ポイントを実数値を入力 |
verticalalignment | 上下の表示場所を指定 | 'top', 'bottom', 'center', 'baseline'から選択 |
horizontalalignment | 左右の表示場所を指定 | 'center', 'left', 'right'から選択 |
書かない場合はデフォルトの値や最適なものが自動的に選ばれます。
xlabel("label name"),ylabel("label name")を使えばx軸y軸それぞれに名前を付けることができます。 文字の大きさや表示する位置は以下のように指定できます。指定しない場合はデフォルトの値や最適なものが自動的に選ばれます。
指定する名前 | 指定できる内容 | 指定するデータ |
---|---|---|
fontsize | 文字の大きさを指定 | ポイントを実数値を入力 |
verticalalignment | 上下の表示場所を指定 | 'top', 'bottom', 'center', 'baseline'から選択 |
horizontalalignment | 左右の表示場所を指定 | 'center', 'left', 'right'から選択 |
凡例はlegend(['Data name1','Data name2'...])と設定することができます。
指定する名前 | 指定できる内容 | 指定するデータ |
---|---|---|
loc | 凡例を表示する位置を指定 | 数値(0=最適,1=右上,2=左上,3=左下...) |
ncol | 凡例の行数 | 自然数 |
fontsize | 文字の大きさを指定 | 'xx-small', 'medium'や数値を指定 |
title | 凡例のタイトルを指定 | 文字列 |
表示する図の大きさはfigure()で指定可能です。
指定する名前 | 指定できる内容 | 指定するデータ |
---|---|---|
figsize | 図の大きさをインチ単位で指定 | 実数or数値のtuple |
dpi | 図の大きさをdpi単位で指定 | 実数or数値のtuple |
facecolor | 図の背景色を指定 | 下の文字列を参照 |
データをプロットするときにplot(data,"strings")と"strings"を指定することで、線やプロットの種類や色、マーカーを指定することが可能です。
色を指定する文字列 | 色 |
---|---|
'b' | 青 |
'g' | 緑 |
'r' | 赤 |
'c' | シアン |
'm' | マゼンタ |
'y' | 黄 |
'k' | 黒 |
'w' | 白 |
プロットを指定する文字列 | プロット方法 |
---|---|
'-' | 実線 |
'--' | 破線 |
'-.' | 一点鎖線 |
':' | 点線 |
マーカーを指定する文字列 | マーカー |
---|---|
'.' | 点 |
',' | ピクセル |
'o' | 小さい円 |
'v' | 下向き三角形 |
'^' | 上向き三角形 |
'<' | 左向き三角形 |
'>' | 右向き三角形 |
'1' | 下向きY字 |
'2' | 上向きY字 |
'3' | 左向きY字 |
'4' | 右向きY字 |
's' | 正方形 |
'p' | 五角形 |
'$*$' | 星 |
"+" | +字 |
"x" | x字 |
"d" | ダイヤモンド型 |
#Decorate the graph
pl.figure(figsize=(5,5))
pl.title("y=x",fontsize=20,verticalalignment="bottom")
pl.xlabel("x-axis")
pl.ylabel("y-axis")
#make plot
data=range(10)
plot1 = pl.plot(data,"r--")
pl.legend(['data1'],fontsize=20)
#display graph in other environment
#pl.show()
xが1から10の範囲における$y=10x^2+4x-2$のグラフを緑の点線で作成しなさい。
グラフタイトルはy=10x**2+4x-2と20ポイントで表示し、
x,y軸には、それぞれ"x-axis","y-axis"という名前を15ポイントで表示する。
凡例は"graph1"という名前で付けること。
#please write your answer here
xが1から15の範囲における$y=x$のグラフを青の実線で作成しなさい。
同時に$y=x^3$のグラフを青の破線で作成しなさい。
グラフタイトルは"question"と15ポイントで表示し、
x,y軸には、それぞれ"x-axis","y-axis"という名前を10ポイントで表示する。
凡例は"graph1"、"graph2"と、それぞれに付けること。
#please write your answer here
pylabで作ることができるグラフはここまでのようなプロット図のみではありません。
ヒストグラムと散布図の使い方について説明したいと思います。
タイトルの付け方などは他の形式のグラフにおいても同様です。
prot(data)同様にhist(data)を使うとdata内に現れるデータの数を棒グラフとして表示します。
指定する名前 | 指定できる内容 | 指定するデータ |
---|---|---|
bins | データの刻み幅 | 数値を入力 |
range | x軸の範囲を指定 | (最小値,最大値)のtuple |
align | 棒グラフの表示場所を指定 | 'left', 'mid', 'right'から選択 |
color | 棒グラフの色を指定 | グラフの色を参照 |
scatter(data_x,data_y)一つの点を表現するためのxとy座標のリストのようなデータを入力すると散布図を返します。
指定する名前 | 指定できる内容 | 指定するデータ |
---|---|---|
s | 点の大きさをして | 数値を入力 |
c | 点の色を指定 | グラフの色を参照 |
marker | 点のマーカーを指定 | グラフのマーカーを参照 |
#random module
import random as rd
#Average
mu = 0
#standard deviation
sigma = 10
data = [rd.normalvariate(mu, sigma) for i in range(100)]
pl.title("normal distribution histgram",fontsize=15)
pl.xlabel("Value",fontsize=10)
pl.ylabel("Frequency",fontsize=10)
#make histogram
hi = pl.hist(data,color="g")
#display graph in other environment
#pl.show()
randomモジュールは名前の通り色々な乱数を発生させる機能を使えるようにするモジュールです。エイリアスをつけてimportします。
平均と標準偏差は統計学で一般的な記号と同様に、$\mu$(mu)と$\sigma$(sigma)という変数に格納します。
randomモジュールのnormalvariate()関数に平均と標準偏差を渡すとその値に従った数値をランダムに生成してくれます。
x,y座標を平均0、標準偏差10の正規分布に従ってランダムに生成したデータを赤い点の散布図として表示する。
#Average
mu = 0
#standard deviation
sigma = 10
data_x = [rd.normalvariate(mu, sigma) for i in range(10)]
data_y = [rd.normalvariate(mu, sigma) for i in range(10)]
pl.title("normal distribution scatter plot",fontsize=15)
pl.xlabel("x-coordinate",fontsize=10)
pl.ylabel("y-coordinate",fontsize=10)
#make scatter plot
sc = pl.scatter(data_x,data_y,c="r")
#display graph in other environment
#pl.show()
0以上100以下の数値をrandom()を使って40個作り、ヒストグラムで表示せよ。
randomモジュールには以下のような関数がある。
関数の名前と入力 | 出力される内容 | 備考 |
---|---|---|
random() | 0.0以上1.0未満の実数をランダムに返す | |
randint(a, b) | a以上b以下の整数をランダムに返す | |
randrange(start, stop, step | start以上stop未満step刻みの要素からランダムに値を返す |
#please write your answer here
ここまでは1つの図を表示する内容を扱ってきたが、複数の図を並べて表示したいことが多々あるでしょう。 そこで、複数の図を並べる方法としてsubplot()を紹介します。
n×mの領域のk番目に図を入れたいときは、subplot(n,m,k)と書きます。 省略してsubplot(nmk)と書いても同様です。
#plot1 position is upper left
pl.subplot(2, 2, 1)
pl.plot(range(10))
pl.title("plot1")
#plot2 position is upper right
pl.subplot(2, 2, 2)
pl.plot(range(10,0,-1))
pl.title("plot2")
#plot3 position is bottom left
#different length data is OK
pl.subplot(2, 2, 3)
pl.plot([1,3,5,4,2,6,9,8])
pl.title("plot3")
#display graph in other environment
#pl.show()
しかしこのままではplot1のx軸とplot3タイトルが被ってしまいます。調整する方法として2つ紹介します。
1つ目はtight_layout()を紹介します。
指定する名前 | 指定できる内容 | 備考 |
---|---|---|
pad | 図の間隔の比率 | 実数値 |
h_pad | 図の上下の間隔の比率 | 実数値 |
w_pad | 図の左右の間隔の比率 | 実数値 |
何も書かなければフォントに合わせて自動的にきれいに整います。
#plot1 position is upper left
pl.subplot(2, 2, 1)
pl.plot(range(10))
pl.title("plot1")
#plot2 position is upper right
pl.subplot(2, 2, 2)
pl.plot(range(10,0,-1))
pl.title("plot2")
#plot3 position is bottom left
#different length data is OK
pl.subplot(2, 2, 3)
pl.plot([1,3,5,4,2,6,9,8])
pl.title("plot3")
pl.tight_layout()
#display graph in other environment
#pl.show()
subplots_adjust()を使うと、空白を任意に設定することができます。
指定する名前 | 指定できる内容 | 備考 |
---|---|---|
left | 図の左幅を調節 | 実数値 |
right | 図の右幅を調節 | 実数値 |
bottom | 図の下幅を調節 | 実数値 |
top | 図の上幅を調節 | 実数値 |
wspace | 図の左右の間隔を調節 | 実数値 |
hspace | 図の上下の間隔を調節 | 実数値 |
スペースを0に設定することで同じ軸を共有できるようなデータは見やすくなることをあります。
この場合は軸が違うのでずれてしまうことを確認してください。
pl.subplot(2, 2, 1)
pl.plot(range(10))
pl.subplot(2, 2, 2)
pl.plot(range(10,0,-1))
pl.subplot(2, 2, 3)
pl.plot([1,3,5,4,2,6,9,8])
pl.subplots_adjust(wspace=0,hspace=0)
#display graph in other environment
#pl.show()
作ったグラフをレポートや論文、書籍などで活用するためには、画像を保存する必要があります。
もちろん、作った画像をクリックして保存することも可能ですが、実験結果などで多くの画像を出力する場合にはいささか面倒です。
そこでsavefig("file_name")というモジュールを紹介します。
ファイルが保存される場所はカレントディレクトリ(特に指定しない場合はこのファイルを開いた場所)に保存されます。保存形式は"file_name"に付けた拡張子から自動的に推測して保存されます。形式はpdfも含む画像を扱う多くの形式をサポートしています。
指定する名前 | 指定できる内容 | 備考 |
---|---|---|
dpi | 図の大きさを調節 | 実数値 |
facecolor,edgecolor | 図の背景色を調節 | グラフの色を参照 |
format | 画像の形式を明示 | 文字列 |
bbox_inches | 図の保存する場所を指定 | "tight"と書くと空白を除いて保存する |
#Average
mu = 0
#standard deviation
sigma = 10
data = [rd.normalvariate(mu, sigma) for i in range(1000)]
pl.title("normal distribution histgram",fontsize=15)
pl.xlabel("Value",fontsize=10)
pl.ylabel("Frequency",fontsize=10)
#make histogram
hi = pl.hist(data,color="g")
#save figure as png file
pl.savefig("fig1.png")
ここまで紹介した方法で図やグラフを使う機能はおおむね終わりです。
実際的には他のモジュールやクラスと併用することが多くなることと思います。
最後にnumpyモジュールと合わせて使うことを説明します。簡単に複雑な図やグラフを作ることができる事を体感してもらえればと思います。
import numpy as np
numpyではlistの代わりにarrayを使います。
range()に相当する機能がarange()があり、ほかにもlinspace()やndarray()という配列を作る便利な機能が用意されています。
また、三角関数や対数関数なども簡単に計算できます。
np.array([1,2,3,4,5])
arrange()使い方はrange()と同様
np.arange(5)
linspace(a,b,c)はaからbまでの数をc個に分けたarrayを返します
np.linspace(0,4,5)
ndarrayは与えたtupleに従って多次元の配列を返します。
np.ndarray((3,3))
y=sin(x)とy=cos(x)のグラフを$-3\le x \le 3$の範囲で作成しなさい。
x = np.arange(-3, 3, 0.1)
y1 = np.sin(x)
y2 = np.cos(x)
pl.title("Trigonometric function",fontsize=15)
pl.xlabel("x-axis",fontsize=10)
pl.ylabel("y-axis",fontsize=10)
pl.plot(x, y1,"b")
pl.plot(x, y2,"--g")
pl.legend(['sin(x)',"cos(x)"],fontsize=10,loc=2)
#display graph in other environment
#pl.show()
$y=e^x$のグラフを$0\le x \le 10$の範囲で作成しなさい。
#please write your answer here
平均0、標準偏差15の正規分布をヒストグラムで表示しましょう。その下に累積グラフを赤い実線で付けたグラフを作成せよ。
data = [i*2 for i in range(1,100)]
pl.hist(data,bins=100,cumulative=True,histtype='step')
pl.show()
#please write your answer here
スマートフォンを買い換えることを考えます。
料金体型が色々あるので、カタログを見ただけでは、どの会社で契約するか悩んでしまいました。
そこで、グラフ化することで分かりやすくしましょう。
データは以下の通りである。
会社名 | 基本料金 | データ通信料金 | 通話料金 | 備考 |
---|---|---|---|---|
docono | 300円/月 | 5000円/月 | 4200円/月 | 通話、通信し放題 |
AG | 300円/月 | 500円+0.02円×通信料(KB) | 1,996円/月 | 通話し放題 |
HardBank | 300円/月 | 5000円/月 | 3200円/月 | 通話、通信し放題 |
Kakuyasu | 700円/月 | 900円/月 | 20円/30秒 | 通信し放題 |
ただし、毎月のデータ通信料は3GBとして、合計の通話時間は10分とします。
いざ、買おうとお店に行くと、契約する会社によってキャンペーンをやっていることがわかりました。
また、機種についても会社によって選べる機種が違うことがわかりました。
キャンペーン内容や機種のほしい度合(欲しさ)を以下の表で表す。
会社名 | 割引内容 | 備考 |
---|---|---|
docono | 機体50000円引き(ただし0円以下にはならない)、月々の料金3000円引き | 2年以上使う場合 |
AG | 機体30000円引き、月々の料金1000円引き | 2年以上使う場合 |
HardBank | 機体無料、月々の料金2000円引き | 2年以上使う場合 |
Kakuyasu | 0円 | 割引なし |
機種 | 値段 | 欲しさ | 使える会社 |
---|---|---|---|
jPhone | 80000円 | 100 | docono,AG,HardBank |
ZPERIA | 60000円 | 80 | docono,HardBank,Kakuyasu |
Zunfone | 40000円 | 50 | AG,Kakuyasu |
(欲しさ)×(魅力度)=(値段)として扱うことができるものとする。
以上の条件を考慮して以下の問いに答えよ。
機種にこだわりを持つ人は、2年間使うことを考えるとき、度の会社でどの機種を買うのがよいでしょう?このときの魅力度は100000としてください。
機種にほどほどこだわる人(魅力度10)は、2年間使うことを考えると最もお得な方法はどれになるでしょう?
このほかにも面白い機能や便利な機能はたくさんあります。
数学的な処理をする方法もたくさんあります。
自分の研究分野などに合わせて追加の勉強をしてください。。。
たとえば、以下のようにポップなグラフを書くこともできますよ。
pl.xkcd()
x = np.arange(0,2*np.pi,.01)
pl.plot(x,np.sin(x))
#display graph in other environment
#pl.show()