Skip to content

3. データ可視化

データの傾向やパターンを直感的に把握するために、データ可視化は機械学習のプロセスにおいて欠かせない技術です。本章では、Python の代表的な可視化ライブラリである Matplotlib と Seaborn を使ったグラフ描画の基礎から応用までを学び、最後に探索的データ分析(EDA)の手法を紹介します。

3.1 機械学習とデータ可視化

データをグラフにすると、分布、外れ値、特徴量間の関係を数値表より早く把握できる場合があります。モデルの学習前後で、何を確認するために可視化するのかを整理します。

3.1.1 データ理解のための可視化

機械学習のモデルを構築する前に、まずデータを理解することが重要です。数千、数万行にも及ぶデータを数値の羅列として眺めても、そこから意味のある情報を読み取ることは困難です。しかし、適切なグラフで可視化することで、以下のような重要な情報を瞬時に把握できます。

  • データの分布:ヒストグラムや箱ひげ図で、データがどのように分布しているかを確認することができる
  • 外れ値の検出:散布図で、異常な値や外れ値を視覚的に確認することができる
  • 特徴量間の関係:相関図やペアプロットで、変数間の相関関係を把握することができる
  • クラスの偏り:円グラフや棒グラフで、分類問題におけるクラスの不均衡を確認することができる

これらの情報は、モデル選択や前処理の方針を決める重要な判断材料となります。

3.1.2 モデル評価のための可視化

モデルの評価では、単一のスコアだけでなく、誤差の推移やクラスごとの間違い方も確認します。グラフを併用すると、過学習や特定クラスへの偏りを見つけやすくなります。

  • 学習曲線:訓練誤差と検証誤差の推移を可視化し、過学習や未学習の兆候を確認することができる
  • 混同行列:分類モデルの予測結果をヒートマップで表現し、どのクラスで誤りが多いかを把握することができる
  • ROC 曲線:しきい値を変化させた際のモデル性能を比較し、識別能力を評価することができる
  • 特徴量の重要度:どの特徴量が予測に強く寄与しているかを棒グラフなどで可視化することができる

これらの可視化により、単なる精度の数値だけでは見えない、モデルの強みや弱点を分析することが可能になります。

3.1.3 結果の伝達のための可視化

機械学習の成果を他者に説明する際、可視化は強力な伝達の手段となります。専門知識を持たない人にも、グラフを通じて分析結果や予測の根拠を直感的に伝えることができます。

機械学習プロジェクトにおける可視化の役割

機械学習のワークフローでは、目的に応じて可視化を使い分けます。探索時は分布や外れ値、評価時は学習曲線や混同行列、説明時は予測結果と根拠を示すグラフが候補になります。

本章では、MatplotlibとSeabornを使い、目的に合うグラフを作成・調整する方法を学びます。

3.1.4 Python によるデータ可視化

Python には、データ可視化を行うためのツールがさまざま提供されています。特に、オープンソースのライブラリである Matplotlib や Seaborn は、柔軟で詳細なカスタマイズが可能なグラフ作成を強力にサポートしてくれます。これらのライブラリを使用することで、簡単な散布図から複雑なヒートマップや 3D プロットまで、多種多様な可視化を容易に実現できます。

Matplotlib

Matplotlib は、Python で最も広く使われている定番の可視化ライブラリです。細かいカスタマイズが自由自在にできる反面、最初は少し面倒に感じるところもあるかもしれませんが、Python によるデータ可視化を学ぶうえで欠かせません。

公式サイト:https://matplotlib.org/

ライブラリのインストールについて

通常、Python のライブラリは pip コマンドでインストールする必要がありますが、Matplotlib のような使用頻度の高い重要なライブラリは、Google Colab にはじめからインストールされています。Google Colab 以外の環境を使用している方は、必要に応じて各自でインストールしてください(例: pip install matplotlib seaborn)。

3.2 Matplotlib によるグラフ描画

3.2.1 Matplotlib のインポート

Matplotlib による可視化は、pyplot というサブモジュールを通して行われます。インポートは以下のようにして行います。ソースコードの冒頭で一度だけ書くようにしましょう。

import matplotlib.pyplot as plt

以下で紹介するコードは、matplotlib.pyplot モジュールがインポートされ、plt という省略表記で利用できる状態であることを前提としています。

3.2.2 折れ線グラフ

データをプロットして折れ線グラフを表示するには、以下のように pyplot.plot() 関数と pyplot.show() 関数を用います。

# x の値(横軸)
x = [0, 1, 2, 3, 4]

# y の値(縦軸)
y = [0, 1, 4, 9, 16]

# データをプロット
plt.plot(x, y)

# グラフの表示
plt.show()

折れ線グラフ

以下のように 1 行に収めることもできます。

plt.plot([1, 2, 3], [1, 4, 9])

plt.show() の省略について

本来の Python では、plt.plot() 関数のあとに plt.show() 関数を用いてグラフを表示する必要があります。しかし、Google Colab は plot() 関数を見つけると、「グラフを出力したいんだ」と解釈し、裏で自動的に show() 関数相当のことをしてくれるため、記述を省略することができます。

3.2.3 棒グラフ

棒グラフを表示するには、pyplot.bar() 関数を用います。

plt.bar(["A", "B", "C", "D"], [5, 7, 3, 12])

棒グラフ

横向きの棒グラフを表示する場合は、pyplot.barh() 関数を用います。

plt.barh(["A", "B", "C", "D"], [5, 7, 3, 12])

横向きの棒グラフ

3.2.4 散布図

散布図を表示するには、pyplot.scatter() 関数を用います。

plt.scatter([1, 3, 8, 5], [3, 6, 8, 4])

散布図

3.2.5 円グラフ

円グラフを表示するには、pyplot.pie() 関数を用います。各要素にラベルをつける場合は、以下のように labels オプションを指定します。

plt.pie([25, 35, 40], labels=["Good", "Normal", "Bad"])

円グラフ

デフォルトでは上の図のように、時計の 3 時の位置から反時計回りに円グラフが描かれます。これを、時計の 12 時の位置から時計回りに描きたい場合は、以下のように startangle オプションを 90 に、counterclock オプションを False に指定します。

plt.pie(
    [25, 35, 40],
    labels=["Good", "Normal", "Bad"],
    startangle=90,
    counterclock=False,
)

円グラフ2

3.2.6 ヒストグラム

ヒストグラムを表示するには、pyplot.hist() 関数を用います。ヒストグラムではデータの他に、区間(ビン)の数(bins)やビンの色(color, edgecolor)を指定することができます。

import numpy as np
import matplotlib.pyplot as plt

# 標準正規分布のデータを 300 個生成
data = np.random.randn(300)

# ヒストグラムを描画
plt.hist(
    data,
    bins=20,
    color="skyblue",
    edgecolor="black"
)
plt.xlabel("Value")
plt.ylabel("Frequency")
plt.show()

ヒストグラム

3.2.7 グラフの基本要素

グラフの基本要素として、次のものがあります。

  • 「タイトル 」(title)
  • 「横軸ラベル」(xlabel)
  • 「縦軸ラベル」(ylabel)
  • 「グリッド線」(grid)
  • 「凡例」(legend)

それぞれ以下のようにして使うことができます。

plt.plot(
    [1, 2, 3], [1, 4, 9],
    label="Sugoi Sen"      # 凡例のラベル
)
plt.title("Kakkoii Graph") # グラフタイトル
plt.xlabel("Yoko Label")   # 横軸ラベル
plt.ylabel("Tate Label")   # 縦軸ラベル
plt.grid(True)             # グリッド線の表示
plt.legend()               # 凡例の表示

グラフの基本要素

3.2.8 日本語フォントの利用

Matplotlib はデフォルトで日本語フォントに対応していないため、グラフのタイトルや軸ラベルなどに日本語を使うと、文字化け(「□□□」のような表示)が発生することがあります。これを解消する最も手軽な方法は、matplotlib-fontja というライブラリを利用することです。

!pip install matplotlib-fontja

先頭の ! は、Colab などのノートブックのセルからコマンドを実行するための記号です。.py ファイルとして実行する場合は、この行の代わりにターミナルで pip install matplotlib-fontja を実行してください。

次に、プログラムの冒頭でこのライブラリをインポートします:

import matplotlib_fontja

これで、Matplotlib のグラフで日本語が正しく表示されるようになります。以下は使用例です。

import matplotlib.pyplot as plt
import matplotlib_fontja

# 日本語を含むグラフの作成
plt.plot([1, 2, 3], [1, 4, 9], label="すごい線")
plt.title("かっこいいグラフ")
plt.xlabel("横ラベル")
plt.ylabel("縦ラベル")
plt.grid(True)
plt.legend()
plt.show()

日本語フォントの利用

CHIKUWA Editor における日本語対応

CHIKUWA Editor では日本語フォント対応が予め組み込まれているため、特に何も書かなくても日本語をそのまま使うことができます。Google Colab やその他の環境を利用する場合は、上記のインストールおよび import の対応が必要です。

3.2.9 グラフ用データの生成に便利な NumPy の関数

データ可視化の練習をするうえで知っておくと便利な NumPy の関数をいくつか紹介します。必要に応じて NumPy 公式 のドキュメントを参照するようにしてください。

データ生成系

数学・統計系

3.2.10 fig, ax スタイルによるグラフ描画

ここまでは、matplotlib.pyplot をpltとしてインポートし、plt.plot() 関数のようにしてグラフの描画を行いました。シンプルなグラフの描画であればこれでも十分ですが、複数のグラフ描画や細かい制御を行いたい場合は、fig, axスタイルがよく用いられます。

公式サイトのドキュメントを含む多くのサンプルコードでは、以下のような fig, ax を用いた記述が使われています。

import matplotlib.pyplot as plt

# グラフ描画の準備
fig, ax = plt.subplots()

# グラフの描画
ax.plot([1, 2, 3], [1, 4, 9], label="Sen")
ax.set_title("Title")
ax.set_xlabel("X label")
ax.set_ylabel("Y Label")
ax.legend()
ax.grid(True)
plt.show()

fig, ax スタイルによるグラフ描画

これまでの方法との違いをまとめると、以下のようになります。

要素 / 機能 plt スタイル fig, ax スタイル
描画の準備 - fig, ax = plt.subplots()
タイトル plt.title("Title") ax.set_title("Title")
X 軸ラベル plt.xlabel("X label") ax.set_xlabel("X label")
Y 軸ラベル plt.ylabel("Y label") ax.set_ylabel("Y label")
凡例 plt.legend() ax.legend()
グリッド線 plt.grid(True) ax.grid(True)
グラフ表示 plt.show() plt.show()

描画の準備のコードが追加されたことと、グラフ要素を表示する関数名に一部変化はありますが、基本的には plt が ax になったくらいで、大きな変化はありません。pyplot.subplots() 関数は複数のグラフ描画や柔軟なレイアウトを実現するためにするもので、上の例のように引数を省略すると単一のグラフが描かれることになります。

3.2.11 グラフのカスタマイズ

これまでに「タイトル」や「軸ラベル」「凡例」など、簡単なグラフ要素を紹介してきましたが、Matplotlib ではその他にもさまざまな要素を設定することができます。以下は、公式サイト で提供されている、グラフ要素一覧を確認できるチートシートです。

グラフ要素一覧
(Source: matplotlib.org)

さらに包括的なチートシートは、以下のリンクから確認することができます。このような情報を適宜参照しながら、洗練されたグラフを描くことを心がけるようにしてください。

Matplotlib cheatsheets and handouts:https://matplotlib.org/cheatsheets/

3.2.12 グラフ描画関数の一覧

これまでに折れ線グラフや棒グラフなど、基本的なグラフの描き方を紹介しました。ここからは、より高度なグラフについても紹介していきます。

Matplotlib によるグラフ描画関数のうち、特に重要なものの一覧を以下に記します。公式の Plot types や Examples にも同等の情報が掲載されていますので、必要に応じて参照するようにしてください。

グラフの種類 plt スタイル fig, ax スタイル
折れ線グラフ plt.plot() ax.plot()
棒グラフ plt.bar() ax.bar()
散布図 plt.scatter() ax.scatter()
円グラフ plt.pie() ax.pie()
ヒストグラム plt.hist() ax.hist()
箱ひげ図 plt.boxplot() ax.boxplot()
エラーバー付きグラフ plt.errorbar() ax.errorbar()
バイオリンプロット plt.violinplot() ax.violinplot()
ヒートマップ plt.imshow() ax.imshow()

3.2.13 箱ひげ図

箱は第1四分位数 Q1 から第3四分位数 Q3 までを表します。通常、ひげの端は Q1−1.5×IQR 以上、Q3+1.5×IQR 以下の範囲にある最端のデータ点です(IQR = Q3−Q1)。その範囲の外の点は外れ値の候補として個別に表示されます。

箱ひげ図を描くには、pyplot.boxplot() 関数を用います。以下は、標準正規分布に従う分布データを 2 つ生成し、箱ひげ図を描画するコード例です。

import matplotlib.pyplot as plt
import numpy as np

# 標準正規分布に従う分布データを生成
data = [
    np.random.randn(100),
    np.random.randn(100)
]

# 箱ひげ図の描画
fig, ax = plt.subplots()
ax.boxplot(data)
plt.show()

箱ひげ図

3.2.14 エラーバー付きグラフ

エラーバー付きグラフを描くには、pyplot.errorbar() 関数を用います。以下は、エラーバー付きグラフの描画例です。

import matplotlib.pyplot as plt

# データの準備
x = [1, 2, 3]
y = [2, 4, 3]
yerr = [0.2, 0.5, 0.3]

# エラーバー付きグラフの描画
fig, ax = plt.subplots()
ax.errorbar(x, y, yerr, fmt="-o")
plt.show()

エラーバー付きグラフ

3.2.15 バイオリンプロット

バイオリンプロットを描くには、pyplot.violinplot() 関数を用います。以下は、numpy.random.normal(平均値, 標準偏差, サンプル数) 関数を用いて 3 つの分布データを生成し、それを描画するコード例です。

import matplotlib.pyplot as plt
import numpy as np

# 平均値が異なる 3 つの分布データを生成
data = [
    np.random.normal(80, 10, 100),
    np.random.normal(100, 10, 100),
    np.random.normal(120, 10, 100)
]

# バイオリンプロットの描画
fig, ax = plt.subplots()
ax.violinplot(data)
plt.show()

バイオリンプロット

3.2.16 ヒートマップ

ヒートマップを描くには、pyplot.imshow() 関数を用います。ax.imshow() メソッドと書くだけでも描くことができますが、以下のように colorbar() 関数を使用してカラーバーを同時に描画することを推奨します。

import matplotlib.pyplot as plt
import numpy as np

# 5x5 の 2 次元データを作成
matrix = np.random.rand(5, 5)

# ヒートマップの描画
fig, ax = plt.subplots()
cax = ax.imshow(matrix)

# カラーバーの描画
fig.colorbar(cax)
plt.show()

ヒートマップ

デフォルトのカラーマップ(配色テーマ)は viridisと呼ばれるものになっていますが、imshow() 関数の引数で cmap を指定することで(例:ax.imshow(data, cmap="gray"))、さまざまな色合いに変更することができます。以下は代表的なカラーマップの例です。

  • viridis:デフォルト。視認性が高く、色覚異常を持つ人々にも見やすい。
  • plasma:色鮮やかで、印象的かつ色覚異常を持つ人々にも見やすい。
  • inferno:高コントラストで暗い背景に合う。
  • cividis:色覚多様性に完全対応。
  • gray:最も基本的なグレースケール。

3.2.17 複数グラフの描画

pyplot.subplots() 関数を使うと、簡単に複数のグラフを描画することができます。第 1 引数で行の数、第 2 引数で列の数を指定することができ、1×2 のグラフを描きたい場合は subplots(1, 2) のようにします。以下は、1×2 の折れ線グラフを描画する例です。subplots() 関数の引数で、figsize=(12, 5)とすることでグラフ全体の幅と高さを 12 インチ ×5 インチに指定し、sharey=True とすることで Y 軸を 2 つのグラフで共有する設定としています。

import matplotlib.pyplot as plt
import numpy as np

# データの生成
x = np.arange(100)
y1 = np.random.normal(100, 10, 100)
y2 = np.random.normal(80, 15, 100)
y3 = np.random.normal(60, 12, 100)
y4 = np.random.normal(45, 10, 100)

# 1x2 のプロット + Y 軸共有
fig, axs = plt.subplots(
    1, 2,
    figsize=(12, 5),
    sharey=True
)

# 左の折れ線グラフ
axs[0].plot(x, y1, label="Series A")
axs[0].plot(x, y2, label="Series B")
axs[0].set_title("Dataset 1")
axs[0].set_xlabel("Index 1")
axs[0].set_ylabel("Value")
axs[0].legend()

# 右の折れ線グラフ
axs[1].plot(x, y3, label="Series C")
axs[1].plot(x, y4, label="Series D")
axs[1].set_title("Dataset 2")
axs[1].set_xlabel("Index 2")
axs[1].legend()

# レイアウト調整 & 表示
plt.tight_layout()
plt.show()

複数グラフの描画

以下は、2×2 のグラフを描画する例です。

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)

fig, axs = plt.subplots(2, 2, figsize=(8, 6))

axs[0, 0].plot(x, np.sin(x))
axs[0, 0].set_title("sin(x)")

axs[0, 1].plot(x, np.cos(x))
axs[0, 1].set_title("cos(x)")

axs[1, 0].plot(x, np.tan(x))
axs[1, 0].set_title("tan(x)")

axs[1, 1].plot(x, np.exp(-x))
axs[1, 1].set_title("exp(-x)")

plt.tight_layout()
plt.show()

2×2 のグラフ描画

不自然な形のグラフ

tan(x) のグラフが少しおかしな形になってしまっています。値が急激に変化しても不自然にならないよう、ax.set_ylim(bottom, top)を使って見た目を整えてみましょう。

3.3 Seaborn によるグラフ描画

Seaborn は、Matplotlib をベースとした Python のデータ可視化ライブラリです。Seaborn を使うことで、見やすく美しいグラフをさらに簡単に作ることができます。以下では簡単な使用例のみを紹介しますので、必要に応じて公式のドキュメントを参考にするようにしてください。

Seaborn 公式サイト: https://seaborn.pydata.org/

3.3.1 Seaborn のインポート

Seaborn のインポートは以下のようにして行います。

import seaborn as sns

Seaborn 利用時の注意

Seaborn は Matplotlib 上に構築されているため、グラフの表示やグラフ要素の細かいカスタマイズを行うためには matplotlib.pyplotも併せてインポートする必要があります。

3.3.2 サンプルデータセット

Seaborn には、データ分析や可視化の練習に便利なサンプルデータセットが用意されています。以下は、有名なサンプルデータセットの一覧です(データソース全体)。

データセット名 概要
tips レストランのチップに関する情報
iris アヤメの品種と花の長さ・幅のデータ
titanic タイタニック号の乗客情報
flights 年・月ごとの航空旅客数
diamonds ダイヤモンドの価格・カット・カラーなどの特徴
penguins ペンギンの種類・体重・くちばしのサイズなどのデータ
planets 発見された惑星に関する情報(質量・年・方法など)

その他、利用可能なデータセットの一覧は、以下のようにして取得することができます。

print(sns.get_dataset_names())

ここでは、penguins データセットを例に、データ可視化の基本的な流れを確認していきましょう。

サンプルデータセットの読み込み

サンプルデータセットを読み込むには、seaborn.load_dataset() 関数を用います。引数にデータセット名の文字列を渡すことで、各種データフレームを受け取ることができます。データフレームについては別の回で改めて説明しますが、ここでは表形式のデータ型というくらいの認識を持っていてください。seaborn.load_dataset() 関数で penguins データセットを読み込み、DataFrame.head() メソッドで最初の 5 行のデータを確認するコードは以下のようになります(最後の 5 行を確認したい場合は DataFrame.tail() メソッドを用います)。

import seaborn as sns
import matplotlib.pyplot as plt
df = sns.load_dataset("penguins")

# 最初の 5 行を見る
print(df.head())

実行結果は以下のようになり、どのような形でデータが用意されているかを確認することができます。

Output
  species     island  bill_length_mm  ...  flipper_length_mm  body_mass_g     sex
0  Adelie  Torgersen            39.1  ...              181.0       3750.0    Male
1  Adelie  Torgersen            39.5  ...              186.0       3800.0  Female
2  Adelie  Torgersen            40.3  ...              195.0       3250.0  Female
3  Adelie  Torgersen             NaN  ...                NaN          NaN     NaN
4  Adelie  Torgersen            36.7  ...              193.0       3450.0  Female

しかし、途中のカラム(列)が省略されており、すべての構造を確認することができません。このような場合は、DataFrame.columns 属性や DataFrame.info() メソッドを用いることで、カラム一覧やデータ構造を確認することができます。また、公式のデータソース一覧 (GitHub) から、より詳細な情報を確認することもできます。Kaggle のノートブック「penguin dataset : The new Iris」もわかりやすいのでおすすめです。

3.3.3 散布図 (Matplotlib)

Seaborn を使う前に、まずは Matplotlib を使ってデータセットの簡単な散布図を描いてみましょう。以下は、penguins データセットから 2 つの特徴量を取り出して散布図を描画する例です。

import seaborn as sns
import matplotlib.pyplot as plt

# penguins データセットの読み込み
df = sns.load_dataset("penguins")

# Matplotlib で散布図を描画
plt.scatter(df['bill_length_mm'], df['body_mass_g'])
plt.xlabel('Bill Length [mm]')
plt.ylabel('Body Mass [g]')
plt.show()

散布図(Matplotlib)

このように、Matplotlib の plt.scatter() 関数を使っても散布図は描けますが、色分けや凡例の追加などは手動で行う必要があり、やや手間がかかります。次に紹介する Seaborn を使うと、これらをより簡単に実現できます。

3.3.4 散布図 (Seaborn)

Seaborn で散布図を描くには、seaborn.scatterplot() 関数を用います。以下は、penguins データセットに対する使用例です。

import seaborn as sns
import matplotlib.pyplot as plt

# penguins データセットの読み込み
df = sns.load_dataset("penguins")

# デフォルトのテーマに設定(日本語フォントを指定)
sns.set_theme(font="IPAexGothic")

# 散布図のプロット
sns.scatterplot(data=df,
    x="bill_length_mm",
    y="body_mass_g",
    hue="species",
    style="sex"
)

# レイアウトの自動調整
plt.tight_layout()

# グラフの表示
plt.show()

散布図 (Seaborn)

このように Seaborn を使うことで、複雑なデータを簡単に可視化することができ、そこから多くの情報を直感的に得ることが可能となります。その他にもさまざまな表現が可能ですが、使用方法の詳細は公式のドキュメントを参照するようにしてください。

3.4 探索的データ分析(EDA)

機械学習モデルの構築は、データの全体像を把握することから始まります。この作業を探索的データ分析(Exploratory Data Analysis, EDA)と呼びます。EDA では、データの分布、欠損値、外れ値、変数間の相関などを可視化を通じて確認し、データの特徴や問題点を発見します。

ここでは、Iris(アヤメ)データセットを用いて、EDA の基本的な手法を学びます。Iris データセットは、3 品種(setosa、versicolor、virginica)のアヤメについて、がく片(sepal)と花びら(petal)の長さ・幅を計測した 150 件のデータで、機械学習の入門用データセットとして広く使われています。本節では、3.3 節で使った Seaborn の load_dataset() 関数を用いて、このデータを読み込みます。

3.4.1 データの準備

まず、Iris データセットを読み込みます。Seaborn の load_dataset() 関数を使うと、データは pandas の DataFrame(データフレーム)として読み込まれます。DataFrame は、行と列からなる 2 次元のデータ構造で、各列が 1 つの特徴量(例:がく片の長さ)、各行が 1 件のデータ(1 本のアヤメ)に対応します。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Iris データセットの読み込み(seaborn のサンプルデータ)
df = sns.load_dataset('iris')

print(df.shape)
print(df.head())
Output
(150, 5)
   sepal_length  sepal_width  petal_length  petal_width species
0           5.1          3.5           1.4          0.2  setosa
1           4.9          3.0           1.4          0.2  setosa
2           4.7          3.2           1.3          0.2  setosa
3           4.6          3.1           1.5          0.2  setosa
4           5.0          3.6           1.4          0.2  setosa

3.4.2 データの分布の確認

EDA の最初のステップは、データの分布を把握することです。各特徴量のヒストグラムを描画し、データの広がり方を確認します。kde=True を指定すると、カーネル密度推定(KDE)の曲線がヒストグラムに重ねて表示され、分布の形状をより滑らかに把握できます。

fig, axes = plt.subplots(2, 2, figsize=(10, 8))
feature_cols = ['sepal_length', 'sepal_width',
                'petal_length', 'petal_width']

for i, ax in enumerate(axes.flatten()):
    sns.histplot(data=df, x=feature_cols[i], hue='species',
                 kde=True, ax=ax)
    ax.set_title(feature_cols[i])

plt.tight_layout()
plt.show()

また、sns.boxplot() 関数で箱ひげ図を描くと、中央値、四分位数、外れ値を一目で確認できます。Iris データセットでは、品種ごとに特徴量の分布が異なり、特に petal length と petal width では setosa が他の 2 品種と明確に分離していることがわかります。

3.4.3 外れ値の検出

外れ値は、他のデータから大きく離れた値であり、モデルの性能に悪影響を及ぼす可能性があります。箱ひげ図では、箱の上下のひげの外側に表示される点が外れ値です。統計的に外れ値を検出する代表的な手法が IQR(四分位範囲)法で、第 1 四分位数(Q1)と第 3 四分位数(Q3)の差を IQR とし、\(Q1 - 1.5 \times IQR\) より小さいか、\(Q3 + 1.5 \times IQR\) より大きい値を外れ値とみなします。

# IQR法で外れ値を検出する
def detect_outliers_iqr(df, column):
    Q1 = df[column].quantile(0.25)
    Q3 = df[column].quantile(0.75)
    IQR = Q3 - Q1
    lower = Q1 - 1.5 * IQR
    upper = Q3 + 1.5 * IQR
    outliers = df[(df[column] < lower) | (df[column] > upper)]
    return outliers

# sepal_width の外れ値を検出
col = 'sepal_width'
outliers = detect_outliers_iqr(df, col)
print(f"{col} の外れ値の数: {len(outliers)}")
print(outliers[[col, 'species']].head())
Output
sepal_width の外れ値の数: 4
    sepal_width     species
15          4.4      setosa
32          4.1      setosa
33          4.2      setosa
60          2.0  versicolor

外れ値が見つかった場合は、そのデータが本当に異常なのか、それとも重要な情報を含んでいるのかを慎重に判断する必要があります。

3.4.4 相関分析

一方の値が大きいほど、もう一方の値も大きくなる(または小さくなる)傾向があるとき、2 つの変数には 相関 があるといいます。特徴量間の相関を把握しておくと、モデルに使う特徴量を選ぶ際の手がかりになります。相関係数は、2 つの変数間の線形な関係の強さを \(-1\) から \(1\) の範囲で表す指標です。すべての特徴量の組み合わせについて相関係数を求め、表の形に並べたものを、相関行列といいます。corr() メソッドで計算した相関行列をヒートマップで表示すると、変数間の関係性を直感的に把握できます。

# 数値列のみで相関行列を計算
corr_matrix = df[feature_cols].corr()

# ヒートマップによる相関の可視化
plt.figure(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True,
            fmt='.2f', cmap='coolwarm',
            center=0, square=True,
            linewidths=0.5)
plt.title("特徴量間の相関行列")
plt.tight_layout()
plt.show()

ヒートマップから、petal length と petal width の間に非常に強い正の相関(0.96)があることがわかります。また、sepal width は他の特徴量と負の相関を示しています。

さらに、Seaborn の pairplot() 関数を使うと、すべての特徴量の組み合わせについて散布図を一度に描画でき、どの特徴量の組み合わせが品種の分類に有効かを視覚的に判断できます。

sns.pairplot(df, hue='species', diag_kind='hist')
plt.tight_layout()
plt.show()

petal_length や petal_width を含む組み合わせでは、setosa がほかの 2 品種から明確に分かれている様子が確認できます。一方、versicolor と virginica では一部重なりがあります。

外れ値の候補は、測定ミスか、実際に取り得る値かを確かめてから扱いを決めます。

3.5 演習問題

演習 3-1: 棒グラフで比較

演習 3-1

5つの都市の平均気温を棒グラフで表示してください。

要件:

  • matplotlib.pyplot を使う
  • グラフにタイトルと軸ラベルをつける
テンプレートコード
import matplotlib.pyplot as plt

cities = ['東京', '大阪', '札幌', '福岡', '那覇']
temps = [16.3, 17.1, 9.2, 17.3, 23.3]

# 棒グラフを描画

plt.show()
解答例
import matplotlib.pyplot as plt
import matplotlib_fontja

cities = ["東京", "大阪", "札幌", "福岡", "那覇"]
temps = [16.3, 17.1, 9.2, 17.3, 23.3]

plt.bar(cities, temps)
plt.title("都市ごとの平均気温")
plt.xlabel("都市")
plt.ylabel("平均気温(℃)")
plt.show()

実行すると、5都市の平均気温を比較する棒グラフが表示されます(那覇の23.3℃が最も高く、札幌の9.2℃が最も低い)。日本語のラベルを文字化けさせないため、matplotlib_fontja をインポートしています。

演習 3-2: グラフの基本要素

演習 3-2

1週間の最高気温のデータ temps = [22, 25, 28, 27, 24, 21, 19] を折れ線グラフで可視化してください。タイトル・横軸ラベル・縦軸ラベル・グリッド線・凡例をすべて設定すること。横軸には曜日(["月", "火", "水", "木", "金", "土", "日"])を表示してください。

解答例
import matplotlib.pyplot as plt
import matplotlib_fontja

temps = [22, 25, 28, 27, 24, 21, 19]
days = ["月", "火", "水", "木", "金", "土", "日"]

plt.plot(days, temps, marker="o", label="最高気温")
plt.title("1週間の気温の推移")
plt.xlabel("曜日")
plt.ylabel("気温(℃)")
plt.grid(True)
plt.legend()
plt.show()

実行すると、月曜から日曜にかけての気温の推移が折れ線グラフで表示されます(水曜の28℃がピーク)。

演習 3-3: 複数グラフの配置

演習 3-3

fig, ax スタイルを使って、1行2列のグラフを描画してください。左には5教科の平均点 averages = [72, 81, 76, 85, 69](教科は国語・数学・英語・理科・社会)の棒グラフを、右には15人分の点数データ scores = [55, 62, 70, 74, 78, 80, 81, 85, 88, 92, 66, 73, 79, 84, 90] のヒストグラムを描画し、それぞれにタイトルを付けてください。

解答例
import matplotlib.pyplot as plt
import matplotlib_fontja

subjects = ["国語", "数学", "英語", "理科", "社会"]
averages = [72, 81, 76, 85, 69]
scores = [55, 62, 70, 74, 78, 80, 81, 85, 88, 92, 66, 73, 79, 84, 90]

fig, axes = plt.subplots(1, 2, figsize=(10, 4))

axes[0].bar(subjects, averages)
axes[0].set_title("教科ごとの平均点")

axes[1].hist(scores, bins=5)
axes[1].set_title("点数の分布")

plt.tight_layout()
plt.show()

左に棒グラフ(理科の85点が最高)、右に点数のヒストグラムが並んで表示されます。

演習 3-4: 散布図と色分け

演習 3-4

Seaborn の iris データセットを読み込み、petal_length を横軸、petal_width を縦軸とした散布図を、品種(species)ごとに色分けして描画してください。

解答例
import matplotlib.pyplot as plt
import seaborn as sns

df = sns.load_dataset("iris")
sns.scatterplot(data=df, x="petal_length", y="petal_width",
                hue="species")
plt.show()

setosa が左下に明確に分離し、versicolor と virginica は右上に向かって分布します。petal_length と petal_width の組み合わせで品種がよく分離できることがわかります。

演習 3-5: 探索的データ分析

演習 3-5

Seaborn の tips データセット(レストランの会計データ)を読み込み、次の分析を行ってください。

  1. 先頭5行とデータの件数(行数・列数)を確認する
  2. 会計金額(total_bill)のヒストグラムと箱ひげ図を並べて描画する
  3. 会計金額とチップ(tip)の相関係数を計算し、関係の強さを考察する
解答例
import matplotlib.pyplot as plt
import matplotlib_fontja
import seaborn as sns

tips = sns.load_dataset("tips")

# 1. 基本情報の確認
print(tips.head())
print(tips.shape)
print(tips.describe())
print(tips.isnull().sum())

# 2. ヒストグラムと箱ひげ図
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
axes[0].hist(tips["total_bill"], bins=20)
axes[0].set_title("会計金額の分布")
axes[1].boxplot(tips["total_bill"])
axes[1].set_title("会計金額の箱ひげ図")
plt.tight_layout()
plt.show()

# 3. 相関係数
print(tips[["total_bill", "tip"]].corr())
  • データは244行・7列で、欠損値はどの列にもありません(すべて0)
  • 会計金額の分布は右に歪んでおり、箱ひげ図では40ドル以上が外れ値として表示されます
  • 会計金額とチップの相関係数は約 0.68 で、比較的強い正の相関があります(会計金額が大きいほどチップも多い傾向)