9. Pythonによるデータ分析
データフレーム(DataFrame)
Pythonでは表形式のデータを「データフレーム」と呼ぶ.データフレームは行と列から構成され,各行が1つのレコード(データの1件分),各列が1つの属性に対応する.各列には列名とデータ型が設定される.同様のデータ構造は,以下のように各システムで異なる名称で呼ばれている:
リレーショナルデータベース:テーブル(Table)
Microsoft Excel:ワークシート(Worksheet)
Python:データフレーム(DataFrame)
演習準備
この演習では Python を使用する。Python がインストールされていない場合は,下記の「Python 3.12 のインストール(Windows 上)」を展開し,手順に従いインストールすること。下記の「必要なライブラリのインストール」を実施すること。
Python 3.12 のインストール(Windows 上) [クリックして展開]
以下のいずれかの方法で Python 3.12 をインストールする。Python がインストール済みの場合、この手順は不要である。
方法1:winget によるインストール
管理者権限のコマンドプロンプトで以下を実行する。管理者権限のコマンドプロンプトを起動するには、Windows キーまたはスタートメニューから「cmd」と入力し、表示された「コマンドプロンプト」を右クリックして「管理者として実行」を選択する。
winget install -e --id Python.Python.3.12 --scope machine --silent --accept-source-agreements --accept-package-agreements --override "/quiet InstallAllUsers=1 PrependPath=1 AssociateFiles=1 InstallLauncherAllUsers=1"
--scope machine を指定することで、システム全体(全ユーザー向け)にインストールされる。このオプションの実行には管理者権限が必要である。インストール完了後、コマンドプロンプトを再起動すると PATH が自動的に設定される。
方法2:インストーラーによるインストール
- Python 公式サイト(https://www.python.org/downloads/)にアクセスし、「Download Python 3.x.x」ボタンから Windows 用インストーラーをダウンロードする。
- ダウンロードしたインストーラーを実行する。
- 初期画面の下部に表示される「Add python.exe to PATH」に必ずチェックを入れてから「Customize installation」を選択する。このチェックを入れ忘れると、コマンドプロンプトから
pythonコマンドを実行できない。 - 「Install Python 3.xx for all users」にチェックを入れ、「Install」をクリックする。
インストールの確認
コマンドプロンプトで以下を実行する。
python --version
バージョン番号(例:Python 3.12.x)が表示されればインストール成功である。「'python' は、内部コマンドまたは外部コマンドとして認識されていません。」と表示される場合は、インストールが正常に完了していない。
演習
pandasデータフレームを使用した散布図の作成
pandasのデータフレームを使用して2次元平面上の5つの点を散布図として描画する.まずデータフレームを作成し,x列とy列にそれぞれ5つの数値データを追加する.x列には0から4までの連続した整数,y列には4から7までの値を格納する.matplotlibライブラリのpyplotモジュールを用いて,データフレームの2つの列を指定して散布図を作成し表示する.
import pandas as pd
import matplotlib.pyplot as plt
# データフレームを作成
A = pd.DataFrame()
A['x'] = [0, 1, 2, 3, 4]
A['y'] = [5, 7, 5, 6, 4]
# scatter()関数でデータフレームの2列を指定して散布図をプロット
plt.scatter(A['x'], A['y'])
plt.show()
Irisデータセットを使用した散布図の作成
scikit-learnライブラリに含まれるIrisデータセットを使用する.このデータセットは機械学習の入門や教育でよく使用される標準データセットであり,アヤメの花の特徴量(がく片と花弁の長さ・幅)と品種の情報が含まれている.pandasのデータフレームの列には,数値や文字列の列名を付与できる.Irisデータセットでは,scikit-learnのiris.feature_namesとしてsepal length (cm),sepal width (cm),petal length (cm),petal width (cm)の4つの列名が定義されている.さらに,品種情報を格納するspecies列をプログラム中で追加する.
このプログラムは,scikit-learnライブラリからIrisデータセットを読み込み,データフレームとして整形した後,がく片の特徴を散布図として可視化する.まず,load_iris関数でデータセットを取得し,データフレームを作成する.次に,pd.Categorical.from_codesを用いて,iris.targetの数値(0, 1, 2)をiris.target_namesの品種名に対応付ける.この品種情報をカテゴリカルデータとしてspecies列に追加する.がく片の長さ(sepal length)とがく片の幅(sepal width)を用いて散布図を作成し表示する.
from sklearn.datasets import load_iris
import pandas as pd
import matplotlib.pyplot as plt
# scikit-learnからIrisデータセットを読み込み
iris = load_iris()
# データフレームを作成
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df['species'] = pd.Categorical.from_codes(iris.target, iris.target_names)
# がく片の長さと幅を使用して散布図をプロット
plt.scatter(df['sepal length (cm)'], df['sepal width (cm)'])
plt.show()
Irisデータセットを使用した品種別の散布図作成
前節と同様にIrisデータセットを読み込み,データフレームを作成する.がく片の長さ(sepal length)とがく片の幅(sepal width)を用いて散布図を作成し,iris.targetに含まれる品種のインデックス情報を用いて点の色分けを行う.ここではplt.colorbarを使用して色と品種の対応を表示する.plt.colorbarは連続値のカラーバーを表示するため,カテゴリカルデータの凡例としては簡易的な表示となる.離散的な凡例の表示方法は次節で扱う.
from sklearn.datasets import load_iris
import pandas as pd
import matplotlib.pyplot as plt
# scikit-learnからIrisデータセットを読み込み
iris = load_iris()
# データフレームを作成
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df['species'] = pd.Categorical.from_codes(iris.target, iris.target_names)
# 品種別に色分けした散布図をプロット(iris.targetで色分け)
plt.scatter(df['sepal length (cm)'], df['sepal width (cm)'], c=iris.target)
# 凡例を追加(品種名を表示)
plt.colorbar(label='Species')
plt.show()
主成分分析による次元削減と可視化
Irisデータセットは4つの特徴量を持つため,そのままでは2次元平面上に全情報を表示できない.主成分分析(PCA)は,データの分散が大きい方向を抽出することで,情報の損失を抑えながら次元を削減する手法である.ここでは,PCAを適用して4次元の特徴量を2次元に削減し,その結果を散布図として可視化する.
Irisデータセットを読み込み,データフレームを作成する.scikit-learnのPCAクラスを使用して2つの主成分を抽出し,第1主成分と第2主成分を軸とする散布図を作成する.品種別の色分けにはiris.targetを使用する.scatter.legend_elements()を用いて散布図から凡例用の要素を自動生成し,品種名の離散的な凡例を追加する.
from sklearn.datasets import load_iris
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
# scikit-learnからIrisデータセットを読み込み
iris = load_iris()
# データフレームを作成
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df['species'] = pd.Categorical.from_codes(iris.target, iris.target_names)
# PCAの実行(4次元から2次元に削減)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(iris.data)
# PCA結果の散布図をプロット
scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=iris.target)
# 品種名の凡例を追加
plt.legend(handles=scatter.legend_elements()[0],
labels=iris.target_names,
title='品種')
plt.show()
PCA結果へのラベルとアノテーションの追加
前節のPCAによる可視化を拡張し,グラフに軸ラベル,タイトル,データポイントへのアノテーション,グリッド線を追加する.Irisデータセットを読み込み,PCAで2次元に削減した後,Set1カラーマップを使用して品種別に色分けした散布図を作成する.plt.annotateで各データポイントの近くに品種名を表示し,軸ラベル,タイトル,凡例を設定する.このプログラムでは150個のデータポイントすべてにアノテーションを表示するため,文字が重なりグラフが見づらくなる場合がある.
from sklearn.datasets import load_iris
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
# scikit-learnからIrisデータセットを読み込み
iris = load_iris()
# データフレームを作成
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df['species'] = pd.Categorical.from_codes(iris.target, iris.target_names)
# PCAの実行(4次元から2次元に削減)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(iris.data)
# グラフ領域のサイズを設定
plt.figure(figsize=(10, 6))
# PCA結果の散布図をプロット(Set1カラーマップを使用)
scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=iris.target, cmap='Set1')
# 各データポイントに品種名を表示
for i in range(len(df)):
plt.annotate(df['species'][i],
(X_pca[i, 0], X_pca[i, 1]),
xytext=(5, 5), # テキストのオフセット
textcoords='offset points', # オフセットの単位
fontsize=8) # フォントサイズ
# グラフのX軸とY軸にラベルを追加
plt.xlabel('第1主成分')
plt.ylabel('第2主成分')
# グラフのタイトルを追加
plt.title('Irisデータセット:PCAによる2次元可視化(品種名付き)')
# 品種名の凡例を追加
plt.legend(handles=scatter.legend_elements()[0],
labels=iris.target_names,
title='品種')
# グリッド線を表示
plt.grid(True)
# グラフを表示
plt.show()
メッシュグリッドと応用
numpy.arange関数による数値列の生成
Pythonでは,区間[s, t)の数値列(sで始まり,tの値を含まない数値列)は,numpy.arangeを用いて生成できる.
numpy.arange関数を使用して2種類の数値列を生成する.まず,変数aには開始値0,終了値10,刻み幅2の数値列を生成して格納する.これにより,0から始まり10未満までの偶数列(0, 2, 4, 6, 8)が得られる.次に,変数bには開始値0,終了値10,刻み幅1の数値列を生成して格納する.これにより,0から始まり10未満までの連続した整数列(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)が得られる.
import numpy as np
# 開始値0,終了値10,刻み幅2の数値列を生成(偶数列)
a = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
print(a)
# 開始値0,終了値10,刻み幅1の数値列を生成(連続整数列)
b = np.arange(0, 10, 1) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(b)
メッシュグリッドの生成
メッシュグリッドは,2次元平面上の格子点を表現するデータ構造である.2次元関数の値を計算したり,2次元平面上の分布を可視化したりする際に使用する.
numpy.arange関数を用いて格子点のx座標とy座標を表す数値列を生成し,それらからメッシュグリッドを作成する.まず,変数xxとyyに-1から1未満までの刻み幅0.1の数値列を生成する.次に,numpy.meshgrid関数を用いてこれらの数値列から2つの2次元配列pxとpyを生成する.pxは各列が同じx座標値を持ち,pyは各行が同じy座標値を持つ.
注:Pythonのコード中では,\n(バックスラッシュとn)が改行文字を表す.日本語環境のフォントによっては¥nと表示される場合があるが,同じ文字である.
import numpy as np
# x方向とy方向の数値列を生成(-1から1未満まで,刻み幅0.1)
xx = np.arange(-1, 1, 0.1) # x方向の座標値の配列
print("x方向の数値列:")
print(xx)
yy = np.arange(-1, 1, 0.1) # y方向の座標値の配列
print("\ny方向の数値列:")
print(yy)
# meshgrid関数で2次元配列を生成
px, py = np.meshgrid(xx, yy) # メッシュグリッドの生成
# x座標の2次元配列を表示(各列が同じx座標値)
print("\nx座標の2次元配列:")
print(px)
# y座標の2次元配列を表示(各行が同じy座標値)
print("\ny座標の2次元配列:")
print(py)
メッシュグリッドを用いた2次元関数の可視化
メッシュグリッドは2次元関数の可視化に有用である.ここでは,f(x, y) = x² + y²をメッシュグリッド上で計算し,2種類の方法で可視化する.左側のサブプロットではplt.pcolorを用いて関数値を色の濃淡で表現する(疑似カラープロット).右側のサブプロットではplt.contourを用いて関数値が等しい点を線で結んだ等高線を描画する.
import numpy as np
import matplotlib.pyplot as plt
# 2次元関数f(x,y)の定義
def f(x, y):
return x * x + y * y
# メッシュグリッドの生成(-1から1未満まで,刻み幅0.1)
xx = np.arange(-1, 1, 0.1)
yy = np.arange(-1, 1, 0.1)
px, py = np.meshgrid(xx, yy)
# グラフ領域を2分割して描画
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1) # 疑似カラープロット
plt.pcolor(px, py, f(px, py))
plt.colorbar()
plt.subplot(1, 2, 2) # 等高線表示
plt.contour(px, py, f(px, py))
plt.show()
numpy.mgridによるメッシュグリッドの生成
numpy.meshgrid関数と同様の処理を行う方法として,numpy.mgridがある.numpy.mgridを使用すると,スライス記法開始値:終了値:刻み幅により,arangeとmeshgridの2段階の処理を1行で記述できる.刻み幅が実数の場合,終了値は含まれない(半開区間).刻み幅に虚数(例:5j)を指定した場合は,虚数の整数部分が分割数となり,開始値と終了値の間を等分割する.この場合,終了値を含む(閉区間).
以下の例では,-2から2未満までの範囲を刻み幅0.5で分割した2次元のメッシュグリッドを生成する.
import numpy as np
# numpy.mgridによるメッシュグリッドの生成
x, y = np.mgrid[-2:2:.5, -2:2:.5]
print("x座標の2次元配列:")
print(x)
print("\ny座標の2次元配列:")
print(y)
PCAで2次元に削減したIrisデータに対する混合ガウス分布
PCAで2次元に削減したIrisデータに対して混合ガウス分布(GMM)をフィットさせ,その確率密度関数を表示する.まず,GaussianMixtureモデルを作成し,Irisデータセット全体を用いて学習を行う.次に,numpy.mgridを用いて-4から4未満までの範囲を刻み幅0.01の細かいメッシュグリッドとして生成し,各格子点でGMMの確率密度を計算する.gmm.score_samplesは各データ点の対数尤度(log-likelihood)を返すため,np.expで指数変換することで確率密度を得る.
メッシュグリッドから得られる2つの2次元配列xとyにnp.dstack(第3軸方向の結合)を適用して座標のペアを作成し,reshape(-1, 2)でscore_samplesが受け付ける2列の形状に変換する.計算結果を元のメッシュグリッドの形状に戻すために,reshape(x.shape)を適用する.
可視化では,12x5インチの図領域に2つのサブプロットを作成する.左側のサブプロットでは,plt.contourfを用いて確率密度を塗りつぶし等高線として表示し,その上にPCA変換後のデータ点を品種別に色分けした散布図として重ねる.右側のサブプロットでは,plt.contourを用いて確率密度の等高線を表示し,同様にデータ点を重ねる.両方のサブプロットにカラーバーを追加し,確率密度の大きさを示す.
import numpy as np
from sklearn.mixture import GaussianMixture
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
# scikit-learnからIrisデータセットを読み込み
iris = load_iris()
# PCAの実行(4次元から2次元に削減)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(iris.data)
# 混合ガウス分布モデルの学習
gmm = GaussianMixture(n_components=3, random_state=42)
gmm.fit(X_pca)
# メッシュグリッドの作成と確率密度の計算
x, y = np.mgrid[-4:4:.01, -4:4:.01]
pos = np.dstack((x, y))
z = np.exp(gmm.score_samples(pos.reshape(-1, 2))).reshape(x.shape)
# グラフ領域を2分割して描画
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1) # 確率密度の塗りつぶし等高線と散布図
plt.contourf(x, y, z, levels=20, cmap='viridis')
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=iris.target, cmap='Set1', alpha=0.5)
plt.colorbar()
plt.subplot(1, 2, 2) # 確率密度の等高線と散布図
plt.contour(x, y, z, levels=20, cmap='viridis')
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=iris.target, cmap='Set1', alpha=0.5)
plt.colorbar()
plt.show()
クラスタリング分析
Irisデータセットに対するk-meansクラスタリング
Irisデータセットの全特徴量に対してk-meansクラスタリングを適用し,その結果を表示する.k-meansは,データ点を指定した数のクラスタに分割する手法であり,各データ点を最も近いクラスタ中心に割り当てる.混合ガウス分布(GMM)が確率的にクラスタを割り当てるのに対し,k-meansは各データ点を1つのクラスタに確定的に割り当てる.
scikit-learnのKMeansクラスを使用して,クラスタ数を3に設定したクラスタリングを実行する.k-meansは4次元の全特徴量空間でクラスタリングを行うが,散布図として表示する際には4次元を直接描画できないため,最初の2つの特徴量(がく片の長さとがく片の幅)を軸に使用する.クラスタ中心についても同様に,4次元の中心座標のうち最初の2次元を表示している点に注意する.
from sklearn.cluster import KMeans
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
# データの準備
iris = load_iris()
X = iris.data # 全特徴量を使用
# k-meansクラスタリングの実行
kmeans = KMeans(n_clusters=3, random_state=42)
clusters = kmeans.fit_predict(X)
# グラフの作成とクラスタリング結果の可視化
plt.scatter(X[:, 0], X[:, 1], c=clusters, cmap='viridis')
# クラスタ中心の表示
plt.scatter(kmeans.cluster_centers_[:, 0],
kmeans.cluster_centers_[:, 1],
c='red',
marker='x',
s=200,
linewidths=3,
label='クラスタ中心')
# グラフの設定と表示
plt.title('Irisデータセット:k-meansクラスタリング結果')
plt.legend()
plt.show()