2017年10月07日

いい感じのグラフの書き方

こんにちは、なおいです。


機械学習に欠かせないであろうデータの可視化が私にも必要になってきました。


一番有名なmatplotlibというライブラリをご多分にもれずやっていきたいと思います。


 



 


[:contents]


matplotlibとは?


f:id:ct-innovation01:20170927160405p:plain


プログラミング言語Pythonおよびその科学計算用ライブラリNumPyのためのグラフ描画ライブラリである。オブジェクト指向のAPIを提供しており、様々な種類のグラフを描画する能力を持つ。描画できるのは主に2次元のプロットだが、3次元プロットの機能も追加されてきている。描画したグラフを各種形式の画像(各種ベクトル画像形式も含む)として保存することもできるし、wxPython、Qt、GTKといった一般的なGUIツールキット製のアプリケーションにグラフの描画機能を組みこむこともできる。MATLABの対話環境のようなものを提供するpylabというインタフェースも持っている。Matplotlibは、BSDスタイルのライセンスの下で配布されている。(Wiki参照


 


ということで、2次元及び3次元のグラフをさくっとプロットできる非常にありがたいライブラリです。


 


インストール方法(Mac)


pip install matplotlib

私はPython3.6.1を使用しており、上記のコマンドをターミナルで打てば問題なくインストールされました。(実際は、仮想環境を使ったりしているので仮想環境をActivateしたりはしていますが。。。)


 


import方法


import matplotlib.pyplot as plt

 一番よくいろんなサイトに載っている方法はこれだと思います。私もこの方法でやりたいと思います。matplotlibパッケージの中のpyplotモジュールをpltという名前で使うという宣言です。これによって、このあとpltで色々できるようになるという感じです。


 


散布図(ポイント)のプロット


1.基本

import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [9, 8, 7, 6, 5]

plt.scatter(x,y)
plt.show()

 なんにも設定がいらなければ、これだけで散布図(ポイント)をプロットできます。


プロットした結果は以下の通りで、xとyは配列になっていて同じ数であれば、x[0]とy[0]の場所にプロットしてくれるため(1,9)となり、そのあとも同じインデックス同士の(2,8)、(3,7)、(4,6)、(5,5)とプロットされていくはずです。


 


f:id:ct-innovation01:20170927002653p:plain 


問題なくプロットされてますね。あとは見た目をカスタマイズしていきます。


 


2.プロットの見た目をいじる

import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [9, 8, 7, 6, 5]

plt.scatter(x,y, marker='*',c='red',label='test')
plt.legend() #凡例
plt.show()

 赤文字部を追加することでプロットの見た目を変えて、凡例をつけられます。scatterに付けられる主要なカスタマイズキーワードは表形式でグラフの後に載せときます。


 


f:id:ct-innovation01:20170927004159p:plain


凡例つくだけでちょっとグラフっぽくなりますね。星になったのは少しいただけませんかね・・・ともかく、次は目盛線と補助目盛線をつけて、グラフタイトルとX軸Y軸のラベルを入れましょう。


 


Tips)プロットに付与できる主要なカスタマイズキーワード

主要と書いている通り、もっとたくさんキーワードはあります。より細かい指定で様々な散布図が描けますが、最低限これだけおさえてれいれば、普通のグラフは書けるかなという範囲のみ記載しておきます。















































kywd入力例備考
x,y[1,2,3,4,5] または 事前に定義したlistなどarray形式のもの
※必須
ss=5 または
x,yと同範囲のリスト(要素はサイズ)
マーカーの大きさ
指定しないと20
cc="red" または
c="#FFFF00" または
c=(1.0,0,1.0)
マーカーの色
色名や16進数、RGBでの指定が可能
markermarker="."マーカーの形
指定しないと○
*は星形など様々指定可
alphaalpha=0.3マーカーの透明度
指定は0-1の間で行う
linewidthslinewidths=2マーカーの枠線の幅
labellabel="label1"凡例名

色と形については、リファレンスを見ると以下のものが用意されているみたいです。


f:id:ct-innovation01:20170927115343p:plain


color example code: named_colors.py — Matplotlib 2.0.2 documentation


f:id:ct-innovation01:20170927115403p:plainf:id:ct-innovation01:20170927115416p:plain


lines_bars_and_markers example code: marker_reference.py — Matplotlib 2.0.2 documentation


 


3.グラフの見た目をいじる

import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [9, 8, 7, 6, 5]

plt.scatter(x,y, marker='s',c='red',label='test')
plt.legend()
plt.grid(True) #グリッド線
plt.xlabel("X-label") #X軸ラベル
plt.ylabel("Y-label") #Y軸ラベル
plt.title("TEST GRAPH") #グラフタイトル
plt.show()

先ほど同様、赤文字部を追加することで見た目のカスタマイズを行いました。実際のグラフが以下のものです。ちなみに、さすがに星はやめて四角にしました。


 


f:id:ct-innovation01:20170928001147p:plain


 


かなりらしくなってきましたね。これを資料に貼るだけでもテクってる感出ますかね?


では、最後に複数データを同じグラフに入れてみましょう。


 


4.複数データを一つのグラフにプロットする

import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [9, 8, 7, 6, 5]
y2 = [5, 6, 7, 8, 9]

plt.scatter(x,y, marker='s',c='red',label='test')
plt.scatter(x,y2, marker='p',c='blue',label='test2')
plt.legend()
plt.grid(True)
plt.xlabel("X-label")
plt.ylabel("Y-label")
plt.title("TEST GRAPH")
plt.show()

 同じグラフにプロットするだけなら、ただもう一行追加するだけでいいんですね。非常に簡単だし、ループを回す際もかなり楽に書けます。非常にありがたい。


 


f:id:ct-innovation01:20170928001402p:plain


 


いかがでしたか?これでとりあえず、散布図はいい感じにかけるようになりましたね。




posted by naoi at 12:00| Comment(0) | python | このブログの読者になる | 更新情報をチェックする

2017年10月06日

Pythonでよく忘れる文字と数字の変換2

こんにちは、なおいです。


Pythonを触っていると文字列の出力(ファイル出力を含む)でよくフォーマットが問題で出力できないとかで悩んで、検索しているので備忘録シリーズその2を書きます。


 


.format()関数を使った変換


これはよくPythonの事が書かれた本のprint内の型変換で使われているのを見かけます。私は何度も書いてますがC#erでこれに近い書き方に慣れ親しんでいるので、この変換方法は結構好きでよく使ってます。


基本ルール

'文字列 {}'.format(文字列化したい変数など,キーワード引数)

 {} で区切られた置換フィールドに後ろの関数で指定した変数などの演算結果をstring型にして返します。


 


変数の実例をいくつか

本家のドキュメントで使われている例を使って、解読していきます。


 


1.位置引数を使ったアクセス

'{0}, {1}, {2}'.format('a', 'b', 'c')
→'a, b, c'
'{2}, {1}, {0}'.format('a', 'b', 'c')
→'c, b, a'
'{2}, {1}, {0}'.format(*'abc')
→'c, b, a'
'{0}{1}{0}'.format('abra', 'cad')
→'abracadabra'

これは、基本に近いからわかりやすいですね。基本ルールは入れたい変数が一つだったので引数がなかったけど、複数の変数を入れたくなったからナンバリングをしてるってだけですね。


f:id:ct-innovation01:20170911163842p:plain


引数は0から始まっていることだけ注意すれば、1つ目と2つ目の例からformat内の前から0,1,2と対応していることも分かるし、4つ目から同じものを二回呼び出すことも問題なくできることが分かります。


で、気になったのは3つ目formatには一つの変数しか入ってないし、謎の「*(アスタリスク)」があります。


 アスタリスクはアンパックするという指示みたいです。ここでいう一つの文字列'abc'を'a'と'b'と'c'の3つに分けて引き渡すという事のようです。つまり、2つ目の別表記と考えていいかなと思います。(知りませんでした。)


 


2.名前を使ったアクセス

'Coordinates: {lati}, {longi}'.format(lati='37.24N', longi='-115.81W')
→'Coordinates: 37.24N, -115.81W'
coord = {'lati': '37.24N', 'longi': '-115.81W'}
'Coordinates: {lati}, {longi}'.format(**coord)
→'Coordinates: 37.24N, -115.81W'

これもそこまで難しくないですね。1.のナンバリングだったものの代わりに名前を付けたってだけですね。図示する必要もないかな?


ただここでも出ましたアンパック!しかも今回は「**(アスタリスク2個)」ここは詳細省きますが、辞書型のものをよしなにアンパックしてくれると・・・なんかアンパックはそれだけで記事書けそうなのでそういうものとしてスルーします。


 


3.引数の属性へアクセス

c = 3-5j
('The complex {0} is real part {0.real} and imag part {0.imag}.').format(c)
→'The complex (3-5j) is real part 3.0 and imag part -5.0.'

これ知りませんでしたが便利ですね!


今回cはcomplex型を利用しているのですが、complex型にはrealとimagいうプロパティが存在しています。そのプロパティに対して普通にアクセスができるみたいです。


今までわざわざ別の変数に入れてから表示してましたよ。。。


 


4.引数の要素へアクセス

coord = (3, 5)
'X: {0[0]}; Y: {0[1]}'.format(coord)
→'X: 3; Y: 5'

これも知りませんでした・・・セットやリストの要素にもindexでアクセスできるみたいです。この方法ってここまで出来ること多かったんだなって驚いてます。


 


キーワード引数の実例をいくつか

こちらも本家の例を参考に解読していきます。 変換時に何か追加処理を行いたい時にこのあたりを用いれば、いろいろできますね。よく使われるのは、小数点以下何桁まで0埋めするとか正負を付けるとかですかね。


 


1.出力するテキスト幅を指定する

'{:30}'.format('aligned')
→'aligned '
'{:<30}'.format('left aligned')
→'left aligned '
'{:>30}'.format('right aligned')
→' right aligned'
'{:^30}'.format('centered')
→' centered '
'{:*^30}'.format('centered')
→'***********centered***********'

{}内に「:(コロン)」を書く事でここからキーワード引数だという事を示しているっぽいですね。さらに、添え字を付けずに数字を入れた場合はテキスト幅を指定する。前に「<,>,^」のどれかを入れると文字列の配置位置を決められる。さらに前にcharを入れるとその指定charで埋めてくれるようです。


では、下のを試してみます。ちょっと意地悪でテキスト幅を偶数で指定して対象を文字を1文字にしたらどこに行くのかの実験も兼ねて、


'{5:+^10}'.format(1,2,3,4,5,6,7,8)
→'++++6+++++'

結果はこんな感じで、5文字目に置かれました。頭の片隅に入れておこう・・・


f:id:ct-innovation01:20170912095657p:plain


赤枠で5個目を使ってねと指示し、コロンで区切った後ろで「+」で埋めてね。あ、指定した文字は真ん中ね?でテキスト幅は10文字で!という命令ということですね。理解した。


 


2.基数を指定する(基数の接頭辞付での出力含む)

"int: {0:d};  hex: {0:x};  oct: {0:o}".format(42)
→'int: 42; hex: 2a; oct: 52'
"int: {0:d}; hex: {0:#x}; oct: {0:#o}".format(42)
→'int: 42; hex: 0x2a; oct: 0o52'

キーワード引数は、さっきと同様で「:(コロン)」からスタートしてますね。


あとは、なぜ「d,x,o」なのかぐらいですかね。多分10進数、8進数、16進数の英語「decimal,Octal,Hexadecimal」の略だと思いますが、調べます。


 


・・・・まあ、予想どおりでした。


あ、あとbを指定すると2進数でも表示できるようです。ここは、そこまで問題なさそうなのでこれでおしまい。


 


3.正負と表示桁数を指定する

'{:+f}; {:+f}'.format(3.14, -3.14)
→'+3.140000; -3.140000'
'{: f}; {: f}'.format(3.14, -3.14)
→' 3.140000; -3.140000'
'{:.2f}; {:.2f}'.format(3.14, -3.14)
→'3.14; -3.14'

fは固定小数点を示す(Fixed-point)なのかな?調べても分かりませんでした。


それより覚えとかなきゃいけないのは「f」だけ指定すると小数点以下6桁表記されてしまう事ですかね。デフォルトが6桁だそうで、好きな桁数にしたい場合は「f」の前に表記したい桁数を3つ目のように「.2」を付与する必要があります。


では、表示桁数を削る時に気になる。四捨五入なのか切捨てなのかを検証。


'{0:.3f}:{0:.4f}'.format(0.123456)
→'0.123:0.1235'

 四捨五入を使ってるみたいですね。頭の中整理できてきた気がする。


 


4.1000の位にカンマを打つ

'{:,}'.format(1234567890)
→'1,234,567,890'

これは言うことないです。これ以上でも以下でもない。。。。


 


5.パーセント表記にする

points = 19.5
total = 22
'Correct answers: {:.2%}'.format(points/total)
→'Correct answers: 88.64%'

これもあんまり言うことないです。あえて何か言うとすれば、勝手に%にしてくれるので、100倍とかしなくていいのが手間がかからなくて嬉しいっていう事ぐらいですかね?検証してないですけど、希望的観測でこれも四捨五入なんじゃないかなと判断してます。


 


6.それぞれの型特有の表記にする

import datetime
d = datetime.datetime(2010, 7, 4, 12, 15, 58)
'{:%Y-%m-%d %H:%M:%S}'.format(d)
→'2010-07-04 12:15:58'

これは都度調べるしかないのかな・・・って感じです。頻出そうな時間に関してのみ例があったので一応載っけときます。

posted by naoi at 07:00| Comment(0) | 日記 | このブログの読者になる | 更新情報をチェックする

2017年10月04日

Pythonでよく忘れる文字と数字の変換

こんにちは、なおいです。


Pythonを触っていると文字列の出力(ファイル出力を含む)でよくフォーマットが問題で出力できないとかで悩んで、検索しているので備忘録をシリーズもので書きます。今回はその1です。


 


基本的な変数の型変換


まずは、基本的なPythonでデフォルトで組み込まれている関数から進めていきます。


組み込み関数での型の変換は非常に分かりやすく変換したい型名を前に書いて丸括弧で括ればいいです。


文字列の数値への変換

int([x[, 基数]])

float([x])

long([x[, 基数]])

complex([x])

ここの基数というのは、N進数のNのことで何も書かなければ10進数で変換されます。2,8,10,16あたりであれば普通に変換してくれると思います。他の基数は試したことないですが問題なく変換できます(追記:3を基数指定して試してみましたが普通に変換されました、必要かどうかは置いといて・・・)。


エラーが出る場合は、その基数に含まれるべきでない文字が入ってるからと考えられます。


complexは少しルールがあり、”1+4j”とする場合+の前後にスペースなどを入れないようにしておく必要があります。


 


 数値の数値への変換

int(少数)

float(整数)

long(少数)

数値に対して小数点(.0)を付加したり、少数を全て切り捨てて整数型にする場合などは以上の方法で変換をかけることで対応できます。


 


様々なオブジェクト型から文字列への変換

str(オブジェクト)

基本この形でstring型に変換できます。ただ、どのオブジェクトを変換しても1つの値を取ってくるわけではなく、例えばList型の場合はListの[]を含む全てをstringに変換しますし、クラスであれば「<__main__.クラス名 instance at 0x06B48738>」の様などこでインスタンス化された何某みたいな文言がstring変換されます。


型によってどのように変換されるかは決まっているので、正しく扱う必要があります。


ちなみに、strにはオプションは用意されていないのでstrだけでは、もともとint型のものを小数点2桁付加して出力することなどはできません。別の関数を組合せるなどして対応していきます。(ljust関数をうまく使うとか・・・)


 


これらの組み込み関数は簡単ではありますが、やれることがあまり多くないという印象です。とにかくそのまま型を変換する為のメソッドだと思っておくといいかもしれませんね。


 


とりあえず、今回はこの辺にしておきます。


最初のなので軽めのやつを選択しました。次から少しずつよくわからないやつになっていきますが、解読して後から読んでも分かるようにしていくつもりなのでお付き合いいただければ・・・


 


posted by naoi at 09:00| Comment(0) | 日記 | このブログの読者になる | 更新情報をチェックする