このページの分析を自分で再現するには、以下の手順でデータを準備してください。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
私たちの毎日の時間はどのように配分されているのか。仕事・家事・睡眠・趣味など、生活時間の構成は個人の幸福感や生活の質(QoL)と深く結びついていると考えられる。本研究は SSDSE-D(社会生活基本調査 都道府県別生活時間データ)を活用し、生活時間配分の地域差・性差を統計的に明らかにする。
まず「生活時間と幸福感:SSDSE-D「社会生活基本調査」を用いた年代別分析」を統計的にとらえることが有効だと考えられる。 その理由は感覚や経験則だけでは、複雑な社会要因の中で「何が本当に効いているか」を見極めにくいからである。 本研究では公開データと統計手法を組み合わせ、この問いに定量的な答えを出すことを目指す。
SSDSE-D 社会生活基本調査 相関分析 主成分分析(PCA) 性差・地域差比較
SSDSE-D は総務省統計局「社会生活基本調査」(5年ごと実施)の都道府県別集計データを、統計数理研究所が教育・研究用に整備したものである。本分析では 2021年実施(2023年公開)版を使用した。
| カテゴリ | 変数名(SSDSE-D) | 全国平均(総数・分/週) | 地域差の大きさ |
|---|---|---|---|
| 必需的行動 | 睡眠 | 474 分 | 468〜488(幅 20分) |
| 必需的行動 | 食事 | 99 分 | 94〜105(幅 11分) |
| 拘束的行動 | 仕事 | 209 分 | 186〜227(幅 41分) |
| 拘束的行動 | 家事 | 88 分 | 79〜100(幅 21分) |
| 拘束的行動 | 通勤・通学 | 28 分 | 22〜36(幅 14分) |
| 自由時間 | 趣味・娯楽 | 45 分 | 38〜56(幅 18分) |
| 自由時間 | テレビ・ラジオ・新聞・雑誌 | 133 分 | 106〜155(幅 49分) |
| 自由時間 | スポーツ | 13 分 | 9〜17(幅 8分) |
| 自由時間 | 学習・自己啓発 | 11 分 | 6〜18(幅 12分) |
赤字は地域差(幅)が特に大きい変数。仕事・通勤・テレビ時間で都道府県間の差が顕著。
encoding='cp932'、header=1(2行目をヘッダ行として使用)で読み込む必要がある。また、「男女の別」列に 0_総数 / 1_男 / 2_女 の3種類の行が混在しており、分析目的に応じて適切にフィルタリングする。
47都道府県の生活時間配分を積み上げ横棒グラフで可視化した。仕事時間(週あたり分)の短い順に並べることで、生活時間構造の地域差が明確に浮かび上がる。
| 都道府県(グループ) | 仕事時間(分/週) | 趣味・娯楽(分/週) | 特徴 |
|---|---|---|---|
| 島根県(最長) | 227 | 38 | 仕事最長、趣味は少ない |
| 富山県 | 224 | 42 | 勤勉な働き方 |
| 石川県 | 224 | 49 | 仕事と趣味のバランス型 |
| 全国平均 | 209 | 45 | 基準値 |
| 京都府(最短) | 186 | 44 | 仕事最短、文化的生活 |
| 奈良県 | 189 | 50 | 趣味・娯楽が相対的に多い |
生活時間は「1日(または1週)の合計時間」という制約条件下で各活動に配分される。この「固定合計を持つ組成データ(compositional data)」の可視化には積み上げ棒グラフが有効で、各カテゴリの相対的比率と絶対量の両方が一覧できる。
並べ替えの基準変数(ここでは仕事時間)を決めることで、変数間のパターンを効率よく探索できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | time_cols_main = ['睡眠', '仕事', '家事', '育児', '買い物', 'テレビ・ラジオ・新聞・雑誌', '休養・くつろぎ', '趣味・娯楽', 'スポーツ', '交際・付き合い'] colors_main = ['#5C85D6', '#E05C5C', '#F4A261', '#76C442', '#9B59B6', '#3D9970', '#F9A825', '#1ABC9C', '#E74C3C', '#95A5A6'] # 仕事時間で並び替え(47都道府県) df_sorted = total.sort_values('仕事', ascending=True).reset_index(drop=True) fig, ax = plt.subplots(figsize=(10, 13)) lefts = np.zeros(len(df_sorted)) for col, color in zip(time_cols_main, colors_main): vals = df_sorted[col].values ax.barh(df_sorted['都道府県'], vals, left=lefts, color=color, label=col, alpha=0.85) lefts += vals ax.set_xlabel('1週間の合計時間(分)', fontsize=12) ax.set_title('都道府県別 主要生活時間配分\n(仕事時間の短い順)', fontsize=14, fontweight='bold') ax.legend(loc='lower right', fontsize=8, ncol=2) ax.grid(axis='x', alpha=0.3) ax.tick_params(axis='y', labelsize=8) plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_U5_13_fig1_time_stack.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig1 saved: 生活時間配分積み上げ棒グラフ") |
Fig1 saved: 生活時間配分積み上げ棒グラフ
fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。sort_values('列名', ascending=False) — 指定列で並べ替え(降順)。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。全国計の男女別データを比較し、生活時間配分の性差を可視化した。各活動について「男性 − 女性」の差分を注記し、どの活動で性差が大きいかを直観的に示す。
| 活動カテゴリ | 男性(分/週) | 女性(分/週) | 差(男−女) | 解釈 |
|---|---|---|---|---|
| 仕事 | 267 | 152 | +115 | 最大の性差。男性が圧倒的に長い |
| 家事 | 25 | 146 | −121 | 女性が5.8倍。家事の性的分業を示す |
| 育児 | 6 | 21 | −15 | 育児も女性が3.5倍 |
| 買い物 | 18 | 33 | −15 | 買い物も女性が多い |
| 通勤・通学 | 38 | 24 | +14 | 男性の通勤時間が長い(雇用形態の差) |
| 趣味・娯楽 | 60 | 37 | +23 | 自由時間の活用でも性差 |
| 睡眠 | 478 | 469 | +9 | 男性がわずかに長い |
| 交際・付き合い | 8 | 12 | −4 | 女性の社交時間がやや多い |
2グループの棒グラフを並べる際に「差分ラベル」を各棒の上に表示することで、読者は具体的な数値差を一目で把握できる。正負の差を色で区別(青=男性多・赤=女性多)することで、パターンの解読をさらに助ける。
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 | gender_cols = ['睡眠', '仕事', '家事', '育児', '通勤・通学', '買い物', 'テレビ・ラジオ・新聞・雑誌', '休養・くつろぎ', '趣味・娯楽', 'スポーツ', '学習・自己啓発・訓練(学業以外)', '交際・付き合い'] label_map = { '睡眠': '睡眠', '仕事': '仕事', '家事': '家事', '育児': '育児', '通勤・通学': '通勤・通学', '買い物': '買い物', 'テレビ・ラジオ・新聞・雑誌': 'TV・ラジオ等', '休養・くつろぎ': '休養・くつろぎ', '趣味・娯楽': '趣味・娯楽', 'スポーツ': 'スポーツ', '学習・自己啓発・訓練(学業以外)': '学習・自己啓発', '交際・付き合い': '交際・付き合い', } male_vals = [nat_male[c] for c in gender_cols] female_vals = [nat_female[c] for c in gender_cols] labels = [label_map[c] for c in gender_cols] x = np.arange(len(labels)) width = 0.38 fig, ax = plt.subplots(figsize=(12, 6)) bars_m = ax.bar(x - width/2, male_vals, width, label='男性', color='#4e9af1', alpha=0.85) bars_f = ax.bar(x + width/2, female_vals, width, label='女性', color='#f06292', alpha=0.85) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | # 差分アノテーション for i, (m, f) in enumerate(zip(male_vals, female_vals)): diff = m - f sign = '+' if diff > 0 else '' color = '#1565C0' if diff > 0 else '#C62828' ax.text(x[i], max(m, f) + 4, f'{sign}{diff}分', ha='center', va='bottom', fontsize=7.5, color=color, fontweight='bold') ax.set_xticks(x) ax.set_xticklabels(labels, rotation=30, ha='right', fontsize=10) ax.set_ylabel('1週間の平均時間(分)', fontsize=12) ax.set_title('生活時間の男女差(全国計)\n(数値は男性 − 女性、青=男性が多い、赤=女性が多い)', fontsize=13, fontweight='bold') ax.legend(fontsize=11) ax.grid(axis='y', alpha=0.3) plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_U5_13_fig2_gender.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig2 saved: 性別生活時間差") |
Fig2 saved: 性別生活時間差
fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。「仕事時間と余暇はトレードオフか?」という問いを検証するため、散布図と相関分析を行った。左図は仕事時間 vs 趣味・娯楽時間、右図は家事時間 vs テレビ・ラジオ時間のそれぞれ47都道府県の散布図である。
| 変数の組み合わせ | Pearson r | p値 | 統計的有意性 | 解釈 |
|---|---|---|---|---|
| 仕事時間 ↔ 趣味・娯楽時間 | −0.295 | 0.044 | ★ 有意(p<0.05) | 仕事が多い県は趣味が少ない傾向 |
| 仕事時間 ↔ 家事時間 | −0.699 | <0.001 | ★★ 強い負の相関 | 仕事が多い県は家事が少ない |
| 仕事時間 ↔ 買い物時間 | −0.540 | <0.001 | ★★ 中程度の負の相関 | 仕事が多い県は買い物が少ない |
| 睡眠 ↔ 学習・自己啓発 | −0.642 | <0.001 | ★★ 強い負の相関 | 睡眠時間が多い県は学習が少ない |
| 家事時間 ↔ TV時間 | 0.017 | 0.910 | 非有意 | 関係は見られない |
Pearson の相関係数 r は −1 から +1 の値をとり、2変数の線形関係の強さを表す。N=47 での帰無仮説「相関なし(ρ=0)」の検定では、|r| ≥ 0.288 程度で p < 0.05 となる(両側検定)。Cohen (1988) の基準は r=0.1(小)・0.3(中)・0.5(大)。
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | fig, axes = plt.subplots(1, 2, figsize=(14, 6)) # 左: 仕事時間 vs 趣味・娯楽時間 ax = axes[0] for reg, grp in total.groupby('地域'): ax.scatter(grp['仕事'], grp['趣味・娯楽'], color=region_colors.get(reg, 'gray'), label=reg, s=55, alpha=0.85) for _, row in total.iterrows(): ax.annotate(row['都道府県'][:2], (row['仕事'], row['趣味・娯楽']), fontsize=6.5, alpha=0.7, xytext=(2, 2), textcoords='offset points') x_vals = total['仕事'].values y_vals = total['趣味・娯楽'].values slope, intercept, r, p_val, _ = stats.linregress(x_vals, y_vals) xr = np.linspace(x_vals.min(), x_vals.max(), 100) ax.plot(xr, slope * xr + intercept, 'k--', linewidth=1.5, label=f'回帰直線\nr={r:.2f}, p={p_val:.3f}') ax.set_xlabel('仕事時間(分/週)', fontsize=12) ax.set_ylabel('趣味・娯楽時間(分/週)', fontsize=12) ax.set_title('仕事時間 vs 趣味・娯楽時間\n(N=47都道府県, 総数)', fontsize=12, fontweight='bold') ax.legend(fontsize=7.5, ncol=2) ax.grid(alpha=0.3) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。stats.linregress(x, y) — 単回帰の傾き・切片・r値・p値・標準誤差を返します。使わない値は _ で受け取り。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。[式 for x in リスト] はリスト内包表記。forループでappendする代わりに1行でリストを作れます。94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | # 右: 家事時間 vs テレビ・ラジオ時間 ax = axes[1] for reg, grp in total.groupby('地域'): ax.scatter(grp['家事'], grp['テレビ・ラジオ・新聞・雑誌'], color=region_colors.get(reg, 'gray'), label=reg, s=55, alpha=0.85) for _, row in total.iterrows(): ax.annotate(row['都道府県'][:2], (row['家事'], row['テレビ・ラジオ・新聞・雑誌']), fontsize=6.5, alpha=0.7, xytext=(2, 2), textcoords='offset points') x_vals2 = total['家事'].values y_vals2 = total['テレビ・ラジオ・新聞・雑誌'].values slope2, intercept2, r2, p_val2, _ = stats.linregress(x_vals2, y_vals2) xr2 = np.linspace(x_vals2.min(), x_vals2.max(), 100) ax.plot(xr2, slope2 * xr2 + intercept2, 'k--', linewidth=1.5, label=f'回帰直線\nr={r2:.2f}, p={p_val2:.3f}') ax.set_xlabel('家事時間(分/週)', fontsize=12) ax.set_ylabel('TV・ラジオ等時間(分/週)', fontsize=12) ax.set_title('家事時間 vs TV・ラジオ等時間\n(N=47都道府県, 総数)', fontsize=12, fontweight='bold') ax.legend(fontsize=7.5, ncol=2) ax.grid(alpha=0.3) plt.suptitle('生活時間の関係性:都道府県間散布図', fontsize=14, fontweight='bold', y=1.02) plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_U5_13_fig3_scatter.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig3 saved: 生活時間散布図") |
Fig3 saved: 生活時間散布図
df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。stats.linregress(x, y) — 単回帰の傾き・切片・r値・p値・標準誤差を返します。使わない値は _ で受け取り。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。12種類の生活時間変数を用いた主成分分析(PCA)により、47都道府県の生活時間パターンを2次元平面上に射影した。スコアプロット(左)で都道府県のクラスタ構造を、ローディングプロット(右)で各活動の主成分への寄与方向を確認する。
| 主成分 | 寄与率 | 正の方向(高い) | 負の方向(低い) | 解釈 |
|---|---|---|---|---|
| 第1主成分(PC1) | 33.8% | 仕事・通勤 | 家事・TV・休養 | 「就労志向 ↔ 家庭・余暇志向」軸 |
| 第2主成分(PC2) | 17.9% | 学習・趣味・育児・スポーツ | TV・睡眠 | 「積極的余暇 ↔ 受動的余暇」軸 |
| 累積寄与率 | 51.6%(2次元で半分強の情報を捕捉) | |||
PCAは多次元データを少数の主成分に要約する次元削減手法である。スコアプロット(観測値の分布)とローディングプロット(変数の寄与方向)を組み合わせた「バイプロット」で、データ構造を包括的に理解できる。
実装では StandardScaler で標準化を行ってから PCA を適用することが重要。単位や分散スケールが異なる変数を混在させる場合、標準化しないと分散の大きな変数が主成分を支配してしまう。
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import matplotlib.patches as mpatches from matplotlib.patches import FancyArrowPatch import warnings warnings.filterwarnings('ignore') from scipy import stats from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA plt.rcParams['font.family'] = 'Hiragino Sans' plt.rcParams['axes.unicode_minus'] = False plt.rcParams['figure.dpi'] = 150 import os FIG_DIR = 'html/figures' DATA_D = 'data/raw/SSDSE-D-2023.csv' os.makedirs(FIG_DIR, exist_ok=True) df = pd.read_csv(DATA_D, encoding='cp932', header=1) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。import pandas as pd など — 必要なライブラリをまとめて呼び出します。as pd は短い別名(alias)。matplotlib.use('Agg') — グラフを画面表示せずファイルに保存するためのおまじない。plt.rcParams['font.family'] — グラフの日本語表示用フォント指定(Macは Hiragino Sans、Windowsなら Yu Gothic 等)。os.makedirs('html/figures', exist_ok=True) — 図の保存先フォルダを作る(既にあってもOK)。pd.read_csv(...) でCSVを読み込みます。encoding='cp932' は日本語Windows由来の文字コード、header=1 は「2行目を列名として使う」。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。f"...{x}..." はf-string。文字列の中に {変数} と書くだけで埋め込めて、{x:.2f} のように書式も指定できます。144 145 146 147 148 149 150 151 152 | # 都道府県別(全国計 R00000 を除く) total = df[(df['男女の別'] == '0_総数') & (df['地域コード'] != 'R00000')].copy() male = df[(df['男女の別'] == '1_男') & (df['地域コード'] != 'R00000')].copy() female= df[(df['男女の別'] == '2_女') & (df['地域コード'] != 'R00000')].copy() # 全国計 nat_total = df[(df['男女の別'] == '0_総数') & (df['地域コード'] == 'R00000')].iloc[0] nat_male = df[(df['男女の別'] == '1_男') & (df['地域コード'] == 'R00000')].iloc[0] nat_female = df[(df['男女の別'] == '2_女') & (df['地域コード'] == 'R00000')].iloc[0] |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df['A'] / df['B'] — pandasの列同士の四則演算は要素ごと(element-wise)。forループ不要なのが強み。153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | # 地域ブロック分類 region_map = { '北海道': '北海道・東北', '青森県': '北海道・東北', '岩手県': '北海道・東北', '宮城県': '北海道・東北', '秋田県': '北海道・東北', '山形県': '北海道・東北', '福島県': '北海道・東北', '茨城県': '関東', '栃木県': '関東', '群馬県': '関東', '埼玉県': '関東', '千葉県': '関東', '東京都': '関東', '神奈川県': '関東', '新潟県': '中部', '富山県': '中部', '石川県': '中部', '福井県': '中部', '山梨県': '中部', '長野県': '中部', '岐阜県': '中部', '静岡県': '中部', '愛知県': '中部', '三重県': '近畿', '滋賀県': '近畿', '京都府': '近畿', '大阪府': '近畿', '兵庫県': '近畿', '奈良県': '近畿', '和歌山県': '近畿', '鳥取県': '中国・四国', '島根県': '中国・四国', '岡山県': '中国・四国', '広島県': '中国・四国', '山口県': '中国・四国', '徳島県': '中国・四国', '香川県': '中国・四国', '愛媛県': '中国・四国', '高知県': '中国・四国', '福岡県': '九州・沖縄', '佐賀県': '九州・沖縄', '長崎県': '九州・沖縄', '熊本県': '九州・沖縄', '大分県': '九州・沖縄', '宮崎県': '九州・沖縄', '鹿児島県': '九州・沖縄', '沖縄県': '九州・沖縄', } region_colors = { '北海道・東北': '#4e9af1', '関東': '#e05c5c', '中部': '#f0a500', '近畿': '#5cb85c', '中国・四国': '#9b59b6', '九州・沖縄': '#f39c12', } total['地域'] = total['都道府県'].map(region_map) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。.map() は「1対1の置き換え」、.apply() は「関数を当てる」。辞書なら .map()、ロジックなら .apply()。176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | pca_cols = ['睡眠', '仕事', '家事', '育児', '通勤・通学', 'テレビ・ラジオ・新聞・雑誌', '休養・くつろぎ', '趣味・娯楽', 'スポーツ', '買い物', '学習・自己啓発・訓練(学業以外)', '交際・付き合い'] pca_label_map = { '睡眠': '睡眠', '仕事': '仕事', '家事': '家事', '育児': '育児', '通勤・通学': '通勤', 'テレビ・ラジオ・新聞・雑誌': 'TV等', '休養・くつろぎ': '休養', '趣味・娯楽': '趣味', 'スポーツ': 'スポーツ', '買い物': '買い物', '学習・自己啓発・訓練(学業以外)': '学習', '交際・付き合い': '交際', } df_pca = total[['都道府県', '地域'] + pca_cols].dropna().copy() X_raw = df_pca[pca_cols].values scaler = StandardScaler() X_scaled = scaler.fit_transform(X_raw) pca = PCA(n_components=2, random_state=42) scores = pca.fit_transform(X_scaled) loadings = pca.components_ # shape (2, n_features) explained = pca.explained_variance_ratio_ df_pca['PC1'] = scores[:, 0] df_pca['PC2'] = scores[:, 1] fig, axes = plt.subplots(1, 2, figsize=(14, 6)) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。fig, ax = plt.subplots(...) — 図全体(fig)と軸(ax)を作る定番。以降は ax.bar(...) 等で操作。StandardScaler().fit_transform(X) — 各列を「平均0・分散1」に標準化。単位が違う変数のβを比較可能に。r, p = stats.pearsonr(...) — Pythonは複数戻り値を同時に受け取れる(タプルアンパック)。200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | # 左: スコアプロット ax = axes[0] for reg, grp in df_pca.groupby('地域'): ax.scatter(grp['PC1'], grp['PC2'], color=region_colors.get(reg, 'gray'), label=reg, s=60, alpha=0.85) for _, row in df_pca.iterrows(): ax.annotate(row['都道府県'][:2], (row['PC1'], row['PC2']), fontsize=6.5, alpha=0.75, xytext=(2, 2), textcoords='offset points') ax.axhline(0, color='gray', linewidth=0.7, linestyle='--') ax.axvline(0, color='gray', linewidth=0.7, linestyle='--') ax.set_xlabel(f'第1主成分(寄与率 {explained[0]*100:.1f}%)', fontsize=11) ax.set_ylabel(f'第2主成分(寄与率 {explained[1]*100:.1f}%)', fontsize=11) ax.set_title('PCAスコアプロット\n(都道府県の生活時間パターン)', fontsize=12, fontweight='bold') ax.legend(fontsize=8, ncol=2) ax.grid(alpha=0.3) |
print はしません。データや図が裏で更新されただけ。次のステップへ進みましょう。df.groupby('列').apply(関数) — グループごとに関数を適用。時系列や地域別の集計でよく使います。ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。for _, row in df.iterrows() — DataFrameを1行ずつ取り出すループ。1点ずつ描画したいときに使用。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | # 右: ローディングプロット(バイプロット補助) ax = axes[1] scale = 3.0 for i, col in enumerate(pca_cols): lx, ly = loadings[0, i] * scale, loadings[1, i] * scale ax.arrow(0, 0, lx, ly, head_width=0.06, head_length=0.05, fc='#1565C0', ec='#1565C0', alpha=0.8) ax.text(lx * 1.12, ly * 1.12, pca_label_map[col], fontsize=9, ha='center', va='center', color='#0D47A1', fontweight='bold') ax.axhline(0, color='gray', linewidth=0.7, linestyle='--') ax.axvline(0, color='gray', linewidth=0.7, linestyle='--') ax.set_xlim(-scale * 0.7, scale * 0.7) ax.set_ylim(-scale * 0.7, scale * 0.7) ax.set_xlabel(f'第1主成分(寄与率 {explained[0]*100:.1f}%)', fontsize=11) ax.set_ylabel(f'第2主成分(寄与率 {explained[1]*100:.1f}%)', fontsize=11) ax.set_title('PCAローディングプロット\n(各活動が主成分に与える方向)', fontsize=12, fontweight='bold') ax.grid(alpha=0.3) plt.suptitle('主成分分析(PCA)による生活時間パターンの可視化', fontsize=14, fontweight='bold', y=1.02) plt.tight_layout() plt.savefig(os.path.join(FIG_DIR, '2022_U5_13_fig4_pca.png'), dpi=150, bbox_inches='tight') plt.close() print("Fig4 saved: PCA分析") |
Fig4 saved: PCA分析
ax.axhline / ax.axvline — 水平/垂直の点線。平均線や基準線として定番。fig.savefig(..., bbox_inches='tight') — 余白を自動で詰めて保存。plt.close() でメモリ解放。df[col](1列)と df[[col1, col2]](複数列)でカッコの数が違います。リストを渡していると覚えるとミスを減らせます。238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | print("\n========== 分析結果サマリー ==========") print(f"対象都道府県数: {len(total)}") print(f"\n【全国計 生活時間 (分/週)】") for c in ['睡眠', '仕事', '家事', '趣味・娯楽', 'テレビ・ラジオ・新聞・雑誌']: m, f = nat_male[c], nat_female[c] print(f" {c:20s}: 男={m:4.0f}, 女={f:4.0f}, 差={m-f:+.0f}") print(f"\n【仕事時間 最長上位5県】") print(total.nlargest(5, '仕事')[['都道府県', '仕事', '趣味・娯楽', '家事']].to_string(index=False)) print(f"\n【仕事時間 最短下位5県】") print(total.nsmallest(5, '仕事')[['都道府県', '仕事', '趣味・娯楽', '家事']].to_string(index=False)) x_corr = total['仕事'].values y_corr = total['趣味・娯楽'].values r_corr, p_corr = stats.pearsonr(x_corr, y_corr) print(f"\n【仕事時間 vs 趣味・娯楽時間】r={r_corr:.3f}, p={p_corr:.3f}") print(f"\n【PCA寄与率】PC1={explained[0]*100:.1f}%, PC2={explained[1]*100:.1f}%") print(f" 累積寄与率: {(explained[0]+explained[1])*100:.1f}%") print("\nAll figures saved to:", FIG_DIR) print("Done!") |
========== 分析結果サマリー ========== 対象都道府県数: 47 【全国計 生活時間 (分/週)】 睡眠 : 男= 478, 女= 469, 差=+9 仕事 : 男= 267, 女= 152, 差=+115 家事 : 男= 25, 女= 146, 差=-121 趣味・娯楽 : 男= 60, 女= 37, 差=+23 テレビ・ラジオ・新聞・雑誌 : 男= 131, 女= 125, 差=+6 【仕事時間 最長上位5県】 都道府県 仕事 趣味・娯楽 家事 島根県 227 38 84 富山県 224 42 84 石川県 224 49 79 福井県 223 40 88 佐賀県 223 41 83 【仕事時間 最短下位5県】 都道府県 仕事 趣味・娯楽 家事 京都府 186 44 94 奈良県 189 50 100 山口県 193 46 92 和歌山県 198 42 95 愛媛県 198 48 93 【仕事時間 vs 趣味・娯楽時間】r=-0.295, p=0.044 【PCA寄与率】PC1=33.8%, PC2=17.9% 累積寄与率: 51.6% All figures saved to: html/figures Done!
stats.pearsonr(x, y) — Pearson相関係数 r と p値を同時に返します。x if cond else y は三項演算子。リスト内包表記と組み合わせると、forとifを1行で書けます。SSDSE-D(社会生活基本調査 都道府県別生活時間)を用いた分析から、以下の知見が得られた。
| 項目 | 内容・出典 |
|---|---|
| 使用データ | SSDSE-D-2023.csv(社会生活基本調査 都道府県別生活時間) |
| データ出典 | 統計数理研究所 SSDSE / 総務省統計局 社会生活基本調査(2021年実施) |
| 分析手法 | 記述統計、Pearson相関分析、主成分分析(PCA) |
| 使用ライブラリ | pandas, numpy, matplotlib, scipy, scikit-learn |
| 生成図表 |
fig1: 都道府県別生活時間配分 積み上げ棒グラフ fig2: 生活時間の男女差(全国計) fig3: 生活時間変数間の散布図(仕事vs趣味、家事vsTV) fig4: PCAスコアプロット & ローディングプロット |
本コードは SSDSE-D-2023.csv の実データを使用。合成データ・乱数生成は一切使用していない。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。