Seaborn を使う最大の利点は、1行で「集計+作図+凡例+エラーバー」までやってくれることです。Matplotlib で10行かかる処理が、sns.barplot(data=df, x="都市", y="年齢")だけで終わります。

ただし Seaborn は「整然データ(tidy data)」を前提にしているため、データの形を先に整えないと期待通りに描けません。また、日本語ラベルは Matplotlib と同じく設定なしでは文字化けします。

この記事では、Pandas で形を整えるところから、Seaborn の主要なグラフ、そして公式が推奨するsns.objectsインターフェースまでを、動くコードで解説します。

環境の準備と日本語表示

pip install pandas seaborn matplotlib matplotlib-fontja

 

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib_fontja  # 日本語の文字化けを防ぐ

sns.set_theme(style="whitegrid")  # 見た目のテーマを設定
plt.rcParams['axes.unicode_minus'] = False

 

注意点が1つあります。sns.set_theme()はフォント設定を上書きします。 そのため、matplotlib_fontjaのインポートよりset_theme()を呼ぶと文字化けが戻ることがあります。上のようにインポート → set_theme()の順で書いてください。

それでも化ける場合は、テーマ側にフォントを渡します。

sns.set_theme(style="whitegrid", font="Hiragino Sans")  # macOS
# sns.set_theme(style="whitegrid", font="Yu Gothic")    # Windows

 

Seaborn が求めるデータの形

ここが最初の関門です。 Seaborn は「1行=1観測、1列=1変数」というロング形式を前提にしています。Excel でよく作る「横に月が並んだ表」(ワイド形式)のままでは、x=hue=に渡す列がありません。

# ワイド形式(Excelでよくある形)
wide = pd.DataFrame({
    "商品": ["A", "B"],
    "1月": [100, 80],
    "2月": [120, 90],
    "3月": [140, 70],
})

# → ロング形式に変換する
long = wide.melt(id_vars="商品", var_name="月", value_name="売上")
print(long)
#   商品   月  売上
# 0  A   1月  100
# 1  B   1月   80
# 2  A   2月  120
# ...

 

melt()でロング形式にすれば、そのまま渡せます。

sns.lineplot(data=long, x="月", y="売上", hue="商品", marker="o")
plt.show()

 

hue=に列名を渡すだけで系列が分かれ、凡例まで自動で付くのが Seaborn の強みです。逆に言えば、この形にできていないと利点がほとんど活きません。「うまく描けない」ときの原因は、9割がデータの形です。

 

Pandas での前処理

df = pd.read_csv("data.csv", encoding="utf-8-sig", parse_dates=["date"])

# 欠損の確認
print(df.isna().sum())

# 欠損を落とす(列を指定する)
df = df.dropna(subset=["value"])

# 平均で埋める場合
df["value"] = df["value"].fillna(df["value"].mean())

# 条件で絞る
adults = df[df["age"] >= 20]

# グループ集計
summary = df.groupby("category", as_index=False)["value"].agg(["mean", "sum", "count"])

 

encoding="utf-8-sig"は Excel が書き出した CSV の BOM 対策です。utf-8で読むと1列目の列名が壊れて参照できなくなります。

inplace=Trueは使わず、上のように代入で書き戻してください。pandas 2系では非推奨の方向にあり、コピーの有無も分かりにくくなります。

 

基本のグラフ4種

棒グラフ(barplot):平均値の比較

tips = sns.load_dataset("tips")

sns.barplot(data=tips, x="day", y="total_bill", hue="sex")
plt.title("曜日別・性別ごとの平均会計額")
plt.show()

 

barplotが描くのは合計ではなく「平均値」で、黒い縦線は95%信頼区間です。合計を出したいときはestimator="sum"を指定するか、事前にgroupby().sum()してから渡します。ここは誤解しやすいポイントです。

箱ひげ図(boxplot):ばらつきを見る

sns.boxplot(data=tips, x="day", y="total_bill")
plt.show()

 

データ点が少ないとき(数十件程度)は、箱ひげ図よりstripplotswarmplotで実際の点を出した方が誠実です。3件のデータで箱ひげ図を描いても、四分位数に意味がありません。

sns.boxplot(data=tips, x="day", y="total_bill", showfliers=False)
sns.stripplot(data=tips, x="day", y="total_bill", color=".25", size=3, alpha=.5)
plt.show()

 

ヒストグラム(histplot):分布を見る

sns.histplot(data=tips, x="total_bill", bins="auto", kde=True)
plt.show()

 

kde=Trueで分布の推定曲線が重なります。binsを指定しない場合は自動で決まるので、まずそのまま描いて形を見るのがおすすめです。

散布図(scatterplot):2変数の関係を見る

sns.scatterplot(data=tips, x="total_bill", y="tip", hue="time", size="size", alpha=.7)
plt.show()

 

hue(色)、size(大きさ)、style(形)に別々の列を割り当てられるので、4変数までを1枚に表現できます。ただし詰め込みすぎると読めなくなるので、実用上は3つまでにとどめるのが無難です。

 

相関ヒートマップ:pandas 2系での注意点

文字列の列が混ざったままdf.corr()を呼ぶとエラーになります。 pandas 1系では自動で数値列だけを使ってくれましたが、2系では明示が必要です。

# ❌ 文字列列があると ValueError
# corr = tips.corr()

# ✅ 数値列だけを対象にする
corr = tips.corr(numeric_only=True)

fig, ax = plt.subplots(figsize=(6, 5))
sns.heatmap(corr, annot=True, fmt=".2f", cmap="coolwarm",
            vmin=-1, vmax=1, square=True, ax=ax)
ax.set_title("相関のヒートマップ")
plt.show()

 

vmin=-1, vmax=1の指定が重要です。 指定しないとデータの範囲に合わせて色が自動調整され、相関0.3が真っ赤に見えるといった誤読を招きます。相関行列のスケールは必ず固定してください。

 

pairplot:全変数の関係を一覧する

iris = sns.load_dataset("iris")

sns.pairplot(iris, hue="species", diag_kind="hist", corner=True)
plt.show()

 

corner=Trueを付けると対角線の上半分が省略され、同じ情報の重複が消えて見やすくなります

注意点として、pairplot列数の2乗に比例して重くなります。列が20を超えるようなデータでそのまま呼ぶと、数分固まります。vars=["列A", "列B", "列C"]で対象を絞ってください。

 

回帰プロット:数値どうしにしか使えない

regplotは散布図に回帰直線を重ねますが、x も y も数値列である必要があります。カテゴリ列(都市名、商品名など)を渡すとエラーになります。

# ❌ y に文字列のカテゴリは渡せない
# sns.regplot(data=df, x="年齢", y="都市")

# ✅ 数値どうしで
sns.regplot(data=tips, x="total_bill", y="tip", scatter_kws={"alpha": .4})
plt.show()

 

カテゴリごとに回帰直線を引き分けたい場合はlmplotを使います。

sns.lmplot(data=tips, x="total_bill", y="tip", hue="smoker", height=5)
plt.show()

 

figure-level と axes-level の違い

Seaborn の関数は2種類あり、これを混同するとレイアウトが崩れます

種類 関数の例 特徴
axes-level scatterplotbarplotboxplothistplot ax=を受け取る。既存の図に描き込める
figure-level relplotcatplotdisplotlmplotpairplot 自分で図全体を作る。ax=は使えない
# axes-level:複数を並べられる
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
sns.histplot(data=tips, x="total_bill", ax=axes[0])
sns.boxplot(data=tips, x="day", y="tip", ax=axes)
plt.tight_layout()
plt.show()

# figure-level:col= で自動的に分割してくれる
g = sns.relplot(data=tips, x="total_bill", y="tip",
                col="time", hue="smoker", height=4)
g.figure.suptitle("時間帯別の会計額とチップ", y=1.02)
plt.show()

 

figure-level 関数の戻り値はAxesではなくFacetGridです。 タイトルを付けるときはg.figure.suptitle()、保存するときはg.savefig()を使います。plt.title()を呼んでも、最後のサブプロットにしか付きません。

 

これから書くなら sns.objects インターフェース

Seaborn 0.12 以降には、グラフを部品の組み合わせで宣言的に書く新しいインターフェースが入りました。R の ggplot2 に近い書き方です。

import seaborn.objects as so

(
    so.Plot(tips, x="total_bill", y="tip", color="time")
    .add(so.Dot(alpha=.5))
    .add(so.Line(), so.PolyFit())      # 回帰直線を重ねる
    .facet(col="smoker")               # 列方向に分割
    .label(x="会計額", y="チップ", title="会計額とチップの関係")
    .show()
)

 

従来の関数群も引き続き使えますが、「何を描くか」と「どう見せるか」が分離されるので、複雑なグラフほど読みやすくなります。新規に書くならこちらを検討する価値があります。

 

保存するとき

# axes-level の場合
fig.savefig("chart.png", dpi=150, bbox_inches="tight")

# figure-level の場合
g.savefig("chart.png", dpi=150, bbox_inches="tight")

 

  • bbox_inches="tight":軸ラベルや凡例が切れるのを防ぐ
  • plt.show()より前に呼ぶ:表示後は図が破棄され、空の画像になることがある

 

まとめ

  • 日本語はmatplotlib-fontjaをインポート。sns.set_theme()はその後に呼ぶ
  • Seaborn はロング形式が前提。ワイド形式はmelt()で変換する
  • barplotが描くのは合計ではなく平均。合計ならestimator="sum"
  • df.corr()にはnumeric_only=True、ヒートマップにはvmin=-1, vmax=1
  • regplot数値列どうしにしか使えない。カテゴリ別ならlmplot
  • pairplotは列数の2乗で重くなる。vars=で絞る
  • figure-level 関数はax=を取れない。戻り値はFacetGrid
  • 新規に書くならseaborn.objectsも検討する

グラフを細かく制御したい場合は Matplotlib を直接触る方が早いこともあります。そちらはPandasとMatplotlibを活用したデータ可視化にまとめました。

ABOUT ME
りん
このブログでは、Web開発やプログラミングに関する情報を中心に、私が日々感じたことや学んだことをシェアしています。技術と生活の両方を楽しめるブログを目指して、日常で触れた出来事や本、グルメの話題も取り入れています。気軽に覗いて、少しでも役立つ情報や楽しいひとときを見つけてもらえたら嬉しいです。