こんにちは。

2019年に新卒社員として、キャスレーコンサルティングで
エンジニアのキャリアをスタートさせた梁 泰榮です。

はじめに

私は学生の頃にC言語やJava、C#を学ぶ機会はありましたが
Pythonについては勉強したことがありませんでした。

最近アメリカでは、JavaよりもPythonが多く使われているという記事を読み
Pythonに興味を持ちました。

今回は、Pythonの強みであるデータ分析の一例として、
CSVファイルをグラフ化する機能を少し勉強しましたので
その内容を皆さんにご紹介したいと思います。

データ視覚化の実例

まずは、データ視覚化の重要性についてご紹介したいと思います。

皆さんはナイチンゲールをご存知でしょうか。
イギリスの看護師として有名ですが、実は統計学者でもありました。
野戦病院で人々を看護していく中で、野戦病院の劣悪な衛生環境により病気が悪化し死亡する人々が
戦場での死亡者よりも多いことに気づきました。

ナイチンゲールは、このような状況を改善するために、
野戦病院の状況を数値で把握し、人々に知らせる努力をしました。

しかし、数値で表現されている統計データは、人々がよく理解できないという問題がありました。
この問題を解決するため、考案されたのがRose diagram(ローズダイアグラム)です。

このローズダイアグラムは、1854年にナイチンゲールが野戦病院に赴任してから2年間のデータを基に作成されました。

ローズダイアグラムは月ごとの、
 ・青色:病気による死亡者数
 ・赤色:負傷による死亡者数
 ・黒色:その他の理由で死亡した人数
を表しています。

右側が1854年4月~1855年3月のグラフで、
左側の小さいグラフが、1855年4月~1856年3月のグラフです。

野戦病院の衛生環境が改善することで、病気による死亡者数が急減していることがわかります。

このグラフは野戦病院の衛生環境改善事業の効果をよく表しており、
多くの人が病院の衛生の重要さに気づくきっかけになりました。

このような貢献もあり、ローズダイアグラムは19世紀指折りの統計グラフだと言われています。

このように、単純に数値を列挙するよりも、数値を見える化して情報を伝えた方が効果的であることがわかります。

それでは、Pythonを使いCSVファイルをグラフ化する機能を紹介します。

環境

Windows 10
Python 3.7.4
pandas 0.25.2
⤴データ分析のために使われるライブラリです。

matplotlib 3.1.1
⤴データをチャートなどに視覚化するライブラリです。

JupyterNotebook
⤴webブラウザでPythonコードを書いて実行ができるツールです。

pip

pipは、Pythonのパッケージを管理するシステムで、3.4以降には基本的に入っています。

このpipを使い、コマンドプロンプトで下記のコマンドを実行することで
pandasとmatplotlib、JupyterNotebookのダウンロードが簡単にできます。

・pandasのインストール

pip install pandas

・matplotlibのインストール

pip install matplotlib

・JupyterNotebookのインストール

pip install jupyter

JupyterNotebook

JupyterNotebookを実行

jupyter notebook

CSVファイルの事前準備

グラフ化に使用するCSVファイルを、JupyterNotebookに配置します。

JupyterNotebookへの配置は、「upload」ボタンを選択し使用するCSVファイルをアップロードします。

CSVファイルは、2018年09月28日に文部科学省が発表した
 「親の収入による子供の中学校3年生時の成績」
を調査した統計データを使用します。
※日本政府の統計データが確認できる「e-Stat」からダウンロードし、必要なデータだけを利用しました。

csvファイルをアップロードしたら、newを押下し、python3を選択するとソースの作成ができます。

csvファイルをグラフ化させよう

先ずは、CSVファイルを扱うためのpandasライブラリと、
グラフ化するためにmatplotlibと、matplotlibのサブパッケージであるpyplotを
それぞれimportします。
※簡単な視覚化プログラムはpyplotだけで作成ができます。

CSVファイルの読み込みは、「read_csv()」を使用します。

「CSVファイルの事前準備」にてJupyterNotebookへ配置したCSVファイルを読み込み、
データフレームのインスタンスを返してくれます。

import pandas as pd
import matplotlib.pyplot as plt

#CSVファイルをUTF-8形式で読み込む
data = pd.read_csv('gold3.csv',encoding = 'UTF8')
#dataを出力
data

最初は、簡単な折れ線グラフから作っていきます。

data.plot()

このようにpyplotを使うと簡単に折れ線グラフの出力ができますが、文字化けしてしまいました。

フォント設定

グラフ内で日本語を使用する場合は、フォントの設定が必要であることが分かりました。

フォントの設定については、matplotのフォントマネージャを使用して行います。
今回は、設定ファイル(matplotlibrc)の既定フォントを変更したいと思います。

 #ロカール上のフォントパスを指定(Windows標準)
font_location = 'C:\Windows\Fonts\BIZ-UDMinchoM.ttc'
#フォントパス(font_location)を指定しフォント名を取得
font_name = fm.FontProperties(fname=font_location).get_name()
#設定ファイル(matplotlibrc)の「font.family」取得したフォント名へ変更
matplotlib.rc('font',family=font_name)

※windowsの場合は、以下のパスにフォントファイルが配置されています。

「C:\Windows\Fonts」

折れ線グラフ

フォントを設定して、再び折れ線グラフを作ってみます。

data.plot()

これで、日本語が使えるようになりました。

棒グラフ

次に、棒グラフを作りたいと思います。
グラフの種類は、「kind」で指定ができます。

#mataplotlibのpyplotを使いバーグラフを出力
data.plot(kind='bar')

しかし、x軸の文字が縦に表示され分かりづらくなっています。
「plot」の引数へ「rot」を指定し、x軸を回転させ斜めに表示すると見やすくなります。

#X軸の内容を45度で出力する
data.plot(kind='bar',rot=45)

次は、「上の方」の成績だけを抽出して棒グラフにしてみます。

以下のように、「上の方」と指定するだけで実現できます。

 #カラム名を指定するとそのカラムデータだけをとれる
data.上の方.plot(kind='bar',rot=45)

任意データ取得

任意のデータを取得するには、pandasのlocを使用する方法もあります。
※他にも、「at」「iat」「iloc」等があります。

 data_200 = data.loc[['200万円未満']]
data_200

 data_200.plot(kind='bar',rot=45)

このようにすごく簡単に、欲しいデータだけをグラフ化することができます。

しかし、皆さん気づきましたか?
上のデータは調査対象の人数が違うため、
このような単純比較では、収入による成績の違いがよく分かりません。


※そもそも800万円以上の収入の方が多い。。

そのため、「200万円未満の方」と「800万円以上の方」のデータを抽出してパーセントに変更し
円グラフで表現してみます。

円グラフ

円グラフは、matplotlibのpyplot.pieを使用します。

各パラメータへは下記を指定します。
plt.pie(①,labels = ②,autopct=③,startangle=④)

①「200万円未満の方」のデータを渡します。
②data(csvファイルをデータフレーム化したもの)のカラム名を使うため、labelsにdataを渡します。
③autopctには小数点何位まで出力するかを指定します。
④startangleには一番比率が高いデータをどの位置に配置するかを指定します。

#円グラフするデータを渡す
#labelsにdataを渡してdataにあるカラムを取得する
#autopctにパーセントを指定。以下の数字だと小数点一位まで表現する
#startangleに一番高いパーセントを45度の位置に表現することを指定
plt.pie(data_200,labels = data, autopct='%1.1f%%',startangle=45)
plt.show()

円グラフができました!

しかし、エラーが出力されています。
もしかしたら、渡したdataに日本語など文字が含まれているからかもしれません。

pandasのvaluesを使い値だけを取得し、リストに変更してから円グラフに渡してみます!

#data_200にある値だけを取得しリストに変更する
datalist = data_200.values.tolist()
datalist

「200万円未満の方」の値だけ格納されている「datalist」を円グラフに渡すと

plt.pie(datalist,labels = data, autopct='%1.1f%%',startangle=45)
plt.show()

エラーになります。
エラーの内容をしっかりと読んでみましょう…

エラー内容の通り、一次元配列を作り渡してみます!

Pythonでは一次元配列作る色々な方法がありますが、今回は簡単にsum関数を使って作ってみます。

#sum関数の二番目の引数に[]を渡して、datalistの値を一次元配列に変更
sum_data = sum(datalist,[])
sum_data

この一元配列を渡し、円グラフを作ってみましょう。

plt.pie(sum_data, labels=data, autopct='%1.1f%%',startangle=45)
plt.show()

エラーが解消されました!

次にこの円グラフのx軸に「200万未満」と表示させるために、「xlabel」を使ってみます。

plt.pie(sum_data, labels=data, autopct='%1.1f%%',startangle=45)
#xlabelに出力する文字列を指定
plt.xlabel('200万未満')
plt.show()

今回は同じやり方で「800万円以上の方」のデータを円グラフ化し、
「xlabel」ではなく「title」を使ってみます。

sum800_data = sum((data.loc[['800万円以上']]).values.tolist(),[])
sum800_data

plt.pie(sum800_data,labels=data,autopct='%1.1f%%',startangle=45)
#円グラフのタイトル(titleに出力する文字列を指定)
plt.title('800万円以上の円グラフ')

「200万円未満の方」は「真ん中あたり」が多いことに比べて、
「800万円以上の方」は「やや上の方」が一番多いことがわかります。

次は円グラフの特定部分を突出させる機能「explode」を使い、
「200万円未満の方」と「800万円以上の方」の中から一番高いパーセント部分を突出させてみます。

円グラフの特定部分を突出させる

今回は一番パーセントが高い部分を特定して突出させたいので、
まずはリストを作り、何番目のデータが一番高いかを確認し、リストに渡します。

先に、「data」と同じサイズの配列を作り、0.0を格納します。

max800_data = []
max200_data =[]
for i in data:
    max800_data.append(0.0)
    max200_data.append(0.0)
max800_data

max200_data

その後、「index」と「max」機能を使い、
①200万未満のデータ(sum_data)と800万以上のデータ(sum800_data)から
 一番大きい値が入っているインデックス番号を取得します。
②取得したインデックス番号に「どのくらい突出させるか」を数字で渡します。
 今回は0.5を渡します。

#200万円未満のデータ(sum_data)の中
#一番大きい数値が格納されているインデックス番号を取得し、0.5を格納する
max200_data[sum_data.index(max(sum_data))] = 0.5
max200_data

#800万円以上のデータ(sum800_data)の中
#一番大きい数値が格納されているインデックス番号を取得し、0.5を格納する
max800_data[sum800_data.index(max(sum800_data))] = 0.5
max800_data

それぞれ、最大値のインデックス箇所へ0.5が格納されました!
この0.5が格納されている部分が「突出する部分」になります。

引き続き、二つの円グラフを縦に出力するために「figure」と「subplot」を使います。

先ずは、「figure」にて円グラフの大きさを指定します。
その後「subplot」に行の数、列の数、表示される順番を指定します。

最後にplt.pie(explode = “”)へ「突出する部分」としてデータを作成した「max200_data」「max800_data」 を指定します。

#大きさを決める
plt.figure(figsize=(12,12))
#サブグラフ、引数は一番目から行、列、グラフが表示される順番を意味する
plt = subplot(2,1,1)
#explodeに0.5を格納した配列を渡します。(max800_data)
plt.pie(sum800_data,labels=data,autopct='%1.1f%%',startangle=45,explode=max800_data)
plt.title('800万円以上の円グラフ')
plt.xlabel('中学校3年生時の成績')
#サブグラフ、引数は一番目から行、列、グラフが表示される順番を意味する
plt.subplot(2,1,2)
#explodeに0.5を格納した配列を渡します。(max200_data)
plt.pie(sum_data, labels=data, autopct='%1.1f%%',startangle=45,explode=max200_data)
plt.title('200万円未満の円グラフ')
plt.xlabel('中学校3年生時の成績')

「800万円以上の方」は「やや上の方」が、
「200万円未満の方」は「真ん中あたり」が、一番多い事が一目でわかります。

また、「Artist」クラスのサブクラスである「Circle」を使用するとドーナツグラフができます。

plt.figure(figsize=(7,7))
plt.title('800万円以上の円グラフ')
#pctdistanceはパーセントの数値を出力する位置
plt.pie(sum800_data,labels=data,autopct='%1.1f%%',startangle=45,pctdistance=0.8)
#(0,0)は中心を意味、0.6は60%の大きさ,fcに色を指定
center_circle = plt.Circle((0,0),1.0, fc='white')
#gcf = Get the current figure グラフを取得
fig = plt.gcf()
#gca = Get the current Axes 軸を取得
#artistクラスを追加CircleはArtistクラスのサブクラス
#現在のグラフの軸にcircleを追加する処理
fig.gca().add_artist(center_circle)

全体コード

import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm

#自分のロカール上にあるフォントパスを指定
font_location = 'C:\Windows\Fonts\BIZ-UDMinchoM.ttc'
#フォントパスにフォント名を取得
font_name = fm.FontProperties(fname=font_location).get_name()
#matplotlibにフォント情報を渡す
matplotlib.rc('font',family=font_name)

#CSVファイルをUTF-8形式で読み込む
data = pd.read_csv('gold3.csv',encoding = 'UTF8')
#dataを出力
data
data.plot()
#mataplotlibのpyplotを使いバーグラフを出力
data.plot(kind='bar')
#X軸の内容を45度で出力する
data.plot(kind='bar',rot=45)
#カラム名を指定するとそのカラムデータだけをとれる
data.上の方.plot(kind='bar',rot=45)
#locの中に行の200万円未満を指定すると200万円未満のデータをdataframeとして取得できる
data_200 = data.loc[['200万円未満']]
data_200
data_200.plot(kind='bar',rot=45)
#円グラフするデータを渡す
#labelsにdataを渡してdataにあるカラムを取得する
#autopctにパーセントを指定。以下の数字だと小数点一位まで表現する
#startangleに一番高いパーセントを45度の位置に表現することを指定
plt.pie(data_200,labels = data, autopct='%1.1f%%',startangle=45)
plt.show()
#data_200にある値だけを取得しリストに変更する
datalist = data_200.values.tolist()
datalist
plt.pie(datalist,labels = data, autopct='%1.1f%%',startangle=45)
plt.show()
#sum関数の二番目の引数に[]を渡して、datalistの値を一次元配列に変更
sum_data = sum(datalist,[])
sum_data
plt.pie(sum_data, labels=data, autopct='%1.1f%%',startangle=45)
#xlabelに出力する文字列を指定
plt.xlabel('200万未満')
plt.show()
sum800_data = sum((data.loc[['800万円以上']]).values.tolist(),[])
sum800_data
plt.pie(sum800_data,labels=data,autopct='%1.1f%%',startangle=45)
#円グラフのタイトルを指定
plt.title('800万円以上の円グラフ')
max800_data = []
max200_data =[]
for i in data:
    max800_data.append(0.0)
    max200_data.append(0.0)
max200_data
max800_data
#200万円未満のデータ(sum_data)の中
#一番大きい数値が格納されているインデックス番号を取得し、0.5を格納する
max200_data[sum_data.index(max(sum_data))] = 0.5
max200_data
#800万円以上のデータ(sum800_data)の中
#一番大きい数値が格納されているインデックス番号を取得し、0.5を格納する
max800_data[sum800_data.index(max(sum800_data))] = 0.5
max800_data
#大きさを決める
plt.figure(figsize=(12,12))
#サブグラフ、引数は一番目から行、列、グラフが表示される順番を意味する
plt = subplot(2,1,1)
#explodeに0.5を格納した配列を渡します。(max800_data,max200_data)
plt.pie(sum800_data,labels=data,autopct='%1.1f%%',startangle=45,explode=max800_data)
plt.title('800万円以上の円グラフ')
plt.xlabel('中学校3年生時の成績')
#サブグラフ、引数は一番目から行、列、グラフが表示される順番を意味する
plt.subplot(2,1,2)
plt.pie(sum_data, labels=data, autopct='%1.1f%%',startangle=45,explode=max200_data)
plt.title('200万円未満の円グラフ')
plt.xlabel('中学校3年生時の成績')
plt.figure(figsize=(7,7))
plt.title('800万円以上の円グラフ')
#pctdistanceはパーセントの数値を出力する位置
plt.pie(sum800_data,labels=data,autopct='%1.1f%%',startangle=45,pctdistance=0.8)
#(0,0)は中心を意味、0.6は60%の大きさ,fcに色を指定
center_circle = plt.Circle((0,0),1.0, fc='white')
#gcf = Get the current figure グラフを取得
fig = plt.gcf()
#gca = Get the current Axes 軸を取得
#artistクラスを追加CircleはArtistクラスのサブクラス
#現在のグラフの軸にcircleを追加する処理
fig.gca().add_artist(center_circle)

最後に

CSVファイルを使い、色々なグラフを作ってみました。
Pythonにはこのように便利なライブラリが多いですね。

まだ業務でPythonを使い開発をした経験はありませんが、
もっと勉強しPythonが使えるSEになりたいと思うくらい、スマートな言語だと感じました。

この記事で皆さんが少しでもPythonって便利で使いやすいな、と
感じていただけたら幸いです。

最後までお読みいただき、ありがとうございました。

梁 泰榮
CSVIT事業部 梁 泰榮
19新卒で、銀行システムの保守開発に従事しています。より多彩な言語やフレームワークが使いこなせるよう頑張ります。