「モデルとデータの可視化」というテーマで各種グラフの描画方法を前後編で解説。後編である今回は、棒グラフ/ヒストグラム/箱ひげ図/散布図/ヒートマップを作成し、複数のグラフを並べて表示する方法を説明する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
前回は、「ビジュアライズ(可視化、視覚化)」というテーマの前編として、関数をグラフ化することによりモデルを可視化する方法を見ました。今回は後編です。収集したデータや分析結果を可視化するために、棒グラフやヒストグラム、散布図、ヒートマップなどを作成します。
今回の練習問題としては、3D散布図と個別の2D散布図を並べて描く例、回帰分析を行って散布図に回帰直線を重ねて描く例を取り上げます。もちろん、全て中学/高校までの数学の知識があれば作成できるプログラムです。グラフ化するデータの準備についてはある程度Pythonの経験がないと難しい部分もありますが、分からない部分については「おまじない」だと思ってサンプルコードをそのまま入力してもらって構いません。
見出し/図/リスト/脚注などの番号は、前編である前回からの続き番号となっています。
『数学×Pythonプログラミング入門 ― 中学・高校数学で学ぶ』
この連載では、中学や高校で学んだ数学を題材にして、Pythonによるプログラミングを学びます。といっても、数学の教科書に載っている定理や公式だけに限らず、興味深い数式の例やAI/機械学習の基本となる例を取り上げながら、数学的な考え方を背景としてプログラミングを学ぶお話にしていこうと思います。
筆者紹介: IT系ライター、大学教員(非常勤)。書道、絵画を経て、ピアノとバイオリンを独学で始めるも学習曲線は常に平坦。趣味の献血は、最近脈拍が多く98回で一旦中断。
前回は、折れ線グラフを使って関数のグラフを描く方法を見てきましたが、実用面を考えると、数式をグラフ化する方法だけでなく、収集したデータや分析結果をグラフ化する方法についても身に付けておきたいところです。目的に合わせてさまざまな種類のグラフを作成したいですね。
そこで、これだけ知っていればあとは自力で調べながら必要なグラフが描ける、というレベルに到達できる基本的な事例を幾つか紹介することにします。以下のようなグラフが作成できることを目指しましょう。
また、複数のグラフを使った比較を行うために、以下の方法についても紹介します。
以下、数学的に難しい概念や計算は出てきませんが、pandasモジュールを使って分析のためのデータを作成する方法やmatplotlib.pyplotモジュールのさまざまなグラフ作成機能など、より実用的な機能の利用について見ていきます。今回は小さなサンプルプログラムばかりなので、作成から実行までの大きな流れが把握しづらいことはないと思います。というわけで[1]〜[5]までの動画は用意していません([6]以降の動画は用意されているので、後ほどご覧ください)。
棒グラフは、数値の規模を見たり、数値を比較したりするのに役立ちます。棒グラフの作成には、matplotlib.pyplotモジュールのbar関数を使います。横軸のラベルとグラフ化するデータを用意しておけばグラフが描けます。以下の例は、東京都の幾つかの地点での2021年7月の月間降水量をグラフにしたものです(出典:気象庁の「過去の気象データ」)。
import matplotlib.pyplot as plt
location = ['Ome', 'Hachoji', 'Tokyo', 'Oshima', 'Miyakejima', 'Hachijojima']
amount = [248.5, 273.0, 310.0, 434.5, 408.5, 229.0]
plt.bar(location, amount)
リスト21の実行例は図10の通りです。
複数の系列を描画するなら、最初の系列の幅(引数width)に負の値(例:-0.4)を指定し、2番目の系列の幅に正の値(例:0.4)を指定します。負の値を指定すると、横軸のラベルの左側に向かって棒の幅が広がり、正の値を指定すると、横軸のラベルの右側に向かって棒の幅が広がります。あとは、位置(引数align)を横軸の端(edge)に合わせるようにすれば2つの系列が並びます。2020年7月の月間降水量と2021年7月の月間降水量を比較してみましょう(出典:気象庁の「過去の気象データ」)。
import matplotlib.pyplot as plt
location = ['Ome', 'Hachoji', 'Tokyo', 'Oshima', 'Miyakejima', 'Hachijojima']
amount202007 = [337.5, 350.0, 370.0, 623.5, 746.5, 462.5]
amount202107 = [248.5, 273.0, 310.0, 434.5, 408.5, 229.0]
plt.bar(location, amount202007, width=-0.4, align='edge', label='2020/7')
plt.bar(location, amount202107, width=0.4, align='edge', label='2021/7')
plt.legend(loc=2)
実行例は図11の通りです。
複数の系列を並べるための設定については、図12の図解を見ると分かりやすいと思います。
ヒストグラムは棒グラフに似ていますが、度数分布表を基に頻度(ひんど:値の個数)を棒グラフにし、分布を可視化したものです。普通、棒と棒の間にスペースは設けません。といっても、いちいち度数分布表を作ってから、頻度を棒グラフにし、棒と棒の間にスペースが入らないように調整するという必要はありません。もちろん、そのようにしても作れますが、hist関数を使えば元のデータから直接ヒストグラムが作成できます。
以下の例は、架空の成績データ(ですが、某大学の授業での傾向に合わせて作ったものです)を基にヒストグラムを作成したものです。
データ数がある程度多くないとヒストグラムを描いてもつまらないので、GitHubに置いてあるCSVファイル(値をカンマで区切って表したテキストファイル)のデータを利用することにしました。ここでは、データ分析のために使われるpandasモジュールのread_csv関数を使ってCSVファイルを読み込むことにします。read_csv関数では、ファイルだけでなく、WebサイトからCSVファイルを取得することもできます。返されるデータはpandasのデータフレーム(DataFrame)と呼ばれる表形式のデータなので、直感的にも分かりやすく、扱いやすいと思います。以下の例では、データの形式と内容が分かるように、headメソッド*8を使って最初の5行だけ表示してあります。
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Gessys/math/main/data/score.csv')
df.head()
*8 メソッドは日本語にすると「方法」といった意味ですが、クラスに含まれる関数のことで、一般的な関数とは区別されます。Pythonでは例えば、モジュール名.hogehoge()なら「関数」、クラスインスタンス名.hogehoge()なら「メソッド」と呼ばれます。ただし、hogehoge()という記載だけの場合など、「メソッドなのか、関数なのか」の見分けが付かないこともあります。見分けが付かなくても実用上の問題は基本的にありませんが、メソッドか関数かを見分けたい場合は、print(hogehoge)のようなコードで関数名/メソッド名を指定してその情報を出力すると、関数の場合は「<function ……>」のように、メソッドの場合は「<bound method ……>」のように表示されるので、どちらかを判別できます。
実行例は図13のようになります。CSVファイルには数値も全て文字列として入力されていますが、数値として解釈できる場合は、自動的に数値に変換されます(ここでは成績の値は整数int64に変換されます)。
では、ヒストグラムを作成してみましょう。列のデータはデータフレームに['列名']を指定すると取り出せます。返されるデータはpandasのSeriesと呼ばれる形式ですが、そのままhist関数に指定できます。Seriesは日本語に訳しにくいのでそのまま「シリーズ」と呼ばれますが「一連」や「連続」といった意味です。「系列」と訳されることもあります。
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('https://raw.githubusercontent.com/Gessys/math/main/data/score.csv')
scores = df['成績'] # 「成績」列データを取得
plt.hist(scores, bins=8, range=[20, 100])
実行例は図14の通りです。
上の例では、matplotlib.pyplotモジュールのhist関数を使ってヒストグラムを作成しましたが、pandasデータフレームのhistメソッドを使ってヒストグラムを作成することもできます。同様に折れ線グラフ(plot)、棒グラフ(plot.bar)、散布図(plot.scatter)なども描けます。ただし、この記事ではmatplotlib.pyplotモジュールの機能を使ってグラフを描画することにします。
import matplotlib.pyplot as plt # なくても動くが、plt.show()のために書いた
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Gessys/math/main/data/score.csv')
df.hist(column='成績', bins=8, range=[20, 100])
plt.show()
実行例は図15の通りです。
この例では、「成績」という列の見出しが日本語文字なので、フォントが正しく表示できないという警告メッセージが表示されます。これはmatplotlib.pyplotでplt.title('成績')と指定し、グラフのタイトルを指定した場合も同じです。グラフの上に「成績」と表示されず、文字化けしているのはそのためです(適切な日本語フォントを指定することで文字化けを回避できますが、Colabで回避するには「こちらの記事」を参考にしてみてください)。
箱ひげ図は、四分位範囲(全体の順位の1/4〜3/4に当たる範囲)を「箱」で表し、四分位範囲から一定の値だけ離れた位置を「ひげ」で表して全体の分布を可視化したものです。さらに、ひげの外側にある外れ値も表示されます。後の実行例を見るとそれぞれどのように表示されるかが分かります。ちなみに、2017年に告示され、2021年から全面実施に移された学習指導要領では、統計的な考え方がますます重要になることが反映され、四分位範囲と箱ひげ図が中学の数学で取り扱うテーマになりました。
リスト26の例は、英語(english)と数学(mathmatics)の成績(架空のデータ)を基に箱ひげ図を作ったものです。箱ひげ図を作成するには、matplotlib.pyplotモジュールのboxplot関数に値のリストを指定します。
import matplotlib.pyplot as plt
english = [98, 77, 64, 45, 58, 62, 89, 30]
mathmatics = [88, 54, 72, 85, 70, 81, 63, 27]
plt.boxplot([english, mathmatics],labels=['english', 'mathmatics'])
plt.show()
実行例は図16の通りです。
箱ひげ図の基となる四分位数についても求めておきましょう。リスト27の例では、英語の成績についての要約統計量を求めています。数学の成績については、この例を参考にして、練習問題として取り組んでいただくといいでしょう。
import pandas as pd
english = [98, 77, 64, 45, 58, 62, 89, 30]
mathmatics = [88, 54, 72, 85, 70, 81, 63, 27]
sr_e = pd.Series(english) # リストをpandasのSeriesに変換
print(sr_e.describe()) # describeメソッドを使って要約統計量を求める
# 数学の要約統計量を求めるためのコードは、ここに書くとよい
#出力例:
count 8.00000
mean 65.37500
std 22.33471
min 30.00000
25% 54.75000
50% 63.00000
75% 80.00000
max 98.00000
dtype: float64
(答え) 数学の要約統計量をsr_mとすると以下のようになります。
sr_m = pd.Series(mathmatics)
print(sr_m.describe())
出力例のうち、箱やひげを描くのに使われる値として、以下の値が求められています。
図16を見ると、第1四分位数(以下「Q1」と略します)から第3四分位数(以下「Q3」と略します)の範囲に箱が描かれていることが確認できますね。この範囲を四分位範囲と呼びます。ここでは、四分位範囲はQ3−Q1=80.0−54.75=25.25です。
ひげの端の位置については、ちょっとした計算が必要です。以下、標準の設定での計算方法を示しておきます。
英語の場合、ひげの外側に値が存在しないので、外れ値と見なせる値は存在しません。
数学の成績についても、コードを入力してそれぞれの値を求め、同様に計算してみてください。以下のオレンジ色の部分をクリックすると、答えが表示されます。
27点という外れ値の存在も分かります。
Copyright© Digital Advantage Corp. All Rights Reserved.