散布図は回帰分析を行うにあたって変数同士の関係を可視化したり、データがどのようなグループに分かれているのかアタリを付けたりするのに役立ちます。散布図を描くにはscatter関数を使います。最低限必要なデータはxのリストとyのリストだけです。以下(リスト28、図17)の例は英語の成績と数学の成績を散布図にしたものです。
import matplotlib.pyplot as plt
english = [98, 77, 64, 45, 58, 62, 89, 30]
mathmatics = [88, 54, 72, 85, 70, 81, 63, 27]
plt.scatter(english, mathmatics, marker='*')
plt.xlabel('English')
plt.ylabel('Math')
図17 英語と数学の成績を散布図にしたものここまでは、収集したデータの特徴を見付けたり、分析のための手かがりを得たりするためにグラフを作成してきましたが、ここでは、分析した結果を基にその特徴を可視化する例を見てみます。架空の例ですが、表1は、クラスタリングにより、顧客データを5つのクラスタに分けたときに、それぞれのクラスタに各年齢の人が何人いるかを集計したものです。
| クラスタ\年齢 | 10〜19 | 20〜29 | 30〜39 | 40〜49 | 50〜 |
|---|---|---|---|---|---|
| 0 | 12 | 25 | 54 | 12 | 8 |
| 1 | 14 | 36 | 44 | 8 | 9 |
| 2 | 0 | 1 | 12 | 48 | 65 |
| 3 | 4 | 4 | 0 | 65 | 23 |
| 4 | 1 | 5 | 8 | 14 | 74 |
この表にまとめられた値をヒートマップで表してみます。ヒートマップとは、値を色で分けたもので、一般に値が大きくなるほど色が濃くなります。天気予報や地理情報などで、気温が高い地域ほど赤く、低い地域ほど青く表示される地図がありますが、そういったものを想像してもらうといいでしょう。先に実行例を見ておきます(図18)。
図18 ヒートマップの作成例ヒートマップは、seabornモジュールのheatmap関数を使えば簡単に作成できるのですが(これについては後で補足します)、ここでは、画像の作成や操作のための基礎ともなるので、あえて自分で色を塗り分ける方法でやってみましょう。そういうわけで、ちょっと回り道になりますが、ヒートマップそのものの作成の前に、画像を自分で作成する方法から見ていきます。既に画像の作り方について理解しているという方は、独力でヒートマップを作るか、コードの作成例のところまで読み飛ばしてもらってもけっこうです。ここから、ステップを分けて進めます。まずは、モノクロ画像(グレースケール画像)の作成からです。
リスト29のように二次元のリストを用意しておき、各点の色の濃さを指定します。あとはmatplotlib.pyplotモジュールのimshow関数で表示するだけです(図19)。簡単ですね。
import matplotlib.pyplot as plt
data=[[1.0, 0.0, 1.0],
[0.5, 1.0, 0.2]]
plt.imshow(data, cmap='gray')
では、解説していきましょう。画像を表すデータdataは二次元のリストになっています。ここでは、2行3列の画像を表しています。以下の図20でインデックスとその位置の対応を見ると、書き方と意味がよく分かりますね。
確認のために穴埋め問題を出しておきましょう。以下のオレンジ色の部分はどのような値かを考えてみてください。その部分をクリックすると答えが表示されます。
リスト名のdataは行全体を表すので、リストの長さを求めるlen関数を使ってlen(data)の値を求めると2が返されます。また、data[0]は0行目全体(0行目の列全体)なのでlen(data[0])の値は3となります。
さて、ここで重要な注意点です。画像を表示するために使うimshow関数でモノクロ(グレースケール)画像を表示する際には、0.0が黒、1.0が白というわけではなく、最小値が黒、最大値が白となるということです。例えば、左上(0行0列目)の1.0を10.0に書き換えて実行すると、左上だけが白で、残りは黒や黒に近い色になります。
なお、色の濃さは上のように浮動小数点数で指定することもできますし、整数で指定することもできます。整数で指定する場合は0〜255という値を使うのが一般的です。以下のコードを実行すると、図19と同様の画像が表示されます。
import matplotlib.pyplot as plt
data=[[255, 0, 255],
[127, 255, 51]]
plt.imshow(data, cmap='gray')
続いて、カラー画像です。実は、ヒートマップはカラー画像を使わなくても作成できるのですが、カラー画像の作成もモノクロ画像の延長でできるので、ここで併せて説明しておくことにします。先を急ぐ方はこのステップを読み飛ばしてもらって結構です。
カラー画像を作成するには、モノクロ画像の各点の値の代わりに、[r, g, b]という形式のリストを指定するだけです(図21)。rは赤の度合い、gは緑の度合い、bは青の度合いです。不透明度aを含めた[r, g, b, a] という形式も使えます。いずれの値にも、0.0〜1.0までの浮動小数点数や0〜255の整数が指定できます。
図21 カラー画像を表示するためのリストカラー画像の場合、データは三次元のリストになりますが、最初のインデックスが行に、次のインデックスが列に、最後のインデックスがrgbそれぞれの色の度合いに当たると考えると分かりやすいですね。例えば、図21のdata[0][1]は0行1列目の色を表しますが、その0番目つまりdata[0][1][0]の値は231で、これが赤(r)の度合いを表します。同様に、data[0][1]の1番目つまりdata[0][1][1]の値は50で、これが緑(g)の度合いを表します。data[0][1] の2番目つまりdata[0][1][2] の値は245で、これが青(b)の度合いを表します。
カラー画像を表すリストを作る方法は、モノクロのリストから順を追って考えると分かりやすかったと思います。では、図21に示したようなカラー画像のデータを作って、表示してみましょう。ここでは、目盛りや軸を非表示にしてみます。
import matplotlib.pyplot as plt
data=[[[233, 55, 36], [231, 50, 245], [168, 245, 253]],
[[104, 223, 181], [247, 236, 80], [247, 203, 248]]]
plt.imshow(data)
plt.axis('off') # 目盛りや軸を非表示にする設定
実行例は図22の通りです。
表示する色の種類がある程度限られるのであれば、色を表すリストに変数名を付けておくと便利です。例えば、[0, 0, 0] にblackという名前を付けておき、[76, 178, 153] にgreenblueという名前を付けるなら、以下のように書けます。
black = [0, 0, 0] # 黒
greenblue = [76, 178, 153] # 緑青っぽい色
さらに、画像の配色に何らかのルールがあるなら、そのルールに従ってコードを書けばさまざまな模様が描けますね。上の2つの色を使って、図23のような市松模様を表示する例を紹介しておきます。
市松模様がどのようなルールで表現できるかちょっと考えてみてください。作成された画像を眺めていると、0行0列、0行2列、1行1列、1行3列……が黒で、0行1列、0行3列、1行0列、1行2列……が緑青になっていることに気づくと思います。ということは、列位置+行位置の値が偶数であれば黒、そうでなければ緑青といった表し方ができますね。偶数であるかどうかは、2で割った余りが0であるかを調べれば分かります。もちろん、他にもやり方はありますが、以下のように書けます。
import matplotlib.pyplot as plt
black = [0, 0, 0] # 黒
greenblue = [76, 178, 153] # 緑青っぽい色
data = [[black if (x + y)% 2 == 0 else greenblue for x in range(10)] for y in range(10)]
plt.imshow(data)
リスト内包表記に慣れていないと、二重のリスト内包表記が理解しづらいかもしれません。また、条件式(三項演算子)と呼ばれることもあります)の、
式1 if 条件 else 式2
という書き方で、「条件を満たしたときには式1の値を返し、そうでないときは式2の値を返す」というのも、初めてだと面食らうかもしれません。if文を使った条件分岐すらこの連載ではまだ触れていないので、本来なら詳しく説明しないといけないところですが、このステップは「脇道」のお話なので、形式を示すにとどめ、詳しい説明はまたの機会とします。
ただ、リスト内包表記については前回も紹介したので、二重のリスト内包表記については簡単に説明を加えておきます。これについては、内側から細部を「つぶして」大まかに考えていくと理解しやすいと思います。まず、条件式の部分を、ざっくりと「何かの値を返す」と考えます。次に内側のリスト内包表記を「10列のリストにする」と考え、最後に一番外のリスト内包表記を「10行のリストにする」と考えればスッキリと理解できます。
画像の取り扱いについては、PNGファイルやJPEGファイルの画像を読み込んで、拡大/縮小する、回転するといった基本的な処理や、さまざまな現象の画像によるシミュレーションなど、興味深い例が数多くあります。それらについても、いずれ回を改めて紹介できればと思います。では、元のお話に戻りましょう。
実は、ステップ1の知識があれば、ヒートマップは作成できます。実行例を見ると、赤っぽい色で表示されているので、自分でカラー画像を作る必要があるかのように思われますが、あらかじめ決められた配色(カラーマップ)に従って、値に対応する色が表示されているだけなので、モノクロ画像が作成できればヒートマップが表示できます。データは二次元のリストにすればいいですね。
import matplotlib.pyplot as plt
cluster=[[12, 25, 54, 12, 8],
[14, 36, 44, 8, 9],
[ 0, 1, 12, 48, 65],
[ 4, 4, 0, 65, 23],
[ 1, 5, 8, 14, 74]]
plt.imshow(cluster, cmap='Reds') # 画像の作成(ヒートマップの作成)
plt.title('heatmap') # タイトルの指定
plt.xlabel('age') # X軸のラベル
plt.ylabel('cluster') # Y軸のラベル
plt.xticks(range(5), ['10-19', '20-29', '30-39', '40-49', '50-']) # 目盛りを置き換える
plt.show()
統計データの可視化に使われるseabornモジュールのheatmap関数を利用するのであれば、以下の3つの文を書くだけでヒートマップが作成できます。
これだけです。他のコードは必要ありません。ただし、ここでの実行例と同様にX軸の目盛りの設定やカラーマップの指定をするなら、sns.heatmap(cluster, xticklabels=['10-19', '20-29', '30-39', '40-49', '50-'], cmap="Reds")と書きます。ヒートマップを作成するためのデータ(cluster)として、ここではリストを使いましたが、pandasのデータフレームやnumpyのndarrayも使えます。
ここまでは、単一のグラフを描く例しか見てきませんでしたが、複数のグラフを並べて描き、それぞれの傾向や特徴を比較したいこともあるはずです。そのような場合には、まず、subplot関数を使って幾つかの描画領域(Axesオブジェクト)を作成します。それらの描画領域にグラフを描画するというわけです。Axesは「軸」や「座標軸」を意味するAxisの複数形ですが、取りあえずは描画領域を表すものだと考えればいいでしょう。
簡単な例で見てみましょう。y=x2とy=2xのグラフを比較するために、同じ描画領域に2つのグラフを描いた例と、複数の描画領域に並べて描いた例を見てみます(リスト34、図25)。数のグラフの並べて描画する方法については、図解で説明した動画も用意してあるので、ぜひ視聴してみてください。リスト34で使われている関数makedataは、前回作成したものと同じです。
import numpy as np
import matplotlib.pyplot as plt
def quadratic(x): # xの2乗
return x**2
def exponential(x): # 2のx乗
return 2**x
# 指定した関数funcを基に、xminからxmaxまで、step刻みでデータを作る(前回作成したもの)
def makedata(func, xmin, xmax, step, **args):
x = np.arange(xmin, xmax, step)
y = func(x, **args)
return x, y
# データを作る
qx, qy = makedata(quadratic, 0, 10, 0.1) # x=0から10まで0.1刻みで
ex, ey = makedata(exponential, 0, 10, 0.1)
# 単純に2つのグラフを描く
plt.figure(figsize=[7, 4])
plt.plot(qx, qy, label='x^2')
plt.plot(ex, ey, label='2^x')
plt.legend(loc=2)
plt.show() # ここまでをいったん表示
# 複数のグラフを並べて描く
plt.figure(figsize=[7, 4]) # デフォルトのサイズだと少し重なるのでやや横長に
# xの2乗のグラフ
ax1 = plt.subplot(121) # 1行2列の1つ目のグラフ
ax1.axis(ymax=1000) # y軸の最大値を1000とする
ax1.plot(qx, qy, color='C0', label='x^2')
ax1.legend(loc=2)
# 2のx乗のグラフ
ax2 = plt.subplot(122) # 1行2列の2つ目のグラフ
ax2.axis(ymax=1000)
ax2.plot(ex, ey, color='C1', label='2^x')
ax2.legend(loc=2)
plt.show() # 2つ目を表示(この行がなくても自動的に表示される)
図25 複数のグラフをまとめて描いた例と並べて描いた例以上、幾つかのグラフや設定を見てきましたが、紹介した内容はごく一部です。これら以外にも「こんなグラフが作りたい」「こんな設定にしたい」というさまざまな要求があるかと思います。が、基本的なグラフが描けるようになれば、あとはmatplotlib.pyplotの公式APIドキュメントなどを参照しながら自力で解決できると思います(サンプルも数多く提供されています)。
というわけで、今回も練習問題に取り組んでみましょう。
Copyright© Digital Advantage Corp. All Rights Reserved.