🍰 まずはやさしく
データの分析でよく使う道具のようなものです。
結果を分かりやすく報告するために使います。
部活の練習量と試合の結果をまとめます。
どんな場面でどの図を使うかを確認しましょう。
論文・記事に 「散布図」「ヒートマップ」「散布図行列」「相関プロット」「バブルチャート」「クロス集計」 として登場する 2変量以上の可視化群。 EDA・モデル評価・結果報告のすべての場面で必須のツール。
論文記事から各用語のリンクをクリックすると、 該当箇所が開きます:
🍰 まずはやさしく
2つのデータの関係を絵にする方法です。
データ同士にどんなつながりがあるか調べます。
勉強時間とテストの点数の関係を調べます。
図の種類と使い分けについて読みましょう。
| 手法 | 変数の型 | サンプルサイズ | 主な用途 |
|---|---|---|---|
| 散布図 | 連続 × 連続 | 10〜数千 | 相関、 回帰、 外れ値 |
| Hexbin | 連続 × 連続 | 10000〜 | 大量データの密度 |
| 2D KDE | 連続 × 連続 | 100〜数千 | 滑らかな密度 |
| バブル | 連続 × 連続 × サイズ | 〜数百 | 3変数の同時表示 |
| ヒートマップ | 行列形式 | 任意 | 相関行列、 混同行列 |
| 散布図行列 | 複数連続変数 | 任意(3〜10変数) | 多変量 EDA |
| クロス集計 | カテゴリ × カテゴリ | 任意 | 独立性検定 |
2 つの連続変数の関係を $(x_i, y_i)$ の点で表現。 探索的データ解析の最も重要な可視化。 相関係数や回帰分析の前に必ず描く。
SSDSE-B-2026 の家計支出から、 食料費と教育費の関係を散布図で確認すると正の相関($r \approx 0.73$)が見えます。 ただし、 相関係数 $r$ の数値だけでは「線形か」「外れ値があるか」が分からないため、 散布図と必ずセットで確認します。
data/raw/SSDSE-B-2026.csv。 列 L322101 (食料費)と L322108 (教育費)、 encoding='cp932'、 header=1。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import pandas as pd # ── この抜粋で使うデータを用意します(SSDSE-B の 47 都道府県・最新年度)── df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy() df['年度'] = pd.to_numeric(df['年度'], errors='coerce') df = df[df['年度'] == df['年度'].max()].copy() for _c in df.columns[3:]: df[_c] = pd.to_numeric(df[_c], errors='coerce') # 費目の正式名は「◯◯費(二人以上の世帯)」。短い別名を付けて使いやすくする df['食料費'] = df['食料費(二人以上の世帯)'] df['住居費'] = df['住居費(二人以上の世帯)'] df['教育費'] = df['教育費(二人以上の世帯)'] df['光熱費'] = df['光熱・水道費(二人以上の世帯)'] df['消費支出'] = df['消費支出(二人以上の世帯)'] # 「地域」は SSDSE に無いので、地域コードの頭 2 桁(都道府県番号)から作る def _blk(code): n = int(str(code)[1:3]) return ('北海道' if n == 1 else '東北' if n <= 7 else '関東' if n <= 14 else '中部' if n <= 23 else '近畿' if n <= 30 else '中国' if n <= 35 else '四国' if n <= 39 else '九州沖縄') df['地域'] = df['地域コード'].map(_blk) import matplotlib.pyplot as plt import seaborn as sns food = df['食料費'] / 1000 edu = df['教育費'] / 1000 # matplotlib plt.scatter(food, edu, alpha=0.6) # seaborn(回帰直線付き) sns.regplot(x=food, y=edu) # 色分け(カテゴリ変数で) sns.scatterplot(x='食料費', y='教育費', hue='地域', data=df) # 透明度で密度を表現 plt.scatter(food, edu, alpha=0.1) # 大量データ用 print(f'食料費と教育費の相関 r = {df["食料費"].corr(df["教育費"]):.3f}') |
大量データ($n > 10000$)の散布図は点が重なり「黒い塊」になりがち。 そんなとき六角形のグリッドに集計するのが Hexbin。
gridsize でビンの粗さを調整する。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # ── この抜粋で使うデータを用意します ── import pandas as pd import matplotlib.pyplot as plt import seaborn as sns df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年の 47 都道府県 df = df.copy() df['x'] = df['A1101'].astype(float) # 総人口 df['y'] = df['A4101'].astype(float) # 出生数 x, y = df['x'].values, df['y'].values plt.hexbin(x, y, gridsize=30, cmap='viridis') plt.colorbar(label='頻度') # seaborn sns.jointplot(x='x', y='y', data=df, kind='hex') |
2変数の同時密度関数を滑らかに推定。 等高線で密度を可視化。
点のサイズで3つ目の変数を表現。 4つ目を色で表現すれば 4変量可視化に拡張可能。
2次元行列の値を色の濃淡で表現。 主な用途:
注意:色覚多様性に配慮し赤緑配色を避ける。 'viridis' は色覚バリア対応。
df.corr() や、 分類の混同行列 confusion_matrix などの 2 次元行列。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import pandas as pd import scipy.cluster.hierarchy # seaborn の clustermap が scipy を必要とする # ── この抜粋で使うデータを用意します(SSDSE-B の 47 都道府県・最新年度)── df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy() df['年度'] = pd.to_numeric(df['年度'], errors='coerce') df = df[df['年度'] == df['年度'].max()].copy() for _c in df.columns[3:]: df[_c] = pd.to_numeric(df[_c], errors='coerce') # 費目の正式名は「◯◯費(二人以上の世帯)」。短い別名を付けて使いやすくする df['食料費'] = df['食料費(二人以上の世帯)'] df['住居費'] = df['住居費(二人以上の世帯)'] df['教育費'] = df['教育費(二人以上の世帯)'] df['光熱費'] = df['光熱・水道費(二人以上の世帯)'] df['消費支出'] = df['消費支出(二人以上の世帯)'] # 「地域」は SSDSE に無いので、地域コードの頭 2 桁(都道府県番号)から作る def _blk(code): n = int(str(code)[1:3]) return ('北海道' if n == 1 else '東北' if n <= 7 else '関東' if n <= 14 else '中部' if n <= 23 else '近畿' if n <= 30 else '中国' if n <= 35 else '四国' if n <= 39 else '九州沖縄') df['地域'] = df['地域コード'].map(_blk) import seaborn as sns import numpy as np # 相関行列のヒートマップ(文字列の列が混ざるので numeric_only=True) cols = ['食料費', '住居費', '教育費', '光熱費', '消費支出'] corr = df[cols].corr(numeric_only=True) sns.heatmap(corr, annot=True, fmt='.2f', cmap='RdBu_r', center=0, vmin=-1, vmax=1) # 混同行列(例として「高齢化率が中央値超か」を予測した結果を作る) from sklearn.metrics import confusion_matrix aging = df['65歳以上人口'] / df['総人口'] y_true = (aging > aging.median()).astype(int) y_pred = (df['消費支出'] < df['消費支出'].median()).astype(int) cm = confusion_matrix(y_true, y_pred) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues') print(cm) # クラスター付き(階層クラスタリングで並び替え) # sns.clustermap はブラウザ版 seaborn が scipy を見つけられず動かないので、 # 並び替えを scipy で自分で計算して、ふつうの heatmap に渡す。 from scipy.cluster.hierarchy import linkage, leaves_list from scipy.spatial.distance import squareform _d = squareform(1 - corr.values, checks=False) _order = leaves_list(linkage(_d, method='average')) _sorted = corr.iloc[_order, _order] sns.heatmap(_sorted, annot=True, fmt='.2f', cmap='RdBu_r', center=0) print('並び替え後の順序:', list(_sorted.columns)) |
RdBu_r で赤=正相関・青=負相関、 対角は 1.0。 注釈 (annot) で数値も表示。$d$ 変数の全ペアの散布図を $d \times d$ グリッドで描く。 多変量データの探索的解析の標準ツール。 対角には各変数のヒストグラム(または KDE)を置く。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import pandas as pd # ── この抜粋で使うデータを用意します(SSDSE-B の 47 都道府県・最新年度)── df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy() df['年度'] = pd.to_numeric(df['年度'], errors='coerce') df = df[df['年度'] == df['年度'].max()].copy() for _c in df.columns[3:]: df[_c] = pd.to_numeric(df[_c], errors='coerce') # 費目の正式名は「◯◯費(二人以上の世帯)」。短い別名を付けて使いやすくする df['食料費'] = df['食料費(二人以上の世帯)'] df['住居費'] = df['住居費(二人以上の世帯)'] df['教育費'] = df['教育費(二人以上の世帯)'] df['光熱費'] = df['光熱・水道費(二人以上の世帯)'] df['消費支出'] = df['消費支出(二人以上の世帯)'] # 「地域」は SSDSE に無いので、地域コードの頭 2 桁(都道府県番号)から作る def _blk(code): n = int(str(code)[1:3]) return ('北海道' if n == 1 else '東北' if n <= 7 else '関東' if n <= 14 else '中部' if n <= 23 else '近畿' if n <= 30 else '中国' if n <= 35 else '四国' if n <= 39 else '九州沖縄') df['地域'] = df['地域コード'].map(_blk) import seaborn as sns # 基本 sns.pairplot(df[['食料費','住居費','教育費','光熱費']].dropna()) # カテゴリで色分け + 回帰直線 sns.pairplot(df.dropna(subset=['食料費','教育費','住居費']), vars=['食料費','教育費','住居費'], hue='地域', kind='reg') # 対角を KDE に sns.pairplot(df[['食料費','住居費','教育費']].dropna(), diag_kind='kde') |
カテゴリ × カテゴリの 2変量集計。 例えば「性別 × 購買意向」の集計表。 関連性はχ²検定で検証。
pd.crosstab で度数表を作り、 normalize で条件付き割合に。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import pandas as pd # ── この抜粋で使うデータを用意します(SSDSE-B の 47 都道府県・最新年度)── df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy() df['年度'] = pd.to_numeric(df['年度'], errors='coerce') df = df[df['年度'] == df['年度'].max()].copy() for _c in df.columns[3:]: df[_c] = pd.to_numeric(df[_c], errors='coerce') # 費目の正式名は「◯◯費(二人以上の世帯)」。短い別名を付けて使いやすくする df['食料費'] = df['食料費(二人以上の世帯)'] df['住居費'] = df['住居費(二人以上の世帯)'] df['教育費'] = df['教育費(二人以上の世帯)'] df['光熱費'] = df['光熱・水道費(二人以上の世帯)'] df['消費支出'] = df['消費支出(二人以上の世帯)'] # 「地域」は SSDSE に無いので、地域コードの頭 2 桁(都道府県番号)から作る def _blk(code): n = int(str(code)[1:3]) return ('北海道' if n == 1 else '東北' if n <= 7 else '関東' if n <= 14 else '中部' if n <= 23 else '近畿' if n <= 30 else '中国' if n <= 35 else '四国' if n <= 39 else '九州沖縄') df['地域'] = df['地域コード'].map(_blk) import seaborn as sns import matplotlib.pyplot as plt # SSDSE-B に「性別」「購入」の列は無いので、実データから 2 つのカテゴリ列を作る df['人口規模'] = pd.cut(df['総人口'], bins=[0, 1_500_000, 3_000_000, 1e9], labels=['小', '中', '大']).astype(str) df['支出水準'] = ((df['消費支出'] > df['消費支出'].median()) .map({True: '高', False: '低'})) ct = pd.crosstab(df['人口規模'], df['支出水準'], margins=True) print(ct) print(pd.crosstab(df['人口規模'], df['支出水準'], normalize='index').round(3)) # 行ごとに正規化 # ヒートマップで可視化 sns.heatmap(pd.crosstab(df['人口規模'], df['支出水準']), annot=True, fmt='d', cmap='Blues') # モザイク図 from statsmodels.graphics.mosaicplot import mosaic mosaic(df, ['人口規模', '支出水準']) plt.close('all') |
| ❌ 誤解 | ✅ 正しい理解 |
|---|---|
| 散布図 で「強い相関」に見えれば因果 | 相関≠因果。 散布図は出発点でしかない |
| 散布図が直線的なら $r$ も高い | 外れ値・非線形があると一致しない。 アンスコムの四重奏 |
| ヒートマップは赤緑が分かりやすい | 色覚多様性に注意。 viridis 系を推奨 |
| 大量データでも散布図で OK | 点が重なり密度が見えない。 Hexbin / 2D KDE |
| 散布図行列で全部見れる | 10変数を超えると小さくて読めない。 PCA / 相関ヒートマップ |
| クロス集計の度数だけ見ればよい | 行・列で正規化した条件付き確率も見る |
data/raw/SSDSE-B-2026.csv。 列 L322101 (食料費)・L322108 (教育費)・L322102 (住居費)、 2023 年、 千円換算。1 2 3 4 5 6 7 8 9 | import seaborn as sns, pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932') data = df.iloc[1:].copy() data['年度'] = data['SSDSE-B-2026'] d23 = data[data['年度']=='2023'] cols = ['L322101', 'L322108', 'L322102'] sub = d23[cols].apply(pd.to_numeric, errors='coerce').dropna() / 1000 sub.columns = ['食料費', '教育費', '住居費'] sns.pairplot(sub, kind='reg', diag_kind='kde') |
Pearson $r$ は線形な関係しか捉えないが、 単調な曲線なら高い相関を示すことがある。 Spearman 順位相関で再確認、 多項式項を含めた回帰、 非線形変換(log)の検討が必要。 アンスコムの四重奏(同じ $r$ でも形が全く違う 4 例)は古典的な警告。
対角は「同じ変数同士の相関」=1。 非対角は $r_{ij} = r_{ji}$ なので対称。 だからヒートマップでは下三角だけ描く(mask で上三角を隠す)と冗長性を減らせる。
連続2 を $x, y$ 軸に、 カテゴリを色(hue)で表現。 sns.scatterplot(x=..., y=..., hue=..., data=df)。 群ごとの傾向の違いが一目で分かる。 さらに 4 つ目(連続)があれば点のサイズで(バブル化)。
選択肢:(a) alpha=0.1 で透明度、 (b) Hexbin で密度集計、 (c) 2D KDE で滑らかな密度、 (d) サブサンプリング(無作為 1000 件)。 (a)(b)(c) を組み合わせるのが現代的。 Hexbin + colorbar が最も実用的。
「47都道府県の食料費と教育費の散布図(n=47、 SSDSE-B-2026、 2023年)では、 明確な正の相関(Pearson $r=0.728$、 95% CI: [0.557, 0.839]、 $p<0.001$)が見られた。 1点(東京都)が右上に外れているが、 これを除いても相関は $r=0.651$ と安定して有意。 散布図行列で他変数(住居費・光熱・水道費)との関係も確認し、 教育費は住居費とはほぼ無相関、 光熱・水道費とは弱い負の相関であった。」
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | # ── この抜粋で使うデータを用意します ── import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1) df = df[df['年度'] == df['年度'].max()].copy() # 最新年度の 47 都道府県 # 費目の正式名は「◯◯費(二人以上の世帯)」。短い別名を付けて使う df['食料費'] = df['食料費(二人以上の世帯)'] df['住居費'] = df['住居費(二人以上の世帯)'] df['教育費'] = df['教育費(二人以上の世帯)'] df['人口'] = df['総人口'] def _blk(code): n = int(str(code)[1:3]) return ('北海道' if n == 1 else '東北' if n <= 7 else '関東' if n <= 14 else '中部' if n <= 23 else '近畿' if n <= 30 else '中国' if n <= 35 else '四国' if n <= 39 else '九州沖縄') df['地域'] = df['地域コード'].map(_blk) x, y = df['食料費'].values, df['教育費'].values # 散布図 plt.scatter(x, y, alpha=0.6) sns.scatterplot(x='食料費', y='教育費', hue='地域', size='人口', data=df) sns.regplot(x='食料費', y='教育費', data=df) # 回帰直線つき # Hexbin plt.hexbin(x, y, gridsize=30, cmap='viridis') # 2D KDE sns.kdeplot(x=x, y=y, fill=True, cmap='Blues') sns.jointplot(x='食料費', y='教育費', data=df, kind='kde') # ヒートマップ # df には地域コードなど文字列の列も入っているので、費目だけで相関を取る _cols = ['食料費', '住居費', '教育費', '人口'] sns.heatmap(df[_cols].corr(), annot=True, cmap='RdBu_r', center=0) # sns.clustermap はブラウザ版 seaborn が scipy を見つけられないので使わない # (必要なら scipy で並び替えてから heatmap に渡す) # 散布図行列 # hue に使う列も一緒に渡さないと KeyError になる sns.pairplot(df[['食料費', '住居費', '教育費', '地域']], hue='地域', kind='reg') # クロス集計 import pandas as pd # 「性別」「購入」は SSDSE に無いので、<架空の>アンケートを作る _rng = np.random.default_rng(0) _survey = pd.DataFrame({'性別': _rng.choice(['男', '女'], 200), '購入': _rng.choice(['あり', 'なし'], 200)}) ct = pd.crosstab(_survey['性別'], _survey['購入']) sns.heatmap(ct, annot=True, fmt='d') # plotly(インタラクティブ) import plotly.express as px px.scatter(df, x='食料費', y='教育費', color='地域', size='人口', hover_name='都道府県') px.imshow(df[_cols].corr(), color_continuous_scale='RdBu_r', zmin=-1, zmax=1) |
| 種類 | 用途 | 推奨 |
|---|---|---|
| 連続型(sequential) | 単調値(頻度、 強度) | viridis, plasma, Blues, YlOrRd |
| 発散型(diverging) | 基準(0)から±に意味(相関、 残差) | RdBu_r, coolwarm, BrBG |
| カテゴリ型(qualitative) | カテゴリ分け | tab10, Set2, Paired |
| 循環型(cyclic) | 角度、 時刻 | twilight, hsv |
避けるべき:rainbow / jet — 色覚多様性で誤読されやすい。 viridis は色覚バリア対応 + 知覚的に均等。
参考:Edward Tufte「The Visual Display of Quantitative Information」(1983)— 可視化倫理の古典。
2変量可視化の主要グラフ・概念・関連手法。
data/raw/SSDSE-B-2026.csv。 列 L322101 (食料費)と L322108 (教育費)、 encoding='cp932'、 header=1。1 2 3 4 5 6 7 8 9 10 11 | import pandas as pd import seaborn as sns import matplotlib.pyplot as plt df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) df = df[df['年度'] == 2023] x_col, y_col = '食料費(二人以上の世帯)', '教育費(二人以上の世帯)' sns.regplot(data=df, x=x_col, y=y_col, scatter_kws={'s':50,'alpha':0.7}) plt.title(f'{x_col} vs {y_col}') plt.savefig('scatter_regline.png', dpi=120, bbox_inches='tight') |
data/raw/SSDSE-B-2026.csv の消費支出内訳 5 列 (食料費・住居費・光熱・水道費・家具・家事用品費・被服費、 2023 年)。1 2 3 4 5 6 | import pandas as pd import seaborn as sns df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) num = df[df['年度'] == 2023].filter(like='二人以上の世帯').iloc[:, 1:6] sns.pairplot(num, diag_kind='kde', plot_kws={'alpha':0.5,'s':30}) |
data/raw/SSDSE-B-2026.csv の消費支出内訳 8 列(食料費〜教育費、 2023 年)の相関行列 (.corr())。1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd import seaborn as sns import matplotlib.pyplot as plt df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) corr = df[df['年度'] == 2023].filter(like='二人以上の世帯').iloc[:, 1:9].corr() plt.figure(figsize=(9, 7)) sns.heatmap(corr, annot=True, fmt='.2f', cmap='RdBu_r', center=0, vmin=-1, vmax=1, square=True, cbar_kws={'shrink':0.8}) plt.title('相関行列ヒートマップ') plt.tight_layout() plt.savefig('corr_heatmap.png', dpi=120) |
data/raw/SSDSE-B-2026.csv の数値先頭 2 列 + 都道府県名を地域ブロックへ写像した色分けキー。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import pandas as pd import seaborn as sns import matplotlib.pyplot as plt df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) block_map = { '北海道':'北海道', '青森県':'東北','岩手県':'東北','宮城県':'東北','秋田県':'東北','山形県':'東北','福島県':'東北', '茨城県':'関東','栃木県':'関東','群馬県':'関東','埼玉県':'関東','千葉県':'関東','東京都':'関東','神奈川県':'関東', } df['ブロック'] = df['都道府県'].map(block_map).fillna('その他') cols = df.select_dtypes('number').columns sns.scatterplot(data=df, x=cols[0], y=cols[1], hue='ブロック', s=80) plt.savefig('scatter_by_block.png', dpi=120, bbox_inches='tight') |
plt.scatter だけで、 数値 2 列の基本の散布図をグリッドつきで描く。data/raw/SSDSE-B-2026.csv を header=1 で読み、 数値列の先頭 2 列を x・y に使う。1 2 3 4 5 6 7 8 9 | import matplotlib.pyplot as plt import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) cols = df.select_dtypes('number').columns plt.scatter(df[cols[0]], df[cols[1]], s=50, alpha=0.7, edgecolor='k') plt.xlabel(cols[0]); plt.ylabel(cols[1]) plt.grid(alpha=0.3) plt.savefig('basic_scatter.png', dpi=120) |
jointplot(kind='hex') で、 散布図の周辺に各軸のヒストグラム (周辺分布) を添える。data/raw/SSDSE-B-2026.csv を header=1 で読み、 数値列の先頭 2 列を x・y に使う。1 2 3 4 5 6 | import seaborn as sns import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) cols = df.select_dtypes('number').columns sns.jointplot(data=df, x=cols[0], y=cols[1], kind='hex', height=8) |
gaussian_kde で各点の 2 次元密度を推定し、 点の色として重ねて密集度を表す。data/raw/SSDSE-B-2026.csv を header=1 で読み、 数値列の先頭 2 列を x・y に使う。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import numpy as np import pandas as pd from scipy.stats import gaussian_kde import matplotlib.pyplot as plt df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) cols = df.select_dtypes('number').columns x = df[cols[0]].dropna().values y = df[cols[1]].dropna().values xy = np.vstack([x, y]) density = gaussian_kde(xy)(xy) plt.scatter(x, y, c=density, s=60, cmap='viridis') plt.colorbar(label='density') plt.savefig('kde_scatter.png', dpi=120, bbox_inches='tight') |
px.scatter で、 ホバー・ズーム可能なインタラクティブ散布図を HTML 出力する。data/raw/SSDSE-B-2026.csv を header=1 で読み、 数値列の先頭 2 列に OLS トレンドラインを重ねる。1 2 3 4 5 6 7 8 | import plotly.express as px import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) cols = df.select_dtypes('number').columns fig = px.scatter(df, x=cols[0], y=cols[1], hover_name='都道府県', trendline='ols', size_max=12) fig.write_html('interactive_scatter.html') |
crosstab でカテゴリ 2 変量を集計し、 seaborn のヒートマップで塗り分ける。1 2 3 4 5 6 7 8 9 10 | import pandas as pd import seaborn as sns import matplotlib.pyplot as plt df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) df['人口層'] = pd.qcut(df.select_dtypes('number').iloc[:,0], q=3, labels=['小','中','大']) df['経済層'] = pd.qcut(df.select_dtypes('number').iloc[:,1], q=3, labels=['低','中','高']) ct = pd.crosstab(df['人口層'], df['経済層']) sns.heatmap(ct, annot=True, cmap='YlOrRd', fmt='d') plt.savefig('crosstab_heatmap.png', dpi=120, bbox_inches='tight') |
🍰 まずはやさしく
2つの情報を1枚の図にまとめることです。
パッと見てデータの傾向をつかむために使います。
スマホの利用時間と睡眠時間の関係を見ます。
まずは直感的に図の意味を理解しましょう。
2 変量の可視化は「2 つの変数の関係を 1 枚の図にする」。 量×量=散布図、 量×質=箱ひげの群比較、 質×質=モザイクやヒートマップ。 SSDSE-B-2026 では、 A1101(人口)と L3221(消費支出)の散布図が定番で、 都市規模の大きい県ほど 1 世帯あたり支出が高めという緩い正相関が見える。
2 変量の可視化 は「可視化」カテゴリの中核概念。 初めて触れる読者は、 まずこの「🎨 直感」セクションだけ通読し、 必要になった時点で「📐 数式」「🐍 Python」「⚠️ 落とし穴」へ戻る読み方が定着しやすいです。
🍰 まずはやさしく
図の仕組みを数式(計算式)で表したものです。
正確な意味を正しく理解するために使います。
買い物で使う金額と個数の関係を計算します。
数式が何を表しているかを詳しく読みましょう。
直感の次は、 厳密な定義を確認します。 数式は言語の一種で、 一度書き慣れれば「言葉より速く伝えられる」便利な道具。 慣れていない方は、 各記号が何を表すかを下の「🔬 数式を言葉で読み解く」で 1 つずつ確認してください。
上の数式を眺めるだけでは身につかないので、 各記号がどんな役割を担っているかを言葉で押さえます。 「数式を音読する習慣」がつくと、 論文や教科書を読むスピードが体感で 2 倍ほど上がります。
数式だけでは「実感」が湧きにくいので、 実データ data/raw/SSDSE-B-2026.csv(47 都道府県 × 16 年)で 1 度手計算してみると理解が定着します。
SSDSE-B-2026 (2023) で A1101 と L3221 の相関 r ≈ 0.33。 散布図に都道府県名ラベルを付けると、 東京・神奈川・愛知が右上、 鳥取・島根が左下に配置される。 「人口 → 都市規模 → 物価 → 消費」の連鎖を仮説として読み解ける。
| 都道府県 | A1101 総人口 | A1303 65 歳以上 | L3221 消費支出 |
|---|---|---|---|
| 東京都 | 14,086,000 | 3,205,000 | 341,320 |
| 神奈川県 | 9,229,000 | 2,390,000 | 306,565 |
| 大阪府 | 8,763,000 | 2,424,000 | 271,246 |
| 愛知県 | 7,477,000 | 1,923,000 | 300,221 |
| 埼玉県 | 7,331,000 | 2,012,000 | 344,092 |
| 千葉県 | 6,257,000 | 1,756,000 | 306,943 |
上記は SSDSE-B-2026 (2023) からの抜粋。 手計算で確認した値が、 後述の Python 実装で得る値と一致することを確認すると、 「数式とコードの対応関係」がクリアに見えるようになります。
公的統計(SSDSE-B-2026)を題材に、 最小限の Python コードで 2 変量の可視化 を動作させます。 まずはこのまま実行してみてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 2 変量の可視化 を SSDSE-B-2026 で実行する最小コード import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年のみ抽出 print(df.shape) # (47, 112) print(df[['Prefecture','A1101','A1303','L3221']].head()) import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(8,6)) ax.scatter(df['A1101'], df['L3221'], alpha=0.6, color='#FF7043') ax.set_xlabel('A1101 総人口') ax.set_ylabel('L3221 消費支出') ax.set_title('SSDSE-B-2026 (2023): 人口 vs 消費支出') for i,row in df.iterrows(): if row['A1101'] > 5_000_000: ax.annotate(row['Prefecture'], (row['A1101'], row['L3221'])) plt.savefig('bivariate_demo.png', dpi=100) print('Pearson r:', df[['A1101','L3221']].corr().iloc[0,1]) |
▶ 実行 を押せばこのページの中でそのまま動きます(ライブラリもデータも同梱済みで、 準備は要りません)。 手元の Python に移して動かすときは pip install matplotlib numpy pandas scikit-learn scipy seaborn statsmodels が必要です。 読んでいるデータは data/raw/SSDSE-B-2026.csv。 日本語を含むので encoding='cp932' の指定を落とさないでください。
2 変量の可視化 を使うときに初学者が踏みやすい失敗パターン。 1 度経験してしまえば次から避けられますが、 先に知っておくに越したことはありません。
→ 2 変量を散布図で見ると、 「正の相関」「負の相関」「無相関」「非線形(U 字・S 字)」がひと目で見分けられる。 ピアソン相関は 線形関係のみ を測るため、 非線形パターンを 0 近傍で見落とすことがある。
以下 5 問を解いて理解度を確認してください。
| 手法 | 適する変数の型 | データ量目安 | 読み取れること |
|---|---|---|---|
| 散布図 | 連続 × 連続 | 〜1,000 件 | 関係の形・外れ値 |
| hexbin / 2D ヒスト | 連続 × 連続 | 1,000〜10 万件 | 密度の集中 |
| 相関ヒートマップ | 連続変数の行列 | 変数 10〜50 個 | 多変量間の関係構造 |
| 箱ひげ(並列) | カテゴリ × 連続 | 中央値・四分位 | 群間比較 |
| クロス集計表 | カテゴリ × カテゴリ | セル数 2x2〜10x10 | 連関・独立性検定 |
| バブルチャート | 連続 × 連続 + 1 補助 | 〜500 件 | 3 変量の同時表現 |
→ 「変数の型 × データ量」で選ぶ。 連続 × 連続 で 1 万件以上なら hexbin。 カテゴリ × 連続なら箱ひげ。 多変量同士の概観は相関ヒートマップが最強。
関連: 散布図 / 相関 / 箱ひげ図 / ヒストグラム / 棒グラフ
散布図は 2 変量の関係を「点の雲」として描く最も古典的かつ強力な可視化である。 統計学者 John Tukey は「探索的データ解析(EDA)」を提唱したとき、 散布図を中心に据えた。 1 万件以下なら散布図、 それを超えると hexbin(六角形ビン)や 2D ヒストグラム に切り替える。 hexbin は四角形ビンよりエッジ効果が小さく、 密度を直感的に読み取れる。
SSDSE-B-2026 の都道府県データのように n=47 の小規模データでは、 散布図上に都道府県名のラベルを付けるのが鉄則。 東京・大阪・愛知などの大都市が右上に外れ値として位置することが多く、 これを除いた回帰直線も併記すると「全国共通の傾向」と「大都市の例外性」を分離して議論できる。 ラベル衝突は adjustText ライブラリで自動回避できる。
相関ヒートマップは多変量の概観に必須。 seaborn.heatmap(df.corr(), annot=True, cmap='RdBu_r', center=0, vmin=-1, vmax=1) が定番。 vmin/vmax を必ず明示 して、 色の中央値 0 を保つことが重要(自動スケールだと相関 0.3 と 0.9 が同じ赤に見えてしまう)。 階層クラスタリングと組み合わせた クラスタマップ(seaborn.clustermap)は、 似た変数同士をまとめて並べ替えるため、 多変量の構造発見に強力。
カテゴリ × 連続の比較では並列箱ひげ図が標準だが、 ストリッププロット(点の散布)や バイオリンプロット(密度の左右対称表示)を重ねるとより情報量が増える。 群が 5 以上なら swarm plot で全データ点を非重複配置すると外れ値も見える。 群サイズが極端に異なる場合は箱の幅を n に比例させる varwidth オプションを使う。
カテゴリ × カテゴリのクロス集計は モザイクプロット や ヒートマップ + 注釈 が読みやすい。 セル度数の独立性は χ² 検定で判定。 セル度数が 5 未満ならフィッシャーの正確検定に切り替える。 SSDSE-B-2026 の都道府県を「人口階級 × 高齢化率階級」でクロス集計すると、 「高齢化が高く人口が少ない地方県」という塊が浮かび上がる。
バブルチャートは「散布図 + 第 3 変数を点サイズで」表現する手法。 例: 横軸 = 人口、 縦軸 = 1 人当たり総生産、 サイズ = 面積、 色 = 地方区分。 ただし サイズは直径ではなく面積で正規化 しないと心理的に過大評価される。 matplotlib では s=area で面積指定が標準。
時系列を 2 変量可視化する場合、 散布図ではなく 折れ線の 2 軸プロット が主流。 ただし 2 軸の単位が違うと「同期して動いている」かのような誤読を招くので、 必ず両軸の最小・最大を明示し、 標準化(z 変換)した値で 1 軸にまとめる方が安全な場合も多い。 動的に観察したいなら アニメーション散布図(年ごとに点が動く)が有効で、 Plotly の animation_frame オプションが代表例。
最後に、 Anscombe の 4 組 を必ず思い出すこと。 平均・分散・相関係数がすべて同一なのに、 散布図は全く違う形になる 4 つのデータセット。 「数値だけで判断せず必ず可視化する」という EDA の原則を示す古典例。 これと現代的な Datasaurus Dozen(恐竜の絵柄など 13 種類)を併記すると、 学習者の印象に残りやすい。
実務では「目的 × 受け手 × データ量」で可視化を決める。 たとえば 探索的解析(EDA) の場面では、 自分自身が外れ値や非線形性を発見したいので、 散布図 + 回帰直線 + LOWESS(局所回帰)を 1 枚に重ねるのが定石。 seaborn.regplot や seaborn.lmplot はこれを一行で実現する。 order=2 や lowess=True オプションで非線形性も即座に確認できる。
報告書・論文向け ではノイズを削ぎ落とした最小限の表現が好まれる。 散布図なら点サイズを小さく、 軸ラベルを大きく、 グリッドを薄く。 ヒートマップなら色数を 5-7 階級に離散化し、 凡例を明示。 カラーブラインドネス(色覚多様性)を意識して、 viridis や cividis のような色覚バリアフリーパレットを選ぶことも 2026 年現在の標準。 Nature や IEEE のガイドラインも明記している。
ダッシュボード・経営向け では「動かせる・絞り込める」が重要。 Tableau / Power BI / Plotly Dash で インタラクティブな散布図 を作り、 ホバーで都道府県名を表示、 クリックで詳細表示、 期間スライダーで時系列変化を見せる、 などが現実的。 静的な PDF ではなく Web に埋め込む前提で設計する。
最近のトレンドとして、 jointplot(散布図 + 周辺ヒストグラム)と pairplot(変数 n 個の散布図行列)は EDA の鉄板。 SSDSE-B-2026 の主要変数 6 個で pairplot を描くと、 36 枚(うち対角 6 枚が周辺分布、 残り 30 枚が散布図)が一気に得られる。 seaborn.pairplot(df, kind='reg', diag_kind='kde') でさらに回帰直線と密度推定が乗る。 これだけで「全体の関係構造」「外れ値」「分布形状」を 30 秒で把握できる。
注意すべき落とし穴として シンプソンのパラドックス がある。 全体での 2 変量関係と、 群別での関係が逆方向になる現象。 散布図に群別の色を付けると一目で分かる。 SSDSE-B-2026 でも「人口」と「1 人当たり所得」を全国でプロットすると弱い正の相関だが、 「首都圏 / 地方都市 / 地方郡部」で色分けすると群内では負の相関に転じることがある。 これを見逃すと施策判断を間違える。
2026 年現在、 Python での 2 変量可視化には複数の選択肢がある。 matplotlib は基盤ライブラリで自由度最大、 細部まで制御可能。 学術論文の最終図はほぼ matplotlib。 seaborn は matplotlib のラッパーで統計可視化に特化、 regplot、 jointplot、 pairplot など EDA で頻用。 デフォルトの配色が美しく学習コストが低い。
plotly はインタラクティブな HTML 出力に強く、 ホバー・ズーム・パンが標準搭載。 Web ダッシュボードや Jupyter Notebook での共有に最適。 altair は宣言的文法(Vega-Lite ベース)で、 「データ + マーク + エンコーディング」を簡潔に記述できる。 bokeh は plotly と並ぶ Web 系の選択肢で、 大規模データのストリーミング描画が得意。
R 系では ggplot2 が文法的可視化のデファクト。 「データ + aes + geom + scale + coord + theme」のレイヤー設計が美しい。 ヒートマップは geom_tile()、 散布図は geom_point() + geom_smooth()。 SAS や SPSS、 Stata にもそれぞれ標準の 2 変量可視化があるが、 学術・産業界とも近年は ggplot2 と seaborn が事実上の二大標準である。
大規模データ(100 万件以上)の可視化には datashader(Python)や vaex が登場している。 これらは描画前に GPU 加速で集約・ビン化を行い、 ピクセル単位で密度を計算するため、 hexbin より滑らかで高精細な結果が得られる。 NYC Taxi の 1 億件データセットでも数秒で散布図が出る。 Web ダッシュボード(HoloViews + Bokeh)への組み込みもしやすい。
最後に、 SSDSE-B-2026 の実データ例 として、 47 都道府県の「総人口(千人, A1101)」と「消費支出(円, L3221)」を散布図にすると、 中程度の正の関係(相関 0.33 程度)に加えて、 東京都・埼玉県などが右上寄りに位置する。 ここに seaborn の regplot(x='A1101', y='L3221', data=df) で回帰直線と 95% 信頼区間を重ねれば、 「弱いながら右上がり」「人口規模だけでは消費支出は決まらない」という構造が一目で読み取れる。 同じデータで jointplot(kind='reg') を使えば、 周辺ヒストグラムが両軸の歪んだ分布(右に長い裾)を同時に示してくれる。
2 変量可視化に習熟したら、 自然な発展先は 多変量可視化 である。 散布図行列(pairplot, SPLOM)は最も素直な拡張で、 d 変数あれば d×d 枚の小さな散布図を格子状に並べる。 ただし d > 10 になると見づらいので、 並行座標プロット(parallel coordinates)、 放射状プロット(radar chart)、 Chernoff faces といった多変量可視化に切り替える。
高次元データを 2 次元に落とすアプローチとして、 PCA(主成分分析) による次元削減後の散布図、 t-SNE や UMAP による非線形次元削減が定石。 SSDSE-B-2026 の 30 特徴量を UMAP で 2 次元にすると、 都道府県の類似グループが視覚的なクラスタとして表れる。 これに クラスタリング結果による色分け を重ねれば、 「数値表だけでは見えなかった構造」を一目で示せる。
時間軸を含む 3 変量可視化では、 ガントチャート風散布図(横軸=時刻、 縦軸=対象、 色=値)や カレンダーヒートマップ(GitHub の commit 履歴のような形式)が有効。 地理データを含むなら コロプレス図(地図塗り分け)が直感的。 SSDSE-B-2026 を都道府県地図に塗ると、 「東京-大阪-愛知の三角」「太平洋ベルト地帯」のような空間構造が即座に見える。 Plotly や Folium、 GeoPandas が代表的な実装ライブラリ。
2 変量可視化は単独で完結する技術ではなく、 記述統計(要約統計量)と組み合わせて初めて意味を持つ。 散布図を描いたら必ず、 平均・標準偏差・相関係数・p 値・回帰係数を併記する。 「数値だけ」「絵だけ」のどちらか一方は判断材料として不十分。 学術論文では「図 + 表 + 検定結果」のセットが標準である。 これは Tufte が「データ可視化の原則」で繰り返し強調する点でもある。
最後に「絵が物を言う」原則を改めて確認しておく。 統計家の Anscombe や Cleveland、 Tukey が口を揃えて指摘するように、 同じ要約統計量を持つデータでも、 形が違えば結論も違う。 散布図・ヒートマップ・箱ひげ図といった 2 変量可視化は、 数値の裏にある「形」を可視化するための強力な道具である。 SSDSE-B-2026 のような公的データを題材に、 様々なパターンで可視化を試すことが、 データサイエンス入門として最も効果的な学習法と言える。 慣れたら必ず多変量・時間軸・空間軸へと進めていくのが、 EDA から本格分析への王道である。
合成 6 点で 2 変数の相関係数を計算する。
| x | y |
|---|---|
| 1 | 2 |
| 2 | 4 |
| 3 | 5 |
| 4 | 7 |
| 5 | 9 |
| 6 | 11 |
1 2 3 4 5 | import numpy as np x = np.array([1,2,3,4,5,6]) y = np.array([2,4,5,7,9,11]) r = np.corrcoef(x, y)[0, 1] print(f"r: {r:.3f}") |
💬 手計算 (Step 2) 0.996 と Python 出力が完全一致。
2 変量可視化は「変数の型」と「観測数」で図を決める。
視覚で発見 → 数値で定量化 (相関係数・回帰) → 報告という流れが標準。
散布図 / ヒートマップは EDA の中核プロセスで、 以下と接続する。
2 変量可視化は「気付き」、 相関係数・回帰は「数値での裏付け」。 両方をセットで報告する。
2 変量可視化の知識ネットワーク。
中央に「2 変量可視化」を置き、 (a) 上位 = データ可視化全般 / EDA、 (b) 並列 = 散布図 / 箱ひげ / ヒートマップ / モザイクプロット、 (c) 派生 = Hexbin / 2D KDE / バイオリン、 (d) 前段 = データクリーニング / 対数変換 / 1 人あたり変換、 (e) 後段 = 相関係数 / 単回帰 / χ² 検定、 (f) 応用 = 関係性発見 / 異常検出 / グループ比較 が枝として伸びる。
SSDSE-B-2026 の場合、 「総人口 × 消費支出」散布図 → 相関 r≒0.33 → 「東京都・埼玉県が上方」発見 → 「1 世帯あたり」で正規化 → 再可視化、 という探索サイクルが基本パターン。
「viz bivariate」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「viz bivariate」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。
これらのキーワードは「viz bivariate の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
2 変量可視化 (viz bivariate) を 30 秒で把握する重要ポイント:
本ページでは「2 変量可視化 (viz bivariate)」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の「総人口 × 消費支出」「食料費 × 教育費」のような変数ペアを題材に、 散布図/箱ひげ/ヒートマップを使い分ける手順を再現する。
2 変量可視化は EDA カテゴリの中核プロセスで、 単変量分布の把握 → 2 変量関係発見 → 多変量可視化 (散布図行列・PCA バイプロット) と段階的に拡張する起点。 本ページは「変数型の組合せ別の図選択 → 過剰描画対策 → 相関係数/回帰での定量化への橋渡し」の 5 視点で構成される。
2 変量可視化 (viz bivariate) は「2 つの変数の関係を 1 枚の図に描く」手法群だ。 単変量は分布、 2 変量は関係性に焦点が移る。 代表は散布図、 ヒートマップ、 並列箱ひげ図、 二次元密度図、 モザイクプロットの 5 種類で、 変数の型 (連続 / カテゴリ) の組み合わせで使い分ける。
SSDSE-B-2026 で「総人口」と「消費支出」の関係を見たいとき、 散布図にすれば「人口が多い県ほど消費支出もやや高い」「東京都・埼玉県が上方にある」「人口規模だけでは説明できない散らばりがある」といった発見が一目で得られる。 数値だけでは見落とす外れ値、 非線形性、 群構造を視覚で捉えるのが 2 変量可視化の役割だ。
本ページでは、 「連続×連続 → 散布図、 連続×カテゴリ → 並列箱ひげ図、 カテゴリ×カテゴリ → ヒートマップ/モザイク」の選択軸を中心に、 SSDSE-B-2026 で実際にプロットしながら、 何が見えて何が見えないかを確認していく。
2 変量可視化は描画関数で定義される。 各図ごとに対応する数式・定義は以下。
散布図 (連続 × 連続): 各点 $(x_i, y_i)$ を 2 次元平面上にプロット。
$$\text{Scatter}(\{(x_i, y_i)\}_{i=1}^n) \to \text{点 } (x_i, y_i) \text{ を描画}$$
並列箱ひげ図 (連続 × カテゴリ): カテゴリ $g \in \{1,\dots,G\}$ ごとに 5 数要約 (最小, Q1, 中央値, Q3, 最大) を描画。
$$\text{BoxPlot}(\{y_i\}, \{g_i\}) \to \{(Q_1^g, Q_2^g, Q_3^g, Q_1^g - 1.5\text{IQR}, Q_3^g + 1.5\text{IQR})\}_{g=1}^G$$
ヒートマップ (カテゴリ × カテゴリ): 集計表 $C_{ij} = \text{count}(X=i, Y=j)$ を色で表現。
$$\text{Heatmap}(C) \to \text{セル }(i,j) \text{ を色強度 } \phi(C_{ij}) \text{ で塗る}$$
ここで $\phi$ は値→色のマッピング (例: linear, log)。
前節の数式に含まれる記号を、 日本語の意味に翻訳する。
2 変量可視化は「2 つの変数の値の対応関係」を視覚化するための数学的写像であり、 統計量を計算する前にデータの素顔を観察する重要な前工程となる。
SSDSE-B-2026 で「総人口」と「消費支出」の散布図を作るための値計算を 6 都道府県で示す。 散布図は 1 点ごとに座標を取るだけなので、 「数値 → 図」のマッピングが計算の主体。
| 都道府県 | x: 総人口 (千人) | y: 消費支出 (円) | 散布図上の位置 |
|---|---|---|---|
| 東京都 | 14086 | 341320 | (14086, 341320) ← 人口最大 |
| 神奈川県 | 9229 | 306565 | (9229, 306565) |
| 大阪府 | 8763 | 271246 | (8763, 271246) |
| 愛知県 | 7477 | 300221 | (7477, 300221) |
| 埼玉県 | 7331 | 344092 | (7331, 344092) ← 消費支出最大 |
| 千葉県 | 6257 | 306943 | (6257, 306943) |
視覚的観察: 6 点は緩やかな右上がりだが直線傾向は弱い (相関 r≒0.36)。 東京都は総人口が最大だが消費支出は埼玉県が最大 → 「人口規模だけでは消費支出は決まらない」。 1 世帯あたりに正規化すると順位が入れ替わる、という発見につながる。
🎯 このコードでやること: SSDSE-B-2026 から「総人口」と「消費支出」を読み込み、 散布図 + 回帰直線を matplotlib で描画。 相関係数も算出する。
📥 入力データ: SSDSE-B-2026 の 47 都道府県データ、 列 A1101 (総人口) と L3221 (消費支出)。 2023 年のみ抽出。
1 2 3 4 5 6 7 8 9 10 11 | import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import pearsonr
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
x, y = df['A1101'], df['L3221']
r, p = pearsonr(x, y)
print(f'Pearson r = {r:.3f}, p = {p:.2e}')
plt.scatter(x, y)
plt.xlabel('Population (1000)'); plt.ylabel('Consumption (JPY)')
plt.savefig('scatter.png', dpi=120)
|
📤 実行結果:
💬 結果の読み方: r≒0.33 は中程度の正の相関。 散布図を見ると、 人口が多い県ほど消費支出もやや高い傾向はあるが、 埼玉県のように人口が最大でなくても消費支出が高い県があり、 人口規模だけでは説明できない。 1 世帯あたりに正規化して再可視化すると関係が変わることもある (=要因変換のヒント)。
2 変量可視化の典型的な落とし穴を列挙する。
viz bivariate を中心に、 関連する概念・上位カテゴリ・応用領域を放射状に配置した。
2 変量可視化を中心に、 関連する技法・上位カテゴリ・応用領域を放射状に配置した。 中央から伸びる枝は、 (a) 前提として 1 変量可視化 (ヒストグラム・箱ひげ図) で各変数の分布を理解、 (b) 並列としてクロス集計 (両者ともペアの関係性可視化)、 (c) 発展として 3 変量以上の多変量可視化 (散布図行列・カラー次元追加)、 (d) 対比としてヒートマップ (連続 2 値 vs カテゴリ 2 値)、 (e) 統合として回帰分析 (散布図 + 回帰直線 + 信頼帯)、 (f) 応用として散布図行列 (pair plot) を示す。
SSDSE-B-2026 の 47 都道府県データで言えば、 「総人口 vs 消費支出」「食料費 vs 教育費」のような変数ペア間関係の発見に直結し、 単独の「散布図を描ける」段階から、 「散布図 + 周辺ヒストグラム + 回帰直線」を組み合わせて構造を読み解く段階に進むための起点となる。
2 変量可視化は EDA (探索的データ分析) の中核プロセスとして、 以下と接続する。
| 隣接手法 | 関係 | 接続のポイント |
|---|---|---|
| 単変量可視化 | 前段 / 並列 | 各軸の分布を先に確認すると外れ値・歪みを散布図で誤読しない |
| 多変量可視化 | 上位 / 拡張 | 3 変数以上の関係は散布行列、 パラレル座標、 PCA バイプロットで表現 |
| 相関分析 | 後段 / 定量化 | 散布図で見えた傾向を Pearson/Spearman r で数値化 |
| 単回帰分析 | 後段 / モデル化 | 散布図に回帰直線をオーバーレイし、 残差プロットへ展開 |
| 対数変換 | 前段 (前処理) | 散布図で右上がりの曲線 → log 軸で線形化 |
| カイ二乗検定 | 後段 (カテゴリ用) | ヒートマップで見える分布偏りを χ² で有意性検定 |
SSDSE-B-2026 の標準ワークフロー: ヒストグラム (単変量) → 散布図 (2 変量) → 相関係数 → 単回帰 → 残差診断、 という連鎖が定石。
2 変量可視化は「2 つの変数の型の組み合わせ」で図を選ぶ。
| 変数 A | 変数 B | 推奨図 |
|---|---|---|
| 連続 | 連続 | 散布図 (基本)。 点数 1000 超 → hexbin/2D KDE |
| 連続 | カテゴリ | 並列箱ひげ図 / バイオリンプロット / ストリッププロット |
| カテゴリ | カテゴリ | ヒートマップ / モザイクプロット / 積み上げ棒グラフ |
| 時系列 (連続) | 連続 | 折れ線グラフ (時系列性が主) / 散布図 (時系列性が副) |
| 順序カテゴリ | 連続 | 並列箱ひげ図 (順序で並べる) / ライン折れ線 |
| 連続 (右裾) | 連続 (右裾) | 対数軸散布図 (両軸 log) で線形化 |
この 2 変量可視化 ページで出てくる主要キーワードを一覧します。チップをクリックすると該当箇所へジャンプできます。
あなたは、可視化 の入口で「2 変量可視化(Bivariate Visualization)」という用語に出会ったところです。 この用語は 2 つの変数の関係(相関・分布の重なり・因果の手掛かり)を 1 枚の図で表現する手法群。
本ページでは、まず数式や形式的定義よりも、実データ(SSDSE-B-2026, 47 都道府県)で具体的な値を見ます。 そのあと、数式 → 計算 → Python 実装 → 落とし穴 → 関連用語、という順で「使える知識」に組み立てていきます。
2 変量可視化 の本質は、ひとことで言うと「2 つの変数の関係(相関・分布の重なり・因果の手掛かり)を 1 枚の図で表現する手法群。」です。 数式に踏み込む前に、まずイメージで掴みましょう。
ヒント:直感が掴めたら、次の「数式または定義」セクションで形式化を確認してください。 形式化と直感がつながれば、2 変量可視化 はもう武器です。
2 変量可視化 を一般化して書くと、観測ペア $(x_1, y_1), \dots, (x_n, y_n)$(ここでは $n = 47$ 都道府県)に対して、次の関係を仮定します。
$$ \boxed{\quad y = f(x_1, x_2, \dots, x_p; \theta) + \varepsilon \quad} $$ここで $\theta$ は推定したいパラメータ、$\varepsilon$ はモデルでは説明しきれない誤差項。 2 変量可視化 の流派ごとに、$f$ の形(線形・ロジスティック・木)、$\varepsilon$ の分布(正規・二項・ポアソン)が変わります。
| 記号 | 意味 | SSDSE-B での例 |
|---|---|---|
| $x$ | 説明変数 | A1303(65 歳以上人口比 × 死亡率) |
| $y$ | 目的変数 | 死亡率・出生率など |
| $n$ | 標本数 | 47(都道府県数) |
| $\theta$ | パラメータ | 傾き・切片など |
| $\varepsilon$ | 誤差項 | モデルで説明しきれない残り |
上の式 $y = f(x; \theta) + \varepsilon$ を「数学者の声」ではなく、「現場の声」で読み直してみます。
合言葉:「定義は短い、解釈は長い」。2 変量可視化 はたった 1 行の式ですが、それを 47 都道府県データに当てると、5 種類のチェックリスト(線形性・独立性・等分散・正規性・外れ値)が芋づる式に出てきます。
数式が読めたら、すぐに 実データ(SSDSE-B-2026, 47 都道府県, 2023 年度)で計算しましょう。 抽象を 47 行の表に落とすと、急に理解できることがあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import pandas as pd # df2023 はこのあとのブロックで作っているので、ここでも用意しておく df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df2023 = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) # 2 変量可視化 の代表値を SSDSE-B-2026 で確認 col = 'A1303' s = df2023[col].astype(float) print('n :', len(s)) # 47 print('mean :', round(s.mean(), 2)) print('median :', round(s.median(), 2)) print('std :', round(s.std(), 2)) print('min / max :', s.min(), '/', s.max()) print('Top 3 prefs :') print(df2023.nlargest(3, col)[['Prefecture', col]]) |
結果を見ると、47 都道府県のうち上位 3 県が突出しているか、なだらかに分布しているか、すぐ分かります。 この「分布の形」が見えると、2 変量可視化 を語る土台ができたことになります。
Python の実装は「読む → 集計 → 描く → 報告」を一直線に書きます。長いコードよりも、各ステップが分離していることが大事です。
1 2 3 4 5 6 7 8 9 10 11 | import pandas as pd import numpy as np import matplotlib.pyplot as plt # SSDSE-B-2026 を読み込み(65 歳以上人口比 × 死亡率) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) # 2023 年度(最新)だけ抽出 df2023 = df[df['SSDSE-B-2026'] == 2023].copy() print(df2023.shape) # (47, ...) print(df2023[['Prefecture', 'A1303']].head()) |
# 2 変量可視化 を 47 都道府県でビジュアル化
fig, ax = plt.subplots(figsize=(9, 6))
df2023.sort_values(col, ascending=False).plot.bar(
x='Prefecture', y=col, ax=ax, color='#00897B', legend=False)
ax.set_title('65 歳以上人口比 × 死亡率(SSDSE-B-2026, 2023)')
ax.set_ylabel(col)
ax.set_xlabel('都道府県')
plt.xticks(rotation=90)
plt.tight_layout()
plt.savefig('figures/viz-bivariate.html_r18_bar.png', dpi=120)
plt.show()
レポート文例:「SSDSE-B-2026(2023 年度, n=47)に基づいて 2 変量可視化 を確認したところ、平均は X、標準偏差は Y、上位 3 県は東京・神奈川・大阪であった。 SSDSE-B-2026 の高齢化率と死亡率を散布図にすると、47 点が右上がりの強い直線関係(r ≈ +0.97)を描きます。」
合言葉:レポート提出前に「ゼロ起点で 1 枚描き直す」「外れ値を 1 県外して再計算」「逆方向の因果を 1 行で否定する」を必ずやる。
本ページに登場した Python コードはすべて以下のテンプレートで読み解けます:
覚え方:「Read → Roll up → Render → Read it back」。 最後の「Read it back」は、出力された数字や図を口に出して 1 度言うこと。 これで 2 変量可視化 の現場運用は十分に回ります。
使います。前処理(特徴量 → 入力ベクトル)、評価(指標の可視化)、解釈(係数の可視化)など、機械学習のあらゆる工程で 2 変量可視化 は登場します。
記述統計や 1 変量・2 変量の可視化には十分。ただし複数の説明変数を同時に検討するときは、自由度が枯れます。bootstrap や情報量規準(AIC/BIC)で補強しましょう。
独立行政法人統計センター(NSTAC)「SSDSE」サイトから無料でダウンロードできます。本ページの実装はすべて data/raw/SSDSE-B-2026.csv を前提にしています。
SSDSE は教育目的での利用が許諾されています(出典明示、改変記録)。論文公開時は出典欄に「総務省統計局, SSDSE-B-2026」を必ず書きましょう。
① ヒストグラム 1 枚を描く → ② 平均・中央値・標準偏差を読み上げる → ③ 上位 3 県・下位 3 県を暗記する → ④ 2 変量の相関を 1 つ確認する → ⑤ レポート 1 行にまとめる。これを 47 都道府県データで 3 回回せば、用語の地形が掴めます。
本リポジトリの 論文一覧 から「可視化」カテゴリの論文を見ると、2 変量可視化 を実際に使った再現コードが付いています。
「目的 → データ → 2 変量可視化 の選択理由 → 結果(図 + 数値)→ 解釈 → 限界(n=47, 単年)→ 次の一手」の順が王道です。
用語は単独では覚えづらいので、前提・並列・発展の 3 方向で 16 件並べます。
勧め方:1 日 1 リンク。クリックして読んだら、2 変量可視化 のページに戻り、「2 変量可視化 とこの用語はどう違う?」を 1 行書く。
合言葉:5 STEP のうちどれか 1 段でも飛ばすと、結論が「数字だけ」になり、読者の腑に落ちなくなります。 2 変量可視化 は「数字 + 物語」のセットで完成です。
np.random.seed で作って「再現実験しました」と書く(教育用途では SSDSE-B-2026 を使うのが必須)iloc[:, 5] のように位置で参照し、SSDSE のバージョン違いで壊れるコードを書くx1, x2, x3 のように匿名化し、読者が意味を追えないコードにする2 変量可視化 は、19 世紀末〜 20 世紀初頭の統計学黎明期から発達してきました。可視化 の中核として、Galton、Pearson、Fisher、Yule などが基礎を築き、現代では SSDSE のような公的データを使った教育素材で広く扱われています。
2 変量可視化 は、観測ペア $(x_i, y_i)_{i=1}^{n}$ から条件付き期待値 $E[y \mid x]$ または分布 $P(y \mid x)$ を推定する道具です。 線形・非線形・パラメトリック・ノンパラメトリックという 4 つの軸の中で、2 変量可視化 は「可視化」という棚に並んでいます。
df.dropna() の前に必ず欠損率を df.isna().mean() で測る。2 変量可視化 は 記述統計・データサイエンス・機械学習 の交差点に位置します。 どの分野から入っても、いずれは 2 変量可視化 を通ります。
同じテーマで使い回せる narration を 5 つ並べておきます。コピペして「コード解説」欄に貼ってください。
2 変量可視化 を学ぶときに使う SSDSE-B-2026 は、47 都道府県 × 約 110 列 × 複数年度のパネルデータです。 本ページでは「2023 年度の 47 行」を主に使います。 以下に、よく登場する代表的なカラムを示します。
| SSDSE コード | 日本語名 | 単位 | 2 変量可視化 での主な使い方 |
|---|---|---|---|
| Code | 地域コード | — | JOIN キー |
| Prefecture | 都道府県名 | — | カテゴリ軸・ラベル |
| A1101 | 総人口 | 人 | 説明変数(規模) |
| A1303 | 65 歳以上人口 | 人 | 高齢化率の分子 |
| A4101 | 出生数 | 人 | 人口動態の説明変数 |
| A4200 | 死亡率 | ‰ | 目的変数の代表 |
| B4101 | 年平均気温 | ℃ | 気候系の説明変数 |
| L3221 | 消費支出 | 円 | 家計の目的変数 |
使い方のコツ:列名はすべて A1101 のような英数記号です。SSDSE のコードブックで日本語ラベルを確認しながら使ってください。
本ページの例では A1303, A4200(65 歳以上人口比 × 死亡率)を中心に使っています。
解説は最小限。コードは 10 行以内。これで 2 変量可視化 の最短ルートが手に入ります。
import pandas as pddf = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])df = df[df['SSDSE-B-2026'] == 2023]col = 'A1303'print(df[['Prefecture', col]].sort_values(col, ascending=False).head())import matplotlib.pyplot as pltdf.plot.hist(y=col, bins=20)plt.title('65 歳以上人口比 × 死亡率(SSDSE-B-2026, 2023)')plt.savefig('figures/viz-bivariate.html_r18_hist.png', dpi=120)plt.show()注意:10 行で動かせる、というだけで、これがゴールではありません。 2 変量可視化 の本当の難しさは「描いた図をどう解釈するか」「報告にどう落とすか」にあります。
2 変量可視化 の結果を、ゼミ・卒論・社内会議で報告するときの定型文を 3 つ用意しました。 最初は丸ごとコピー、慣れたら差し替えて使ってください。
「本研究では、SSDSE-B-2026(n=47, 2023 年度)を用いて 2 変量可視化 を確認した。 主たる説明変数は A1303, A4200(65 歳以上人口比 × 死亡率)であり、47 都道府県を対象とした分布の確認、相関の評価、2 変量可視化 を用いた分析を実施した。 分析の結果、上位 3 県・下位 3 県の特徴と、SSDSE-B-2026 の高齢化率と死亡率を散布図にすると、47 点が右上がりの強い直線関係(r ≈ +0.97)を描きます。」
「65 歳以上人口比 × 死亡率 を 47 都道府県で比較したところ、東京・神奈川・大阪など大都市圏が突出していることが分かった。 2 変量可視化 を用いた分析から、地域差は単に人口規模の違いだけでは説明できず、複数要因の組み合わせで生じていると示唆された。 今後の打ち手は、上位県のベストプラクティスを参考にしつつ、下位県への支援策を検討することである。」
「皆さん、2 変量可視化 はひとことで言うと『2 つの変数の関係(相関・分布の重なり・因果の手掛かり)を 1 枚の図で表現する手法群。』です。 今回は SSDSE-B-2026(総務省統計局, 47 都道府県, 2023 年度)を使って、実際の数字でこの考え方を確かめました。 皆さん自身でも、別の指標(人口、出生率、家計支出など)に置き換えて同じ手順を試してみてください。」
同じ用語でも、見る立場によって意味が変わります。3 つの視点を切り替えて、用語の輪郭を立体的に掴みましょう。
統計学者にとって 2 変量可視化 は「データから母集団を推定する道具」です。 確率モデル・尤度・不偏性・効率性・一致性などの数学的性質に注目し、漸近理論で性能保証を行います。 47 都道府県データは「小標本(n=47)」と分類され、bootstrap や情報量規準による補強が必要になります。
データサイエンティストにとって 2 変量可視化 は「ビジネス課題を数字で答えるパイプラインの 1 部品」です。 モデルの理論的性質より、運用性・解釈性・更新コストを重視します。 SSDSE のような公的データを用いるときは「データの出典・更新頻度・ライセンス」を最優先で確認します。
教育の現場では 2 変量可視化 は「初学者が躓きやすいポイント」を含む単元です。 抽象的な数式よりも、具体的な 47 都道府県データで手を動かし、図を描き、結果を口頭で説明できるようになることが目標になります。 本ページの並び(直感 → 数式 → 計算 → Python → 落とし穴)は、まさにこの教育的アプローチに沿っています。
視点切り替えの効果:1 つの用語を 3 通りに眺めると、自分が今どの立場で議論しているか自覚できます。 論文を読むときは ①、現場で使うときは ②、人に教えるときは ③ ── と意識的に切り替えてください。
2 変量可視化 と似た用語を、使い分けの観点から並べます。違いを言語化できれば、迷いが減ります。
| 用語 | 目的 | 入力 | 出力 | 強み | 弱み |
|---|---|---|---|---|---|
| 2 変量可視化 | 2 つの変数の関係(相関・分布の重なり・因果の手掛かり)を 1 枚の図で表現する手法群。 | 47 都道府県 × 約 110 変数 | 図 + 表 + 200 字レポート | 直感的、再現容易 | 小標本(n=47)の制約 |
| 相関係数 | 2 変量の同調を 1 数で要約 | x, y の 47 ペア | r ∈ [−1, +1] | シンプル | 非線形は捉えられない |
| 線形回帰 | 条件付き期待値の線形近似 | 説明変数群 | 回帰係数・予測値 | 解釈容易 | 非線形には弱い |
| ロジスティック回帰 | 2 値分類 | 説明変数群 | 確率 + 係数 | 分類問題の標準 | 線形決定境界 |
| ランダムフォレスト | 非線形分類・回帰 | 大量変数 | 予測 + 重要度 | 非線形対応 | 解釈やや難 |
2 変量可視化 は 可視化 の中で「2 つの変数の関係(相関・分布の重なり・因果の手掛かり)を 1 枚の図で表現する手法群。」を担う基本道具です。可視化 の他のトピックは、この基本の応用または並列の道具にあたります。
使えます。SSDSE-A(市区町村)、SSDSE-C(年次推移)、SSDSE-D・E(個票)など、2 変量可視化 の手順はそのまま適用できます。粒度(県・市・個人)に応じて n が変わるので、結果の信頼性も変わります。
SSDSE は年に 1 度更新されます。2 変量可視化 のコード自体は変更不要ですが、結果(数値・図)は最新年度のものに置き換えてレポートしましょう。出典欄に「SSDSE-B-2027(仮)」と書き換えるのを忘れずに。
できます。ピボット → グラフ → 関数 で代表値や相関は出ます。ただし、再現性・履歴管理・自動化の面で Python に劣ります。学習用には Python を強く勧めます。
進めます。2 変量可視化 は機械学習の「特徴量設計」と「結果解釈」の両端で必須です。AI と聞くと深層学習を連想しがちですが、SSDSE のような表形式データでは線形モデル + 2 変量可視化 の組み合わせで十分実用になります。
3 つ確認します:①ファイルパス(data/raw/SSDSE-B-2026.csv)が合っているか、②エンコーディングが cp932 か、③ヘッダ 2 行目の日本語ラベルを skiprows で飛ばしたか。これで 9 割解決します。
figures/ ディレクトリが存在しない可能性があります。import os; os.makedirs('figures', exist_ok=True) を先頭に追加してください。
本ページの 12 セクションを順に読み進めるのが最短です。特に「直感 → 数式 → 計算 → Python」の 4 段が腑に落ちれば、用語の 80 % は理解できたとみなせます。
このカードを印刷し、SSDSE-B-2026 で 1 回手を動かせば、用語の「使える形」が定着します。 2 変量可視化 はあくまで「2 つの変数の関係(相関・分布の重なり・因果の手掛かり)を 1 枚の図で表現する手法群。」というシンプルな考え方の道具ですので、迷ったらこの 1 行に戻ってください。
スライダーで 2 変数の相関の強さ・向き を変えると、散布図の形と ピアソン相関係数 r がリアルタイムで変化します。表示を 散布図 / 2 次元ヒストグラム(ヒートマップ)/ 点密度 に切り替えたり、 回帰直線を重ねたりして、「関係が図でどう見えるか」を体感してください。 非線形の例ボタンでは、はっきりした関係があるのに r がほぼ 0 になる様子も確認できます。 (散布図の上を左右にドラッグしても相関を変えられます。スマホのタッチ操作対応)
散布図は 2 変数を縦横の座標に置き、点の雲の傾きで関係の向き、雲の細さで関係の強さを表します。 r は「点がどれだけ 1 本の直線に沿うか」を −1〜+1 で測る数値で、上のスライダーを右に振ると点が右上がりの細い帯に、左に振ると右下がりに、中央では丸い雲になります。 点が多くて重なるときはヒートマップや点密度表示に切り替えると、「どこに点が集中しているか」が色で見えます。
3 つ以上の変数を同時に見るときは、全変数ペアの散布図を格子状に並べた散布図行列(pairplot)や、 相関係数を色で並べた相関行列ヒートマップが定番です。まず 2 変量で「見る目」を鍛えると、多変量でも当たりを付けやすくなります。 SSDSE-B-2026(cp932 / 2023 年 47 都道府県)では、高齢化率と死亡率が右上がりの強い直線関係(本ページ本文の実測値を参照)を示すなど、実データでこの体感を確かめられます。
関連ページ: 相関 / 散布図 / 回帰直線 / 因果 / 見せかけの相関 / ヒートマップ / カーネル密度推定 / 1 変量の可視化
このページの他セクション(散布図の読み方・落とし穴・実装・関連用語)とは重複しない角度だけを集めた補遺です。テーマは「見え方はデータではなく描き方で変わる」という一点に絞ります。
2 変量可視化は結局、「X をある値に固定したとき Y はどう散らばるか」= 条件付き分布 P(Y|X) を読む作業に還元できます。グラフを X 軸に沿った縦の短冊(スライス)に切って眺めると、どの図も同じものの別表現だと分かります。
だから図の選択は本質的に (X の型 × Y の型) で決まります。連続×連続なら散布図、質的×連続なら層別箱ひげ、質的×質的ならモザイク/クロス集計ヒートマップ、という対応はこの「スライスをどう要約するか」の違いにすぎません。
① アスペクト比バンキング(縦横比で傾きの印象が変わる)。 SSDSE-B-2026・2023年・47都道府県で 保健医療費(L322106)× 教育費(L322108) をとると、実測で r = 0.557 / 回帰直線の傾き = 1.095(いずれも実際に計算した値)。r は座標の拡大縮小で不変ですが、画面上で回帰直線が何度に見えるかは図の縦横比で変わります(実データの範囲 x=[11052,21000], y=[4316,24160] から算出):
| 図の縦横比 (幅:高さ) | 回帰直線の見かけの角度 | 受ける印象 |
|---|---|---|
| 2 : 1(横長) | 約 15.3° | 「ほぼ横ばい・弱い」 |
| 1 : 1(正方形) | 約 28.8° | 「そこそこ」 |
| 1 : 2(縦長) | 約 47.7° | 「急・強い」 |
同一データ・同一 r = 0.557 のまま、縦横比だけで印象が「弱い」から「強い」へ振れます。回帰直線をちょうど 45° に立てる(Cleveland の banking to 45°)縦横比は実測で 幅:高さ ≈ 0.549 : 1。教訓:見た目に頼らず r と傾きを数値で併記し、比較する複数図では縦横比を揃えること。プレゼンで「関係が強く見える散布図」は、縦横比が仕込まれていないか疑うべきです。
② 2次元密度図の「空セル」問題(点が少ないと密度は嘘をつく)。 ヒートマップ化した散布図・hexbin・2次元 KDE は「セルあたり何点あるか」で信頼度が決まります。都道府県データは n = 47 しかありません:
(いずれも 47 ÷ セル数の実算値。)1 次元のヒストグラムは数十点でも形が見えますが、2 次元は面積で薄まるため必要点数が桁違いに増えます。n=47 で細かい hexbin/KDE を描くと、実体のない「まだら模様」を構造と誤読しがちです。少数データでは素の散布図+都道府県ラベルが最も正直で、密度図は数千点以上あるときの道具だと割り切りましょう。
2 変量の同時分布は P(X,Y) = P(X)·P(Y|X) と分解できます。jointplot が散布図の上下右に周辺ヒストグラムを添えるのは、この 周辺分布(各軸単独の姿)と条件付き分布(相手を固定した姿)を同時に見せるためです。散布図で外れて見える点が、周辺分布では「単に X が極端なだけ」と分かることも多く、両方を並べると誤読が減ります。
第 3 変数を足すとき、色分け(hue)は 5〜7 系統で飽和します。地域ブロックのようにカテゴリが多い場合は、色を増やすより 小さな倍数図(small multiples / ファセット)——同じ軸の散布図をカテゴリごとに並べる——ほうが、各条件付き分布を公平に比較でき、オーバープロットも自然に緩和されます。「色を増やしたくなったら図を分ける」が実務の目安です。
数値の出典:data/raw/SSDSE-B-2026.csv を pd.read_csv(encoding='cp932', skiprows=[1]) で読み、df[df['SSDSE-B-2026']==2023](47都道府県)で算出。r・傾き・見かけの角度・セルあたり点数はすべて実測値。合成データは使用していません。