生活を良くします - 怠惰なプログラミング

生活を良くします-怠惰なプログラミング

外資系でエンジニアをやっています。便利なサービスや商品、プログラミングで作ったものなどを紹介していきます

Python Jupyter notebookでpandasを使いCSVを読み込みグラフを描画してpdfなどで保存する方法

Pythonでグラフを描画する方法について

Pythonを知らない人やプログラミング初心者の人はこちらの記事をどうぞ

www.what-a-day.net

python用の講座についても無料で勉強できます。

jupyter notebook

昔はIPython Notebookと呼ばれていたが、現在はjupyter notebook(ジュパイターノートブック)となっている便利なものがあります。これでグラフを作る方法についてメモ書きしておきます。

エクセルでグラフを作ってもいいのですが、処理がやや面倒かつMacだとエクセルの動作に不安を覚えます。勝手に落ちたり、立ち上がらなかったりと。

jupyter notebookだと割と簡単で綺麗なグラフがかけます。pythonで動くのでpythonがわかる人ならコードを書くだけで加工ができます。

毎回ググっては忘れるを繰り返しているのでそろそろ覚えたい。

jupyter notebookについてはこちらで書きました。

www.what-a-day.net

今回やりたかったこと

IMFが公開している各種経済関連のデータを使って色々と調べたいことがあったのでいい機会なので逐一行動をメモることにしました。

Select Country or Country Groups

pythonでpandasとmatplotlibを使いグラフを作成する

簡単に言うとcsv形式のファイルから特定の情報だけをとってきてそれをいい感じにグラフに描画し、pdf・jpg・png形式で保存したい、というだけです。

それ別にエクセルでやれば良くない?となりますが、jupyter notebook上でやればとても早いですし何よりフリーズしません。また結構キレイなグラフになりますし、グラフのデザインとかもそれなりに拘れます。

ちなみにエクセルのファイルがどのようになっているのかも書いておきます。yearとGDP_rate(%)という列があり、そこに対応するデータが入っています。

year GDP_rate (%)
1980 10
1981  12
1982 8
1983 2
1984 1
〜〜〜 〜〜〜


ここから特定の行(列)だけを抜き出してグラフにします。それで簡単な説明はあとでするとして、忘れないようにコードを書いておくことにします。

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import os

df = pd.read_csv("/Users/yourname/Desktop/book.csv", encoding="UTF-8")
plt.figure(figsize=(8, 6.5))
plt.rcParams["font.size"] = 22
plt.rcParams["xtick.labelsize"] = 12
plt.rcParams["ytick.labelsize"] = 15
plt.rcParams["legend.fontsize"] = 12
plt.grid()

year = df["year"]
gdp = df["GDP_rate(%)"]

plt.axhline(y=0)
plt.ylim(ymax=8)
plt.ylim(ymin=-8)

plt.xlabel("年")
plt.ylabel("GDP成長率(%)")



plt.plot(year,gdp,"r",marker="o",markersize=2)

plt.savefig("/Users/yourname/Desktop/gdp.svg", bbox_inches="tight")
plt.savefig("/Users/yourname/Desktop/gdp.pdf", bbox_inches="tight")
plt.savefig("/Users/yourname/Desktop/gdp.png", bbox_inches="tight")
plt.savefig("/Users/yourname/Desktop/gdp.jpg", bbox_inches="tight")


f:id:what_a_day:20170210224939j:plain

これは.jpg形式で保存した画像をはてなブログにアップロードしたものになります。

なんか全体的に暗くてダメそうな感じになってしまいました。


f:id:what_a_day:20170210225021p:plain

こちらはpng形式で保存したものです。なかなか悪くない感じになりました。レポートに貼り付ける画像もエクセルだとメンドくさくてスクリーンショットで済ませてしまうことが多かったのですが、最近はちゃんとpythonで書いてます。

データ数が少ないと恩恵が少なく感じますが、数万点のデータを何度も扱う場合は非常に楽になります。

どういう風に楽になるかというと一度グラフを指定して処理の仕方を記述しておけば勝手に計算してくれるからです。たいていちょっと改変するだけで使いまわせます。

エクセルだとちょっと嫌になる処理でもpythonで書いているとなんだか気が楽になる、そういう感じのものです。

具体的な説明について

%matplotlib inlineでは実行したものの結果がすぐにわかるという機能です。

大学とかだとこれでメモとったりしてたら強そう。簡単に情報共有できるし。

f:id:what_a_day:20170210234648g:plain


これらはグラフのフォントや文字サイズをいい感じに調整するための部分です。ちょっと文字が多すぎたので普段よりも小さめにしています。

plt.figure(figsize=(8, 6.5))
plt.rcParams["font.size"] = 22
plt.rcParams["xtick.labelsize"] = 12
plt.rcParams["ytick.labelsize"] = 15
plt.rcParams["legend.fontsize"] = 12
plt.grid()


これでcsv形式のファイルを読み込みdf(データフレーム)として使用します。

そしてyearにはcsvのyear列を取得したものを、gdpにはGDP_rate(%)列を取得したものを入れておきます。

df = pd.read_csv("/Users/yourname/Desktop/book.csv", encoding="UTF-8")


year = df["year"]
gdp = df["GDP_rate(%)"]


データフレームはこんな感じになっています。だいたいエクセルっぽいやつという認識です。

f:id:what_a_day:20170210235228p:plain:w450


これでpythonの描画を実行します。普通の折れ線グラフに実際の点の部分にマーカーをサイズ"2"で埋め込んでいます。色々調べるともっとキレイにできそうですが、これで十分な気がします。

plt.plot(year,gdp,"r",marker="o",markersize=2)

考えられるエラーとその対策

AttributeError: ‘Series’ object has no attribute ‘find’

これはpandasを使っているとよく出るエラーです。

メインの説明はstackoverflowに任せますが、自分が詰まった時のエラーを紹介します。

csvの数値表示はたまに親切で桁表示をしてくれているのですが、それが原因でした。

例:5000と5,000

まさかこれが原因とは知らなかったので時間を無駄にしました。治し方とかは簡単でエクセルでその列または行を指定し、数値表示にさせます。その時に桁表示のオプションをつけなければ治ります。

KeyError: “[‘ ’] not in index”

指定された行または列などが存在していないという意味です。基本的にタイプミスで出てきます。

上の例でいうと、yearがyaerとかになっているとKeyError: “[‘yaer’] not in index"とか表示されます。

TypeError: Can’t convert ‘int’ object to str implicitly

intと文字列で間違って操作をしているというメッセージです。

この場合だとエラーが発生します。

i = 5
print("this is five" + i)


治した場合が下のものです。簡単そうに見えますが、疲れている時にはよく出てくるエラーです。

i = 5
print("this is five" + str(i))

UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0x8c in position 0: invalid start byte

読み込んでいるcsvがUTF-8形式ではなく、SHIFT-JIS形式だった時に発生します。日本語の文字化けですね。

その逆のSHIFT-JISをUTF-8形式で読み込もうとしていた場合でも同様にエラーが発生します。csvの形式に合わせてエンコーディングを指定しましょう。

# UTF-8
df = pd.read_csv("/Users/yourname/Desktop/book.csv", encoding="UTF-8")


# SHIFT-JIS
df = pd.read_csv("/Users/yourname/Desktop/book.csv", encoding="SHIFT-JIS")

seabornを使った場合

堅苦しくない感じのグラフができます。

seabornを使うとヒートマップ形式のグラフが作成できたりします。理系の研究職では便利になってくる機能で、割と簡単に使えるようになるはずです。

df(データフレーム)にcsvを読み込みます。

seabornの場合では直接、xとyにどこの列かという情報を与えています。これだけで勝手にグラフを作ってくれます。

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import os

import seaborn as sns

df = pd.read_csv("/Users/yourname/Desktop/book.csv", encoding="UTF-8")
df.plot(x = 'year',y = 'GDP_rate(%)')
plt.savefig("/Users/yourname/Desktop/seaborn.png", bbox_inches="tight")

f:id:what_a_day:20170211114619p:plain


df.plot(x = ‘year’,y = ‘GDP_rate(%)’,marker=‘o’,linestyle=‘’)と少しのオプションを与えるとグラフの形式を変更できます。

f:id:what_a_day:20170211115235p:plain


そして簡単にヒストグラムだったり分散だったりというのが計算なしで描画可能です。今回のデータにヒストグラムの描画は有効とは思えませんが、例として。

sns.set_style('whitegrid')
sns.distplot(df['GDP_rate(%)'],bins=100,color='green')
plt.savefig("/Users/yourname/Desktop/seaborn.png", bbox_inches="tight")

f:id:what_a_day:20170211120440p:plain


複数のグラフを並べたいときに使う方法についてです。TeXやwordでは図を並べる方法が備わっていてそれなりに便利ですが、なぜか思い通りにやってくれない時などがあります。

思ったようなレイアウトにならないような場合は自分で最初から並べておきましょう。

今回はplt.subplot(2, 1, 1)で、(2,1,1)なので2行、1列、一つ目という意味です。並べる配置とかの設定ですね。

plt.figure(figsize=(8, 6.5))
plt.rcParams["font.size"] = 22
plt.rcParams["xtick.labelsize"] = 15
plt.rcParams["ytick.labelsize"] = 20
plt.rcParams["legend.fontsize"] = 18

GDP_list = ['GDP_rate(%)','GDP_US']


plt.subplot(2, 1, 1)
plt.plot(df['year'],df['GDP_japan'])
plt.legend()

plt.subplot(2, 1, 2)
plt.plot(df['year'],df['GDP_US'])


plt.legend()

f:id:what_a_day:20170211235555p:plain


グラフを4つに増やした場合とグラフ中にテキストを埋め込んだ場合についてです。

もうちょっとスマートにやる方法もあるはずですが、4つしかないので手打ちしました。地味にすごいと思った機能の一つです。

num_rows = 2
num_cols = 2
title_size = 26

plt.figure(figsize=(8, 6.5))
plt.rcParams["font.size"] = 9
plt.rcParams["xtick.labelsize"] = 9
plt.rcParams["ytick.labelsize"] = 20
plt.rcParams["legend.fontsize"] = 11



plt.subplots_adjust(wspace=0.2, hspace=0.3)

# [1]
ax = plt.subplot2grid((num_rows, num_cols), (0,0))
ax.text(2010,6,"回復")
ax.plot(2010,6,marker="o",markersize=5,color="red")
ax.plot(df['year'],df['GDP_japan'])

# [2]
ax = plt.subplot2grid((num_rows, num_cols), (0,1))
ax.text(1995,6,"1995です")
ax.plot(1995,6,marker="o",markersize=5,color="red")
ax.plot(df['year'],df['GDP_japan'])

# [3]
ax = plt.subplot2grid((num_rows, num_cols), (1,0))
ax.plot(df['year'],df['GDP_japan'])
ax.plot(2008,6,marker="o",markersize=5,color="red")
ax.text(2008,6,"大幅下落")

# [4]
ax = plt.subplot2grid((num_rows, num_cols), (1,1))
ax.text(2017,6,"予測値です")
ax.plot(2017,6,marker="o",markersize=5,color="red")
ax.plot(df['year'],df['GDP_japan'])


plt.show()

f:id:what_a_day:20170212004401p:plain


今回はアメリカと日本のGDP成長率を見てみました。2017年以降のデータはIMFによる見積もり値です。二つの線を引くのは簡単でもう一つplotを追加すればいいだけです。

今は2本ですがこれ以上、線の数が増える場合はforループで回した方が効率が良いと思います。

plt.legend()で凡例をつけてわかりやすくしています。

plt.figure(figsize=(8, 6.5))
plt.rcParams["font.size"] = 22
plt.rcParams["xtick.labelsize"] = 15
plt.rcParams["ytick.labelsize"] = 20
plt.rcParams["legend.fontsize"] = 18

GDP_list = ['GDP_rate(%)','GDP_US']

# for gdp in GDP_list:
plt.plot(df['year'],df['GDP_japan'])
plt.plot(df['year'],df['GDP_US'])


plt.legend()

f:id:what_a_day:20170211122607p:plain


ピアソンの相関関数でアメリカと日本のGDP成長率の相関を見てました。正直なところ、統計関連は完全に苦手なのですが、pythonを使うとなんとなくできるようになります。

ピアソンの相関関数が正の値(0.4)なので日本のGDP成長率とアメリカの成長率は相関していると言えます。直感的にもそれはそうと言った感じです。

横軸とか縦軸とかは今回はいい加減にしています。

sns.jointplot('GDP_japan','GDP_US',df,kind='scatter',color='purple')

f:id:what_a_day:20170211122540p:plain


ちょっとかっこよくして見ました。

sns.jointplot('GDP_japan','GDP_US',df,kind='kde',color='m')

f:id:what_a_day:20170211123003p:plain


こういう方法はググりながらでもできますが、最初に体系的に勉強しておくとあとが楽です。

Udemyのデータサイエンスコースではこのようなグラフの描写からデータの分析まで丁寧に勉強できました。Udacityのやつも良かったですけどね。

Jupyter notebookを使ってデータサイエンスの講義をやってくれます。けっこうお気に入りです。

【世界で2万人が受講】実践 Python データサイエンス


こちらの本も参考になります。

NumpyやPandasについて書かれている本です。研究室に入っている学生や研究者は持っていると何かと得します。

まとめ

  • pythonでキレイなグラフの書き方を探した
  • jupyter notebookはやっぱり便利


[f:id:what_a_day:20170211001406p:plain]

ちなみにこんな感じのpythonでもっとキレイなグラフや独特なグラフを使いたい場合はこちらの記事を参考にしていただければと思います。

[http://www.what-a-day.net/entry/2016/11/12/100000:embed:cite]