この教材は原論文と同じデータを読み込み、同じ手順で計算し直しています。画面に出る数値と図は、あなたのブラウザがその場で計算した結果です。
⚠ ただし一部は再現していません:図4 は社会生活基本調査に基づく原論文の報告値(表4)の可視化です。 当該指標は SSDSE 未収録のため再計算していません。
| 原論文が使ったデータ | SSDSE-D・社会生活基本調査・県民経済計算・国勢調査 分析単位:都道府県 中核手法:相関分析・重回帰分析 |
|---|---|
| この教材が使うデータ |
|
| 原論文(PDF) | 日本におけるワークライフバランスの達成状況とその課題 総務大臣賞/村澤 舞・山家 里穂(広島大学附属高等学校) |
▶ ここに書いてある分析は、ページ下部の「🐍 ブラウザで動かす」でそのまま実行できます(インストール不要)。動かしているのは code/2021_H1_daijin.py(192 行)そのものです。
このページの図1〜3は SSDSE-D(生活時間・行動者率の教育用標準データセット)で実際に再現できます。コードの編集は不要です。
data/raw/ フォルダに入れます。html/figures/ に自動保存されます。
政府は2007年に「仕事と生活の調和(ワーク・ライフ・バランス)憲章」を策定し、国を挙げてワークライフバランス(WLB)を推進してきた。一方で「日本人は働き過ぎ」という批判は根強く、過労死や学校教員の部活動負担なども問題化している。本研究は、身近な問題意識(父母の仕事量、教員の残業)を出発点に、日本のWLBがどの程度達成され、その課題は何かを、公的統計を用いて検討する。
基本統計量 相関分析 偏相関分析 重回帰分析 男女比較
受賞区分・著者・所属は原論文1頁目の表記に従う(総務大臣賞[高校生の部]/村澤 舞・山家 里穂/広島大学附属高等学校)。
原論文が使用したデータと出典は次のとおり(原論文・表1)。「ワーク」は仕事・家事・育児の時間、それ以外を「ライフ」と定義している。
| データ | おもな変数 | 年度 | 出典 |
|---|---|---|---|
| SSDSE-D | 仕事(有業者・週全体)の総平均時間、趣味・娯楽/旅行・行楽の行動者率 | 2016 | 社会生活基本調査ベース |
| 社会生活基本調査 | 平日・正規職員の男女別 活動時間(仕事・睡眠・家事・育児・テレビ・休養・趣味 ほか) | 2016 | 総務省 |
| 県民経済計算 | 1人当たり県民所得 | 2016 | 内閣府 |
| 国勢調査 | 総人口・女性人口割合・労働可能人口割合・第三次産業人口割合・職業別割合 | 2015 | 総務省 |
総平均時間は対象者全員(行動しなかった人の0分も含む)の平均。行動者率は「過去1年間にその行動をした人の割合(%)」。原論文はワークを「時間」、ライフの一部を「行動者率」で捉えている。指標の性質が違うので、比較や解釈のときはどちらの数字かを常に意識する。
まず分析に必要なライブラリと入力データを準備する。理由は、以降のすべてのステップが読み込んだ表(DataFrame)を土台に進むからである。ここでは SSDSE-D を読み込み、都道府県×男女別に整える。
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | import os import numpy as np import pandas as pd import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from matplotlib.patches import Patch from scipy import stats plt.rcParams['font.family'] = 'Hiragino Sans' plt.rcParams['axes.unicode_minus'] = False plt.rcParams['figure.dpi'] = 150 FIG_DIR = 'html/figures' DATA_D = 'data/raw/SSDSE-D-2023.csv' os.makedirs(FIG_DIR, exist_ok=True) |
FIG_DIR(図の保存先)と DATA_D(SSDSE-D のパス)を決め、フォルダを用意しただけです。encoding='cp932' は日本語Windows由来の文字コード指定。次のステップでCSVを読むときに使います。matplotlib.use('Agg') は画面を持たない環境でも図をファイル保存できるようにする指定です。つづいてCSVを読み込み、47都道府県×男女別に切り分ける。SSDSE-D は1行目がデータセットID、2行目が日本語の列名なので header=1 で読む。
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | # ─── データ読み込み(SSDSE-D)─────────────────────────────────── # 先頭行はデータセットID、2行目が日本語の列名なので header=1 で読む。 df_d = pd.read_csv(DATA_D, encoding='cp932', header=1) df_d = df_d[df_d['都道府県'] != '全国'].copy() # 全国行を除き47都道府県に # 男女の別で3つに分割(0_総数 / 1_男 / 2_女) tot = df_d[df_d['男女の別'] == '0_総数'].reset_index(drop=True) men = df_d[df_d['男女の別'] == '1_男'].reset_index(drop=True) wom = df_d[df_d['男女の別'] == '2_女'].reset_index(drop=True) assert len(tot) == len(men) == len(wom) == 47, "都道府県数が47ではありません" # 使う列(仕事=総平均時間・分、趣味娯楽/旅行行楽=行動者率・%、人口=推定人口) WORK = '仕事' HOBBY = '趣味・娯楽の総数' TRIP = '旅行・行楽の総数' POP = '推定人口(10歳以上)' |
df_d['都道府県'] != '全国' で全国集計行を除外し、都道府県だけにします。男女の別列(0_総数/1_男/2_女)で3つのDataFrameに分け、assert で各47件をチェック。ここで落ちなければデータ形状は想定どおりです。.reset_index(drop=True) は行番号を0から振り直し、後で男女を突き合わせるときのズレを防ぎます。まず「ワーク」の代表指標である仕事時間の分布を、基本統計量と箱ひげ図・棒グラフで確認する。分布の中心とばらつき、男女差、地域差を先に押さえておくと、後の相関・回帰の解釈が正確になる。
69 70 71 72 73 74 75 76 77 78 79 80 | # ─── 基本統計量(ワークの男女差)───────────────────────────────── print('=== 仕事時間(総平均・分)の平均値 ===') print(f"男性 {men[WORK].mean():.1f}") print(f"女性 {wom[WORK].mean():.1f}") print(f"総数 {tot[WORK].mean():.1f}") print(f"男女差 {men[WORK].mean() - wom[WORK].mean():.1f} 分") # 都道府県別(総数)の最長・最短 i_max, i_min = tot[WORK].idxmax(), tot[WORK].idxmin() print(f"\n最長: {tot.loc[i_max, '都道府県']} {tot.loc[i_max, WORK]}分 / " f"最短: {tot.loc[i_min, '都道府県']} {tot.loc[i_min, WORK]}分 / " f"差 {tot[WORK].max() - tot[WORK].min()}分") |
=== 仕事時間(総平均・分)の平均値 === 男性 266.0 女性 155.2 総数 208.9 男女差 110.8 分 最長: 島根県 227分 / 最短: 京都府 186分 / 差 41分
つぎに都道府県ごとの仕事時間を並べて地域差を見る。棒グラフにすると、どの県が長く・短いかが一目で分かる。
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | # ─── 図1: 仕事時間の箱ひげ図(男女別)───────────────────────────── fig1, ax1 = plt.subplots(figsize=(8, 6)) box = ax1.boxplot( [men[WORK], tot[WORK], wom[WORK]], tick_labels=['男性のみ', '男女の総数', '女性のみ'], patch_artist=True, widths=0.55, showmeans=True, meanprops=dict(marker='D', markerfacecolor='white', markeredgecolor='#333', markersize=7), ) for patch, c in zip(box['boxes'], ['#4e9af1', '#9e9e9e', '#e05c5c']): patch.set_facecolor(c); patch.set_alpha(0.75) for med in box['medians']: med.set_color('#212121'); med.set_linewidth(1.5) ax1.set_ylabel('仕事時間(総平均・分/週全体)', fontsize=12) ax1.set_title('図1: 仕事時間の箱ひげ図(男女別・47都道府県)\nSSDSE-D-2023(2021年調査)で再現', fontsize=12, pad=10) ax1.grid(axis='y', alpha=0.3) fig1.tight_layout() fig1.savefig(os.path.join(FIG_DIR, '2021_H1_fig1.png'), bbox_inches='tight') plt.close(fig1) print('\nfig1 saved') |
fig1 saved
ax.boxplot([...], patch_artist=True) で3群の箱ひげ図を作り、set_facecolor で色分けしています。html/figures/2021_H1_fig1.png に保存され、上の図1として表示されています。showmeans=True と meanprops で平均値の菱形マーカーを追加できます。
137 138 139 140 141 142 143 144 145 146 147 148 149 150 | # ─── 図3: 都道府県別の仕事時間(総数)棒グラフ ───────────────────── tot_sorted = tot.sort_values(WORK).reset_index(drop=True) fig3, ax3 = plt.subplots(figsize=(13, 5)) bars = ax3.bar(range(len(tot_sorted)), tot_sorted[WORK], color='#4e9af1', alpha=0.85, edgecolor='white') ax3.set_xticks(range(len(tot_sorted))) ax3.set_xticklabels(tot_sorted['都道府県'], rotation=90, fontsize=7.5) ax3.set_ylabel('仕事時間(総平均・分)', fontsize=11) ax3.set_ylim(tot_sorted[WORK].min() - 15, tot_sorted[WORK].max() + 8) ax3.set_title('図3: 都道府県別の仕事時間(男女の総数・SSDSE-D-2023)', fontsize=12, pad=8) ax3.grid(axis='y', alpha=0.3) fig3.tight_layout() fig3.savefig(os.path.join(FIG_DIR, '2021_H1_fig3.png'), bbox_inches='tight') plt.close(fig3) print('fig3 saved') |
fig3 saved
sort_values(WORK) で仕事時間の昇順に並べ替えてから ax.bar で描画。左が短く右が長い県です。rotation=90 で県名ラベルを縦にすると47件でも重なりません。仕事時間(ワーク)が長い県ほど、余暇(ライフ)は削られるのか。ここでは相関分析で、仕事時間と「趣味・娯楽」「旅行・行楽」の行動者率の関係を男女別に確かめる。散布図と相関係数を併用して、向き(正/負)と強さ、そして男女差を読む。
82 83 84 85 86 87 88 89 | # ─── 相関分析(ワークとライフ・人口)───────────────────────────── print('\n=== 相関係数(仕事時間 × 各指標)===') for lab, d in [('男性', men), ('女性', wom)]: r_h, p_h = stats.pearsonr(d[WORK], d[HOBBY]) r_t, p_t = stats.pearsonr(d[WORK], d[TRIP]) r_p, p_p = stats.pearsonr(d[WORK], d[POP]) print(f"{lab}: 趣味娯楽 r={r_h:+.3f}(p={p_h:.3f}) / " f"旅行行楽 r={r_t:+.3f}(p={p_t:.3f}) / 人口 r={r_p:+.3f}(p={p_p:.3f})") |
=== 相関係数(仕事時間 × 各指標)=== 男性: 趣味娯楽 r=+0.156(p=0.295) / 旅行行楽 r=+0.170(p=0.252) / 人口 r=+0.098(p=0.514) 女性: 趣味娯楽 r=-0.416(p=0.004) / 旅行行楽 r=-0.457(p=0.001) / 人口 r=-0.249(p=0.092)
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | # ─── 図2: 仕事時間 × 余暇行動者率の散布図(男女別・2枚)────────────── fig2, (axL, axR) = plt.subplots(1, 2, figsize=(13, 5.6)) for ax, ycol, ylabel, title in [ (axL, HOBBY, '趣味・娯楽(総数)の行動者率(%)', '図2a: 仕事時間 × 趣味・娯楽'), (axR, TRIP, '旅行・行楽(総数)の行動者率(%)', '図2b: 仕事時間 × 旅行・行楽'), ]: for d, c, lab in [(men, '#4e9af1', '男性のみ'), (wom, '#e05c5c', '女性のみ')]: ax.scatter(d[WORK], d[ycol], c=c, s=45, alpha=0.8, label=lab, zorder=3) r, _ = stats.pearsonr(d[WORK], d[ycol]) # 回帰線 s, b, *_ = stats.linregress(d[WORK], d[ycol]) xs = np.linspace(d[WORK].min(), d[WORK].max(), 50) ax.plot(xs, s * xs + b, c=c, lw=1.3, ls='--', zorder=2) ax.annotate(f'{lab} r={r:+.3f}', (0.04, 0.10 if lab == '女性のみ' else 0.03), xycoords='axes fraction', color=c, fontsize=10, fontweight='bold') ax.set_xlabel('仕事時間(総平均・分)', fontsize=11) ax.set_ylabel(ylabel, fontsize=11) ax.set_title(title, fontsize=12, pad=8) ax.legend(fontsize=9, loc='upper right', framealpha=0.9) ax.grid(True, alpha=0.3) fig2.suptitle('SSDSE-D-2023(2021年調査)で再現:女性ほど仕事時間と余暇行動者率が負に相関', fontsize=12, y=1.02) fig2.tight_layout() fig2.savefig(os.path.join(FIG_DIR, '2021_H1_fig2.png'), bbox_inches='tight') plt.close(fig2) print('fig2 saved') |
fig2 saved
plt.subplots(1, 2) で作り、男女それぞれに scatter+回帰線(linregress)を重ねています。annotate で図中に表示。出力は「fig2 saved」のみで、結果は上の図2に反映されます。stats.linregress は傾き・切片・r・p・標準誤差を返します。回帰線は slope*x+intercept で引けます。原論文はここから社会生活基本調査(平日・正規職員)の細かいデータに切り替える。これは SSDSE に収録されていないため、以下は原論文の報告値である(本ページでは再計算していない)。
| 指標 | 男性 | 女性 |
|---|---|---|
| 平均 | 547.2 分 | 460.8 分 |
| 中央値 | 548 分 | 458 分 |
| 最頻値 | 550 分 | 458 分 |
| 標準偏差 | 17.9 | 16.8 |
| データ数 | 47 | 47 |
原論文は、女性に負担が偏りやすい育児・家事・介護を取り出して分析した(原論文 図12・13)。グラフによれば、伝統的に女性の役割とされる育児・家事の時間は、女性が男性を大きく上回る。グラフは原論文参照。
女性について、育児時間とライフ(3次活動)の単純な相関は統計的に有意ではない(原論文の報告値 r=−0.193, 家事は r=0.051)。しかし「仕事時間」を交絡変数として統制した偏相関係数は −0.499となり、鮮明な負の関係が現れた。つまり仕事時間が同じなら、育児とライフはトレードオフになる。この交絡の発見が本論文の大きな特徴である。
2変数XとYの相関が弱く見えても、両方に効く第三の変数Zがあると本当の関係が隠れる(見かけの無相関)。偏相関はZを一定にそろえた条件での X–Y 相関で、Zの影響を取り除く。ここでは X=育児、Y=ライフ、Z=仕事時間。Zを統制すると −0.499 の負相関が出現した。
これらの散布図(原論文 図7〜16)は社会生活基本調査の個票集計に基づき、SSDSEでは再現できないため数値は原論文の報告値。グラフは原論文参照。
最後に原論文は、何が仕事時間(平日・雇用されている人)を決めるのかを重回帰分析(最小二乗法)で探索した。従属変数は仕事時間、説明変数は1人当たり県民所得・総人口・女子人口割合・労働可能人口割合・第三次産業人口割合・職業別割合(管理/専門技術/事務/販売/サービス)。以下は原論文・表4の報告値である。
| 説明変数 | 係数 | P値 | 判定 |
|---|---|---|---|
| 15〜64歳人口割合(労働可能人口) | +5.471 | .003 | 有意(正) |
| 第三次産業人口割合 | −2.848 | .002 | 有意(負) |
| 販売職割合 | +8.442 | .012 | 有意(正) |
| 1人当たり県民所得 | −0.014 | .305 | 非有意 |
| 女子人口割合 | +1.183 | .752 | 非有意 |
| 管理職割合 | +17.826 | .152 | 非有意 |
| 専門技術職割合 | +3.086 | .099 | 非有意 |
| 事務職割合 | −3.387 | .263 | 非有意 |
| サービス職割合 | −1.173 | — | 非有意 |
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | # ─── 図4: 【報告値の可視化】社会生活基本調査の重回帰係数(原論文・表4)── # 以下は SSDSE には収録されていない社会生活基本調査ベースの重回帰分析の # 「報告値」である。再計算ではなく、原論文・表4の係数をそのまま描画する。 report_vars = ['1人当たり県民所得', '総人口', '女子人口割合', '15〜64歳人口割合', '第三次産業人口割合', '管理職割合', '専門技術職割合', '事務職割合', '販売職割合', 'サービス職割合'] report_coef = [-0.014, 0.000, 1.183, 5.471, -2.848, 17.826, 3.086, -3.387, 8.442, -1.173] report_sig = [False, False, False, True, True, False, False, False, True, False] # p<0.05 order = np.argsort(report_coef) rv = [report_vars[i] for i in order] rc = [report_coef[i] for i in order] rs = [report_sig[i] for i in order] colors = ['#e05c5c' if c > 0 else '#4e9af1' for c in rc] fig4, ax4 = plt.subplots(figsize=(9, 5.5)) bars4 = ax4.barh(range(len(rv)), rc, color=colors, alpha=0.85, edgecolor='white') for i, (c, sig) in enumerate(zip(rc, rs)): if sig: bars4[i].set_edgecolor('#B8860B'); bars4[i].set_linewidth(2.2) ax4.text(c + (0.3 if c >= 0 else -0.3), i, f'{c:+.3f}' + ('*' if sig else ''), va='center', ha='left' if c >= 0 else 'right', fontsize=9, color='#B8860B' if sig else '#555', fontweight='bold' if sig else 'normal') ax4.axvline(0, color='#333', lw=0.8) ax4.set_yticks(range(len(rv))) ax4.set_yticklabels(rv, fontsize=10) ax4.set_xlabel('回帰係数(仕事時間を従属変数)', fontsize=11) ax4.set_title('図4【報告値の可視化】社会生活基本調査による重回帰係数\n' '(原論文・表4の報告値。SSDSE未収録のため再計算ではない)', fontsize=11.5, pad=10) ax4.text(0.98, 0.03, '重決定R²=0.628 / 補正R²=0.525 / n=47 *p<0.05', transform=ax4.transAxes, ha='right', va='bottom', fontsize=9, color='#555') ax4.set_xlim(min(rc) - 4, max(rc) + 6) fig4.tight_layout() fig4.savefig(os.path.join(FIG_DIR, '2021_H1_fig4.png'), bbox_inches='tight') plt.close(fig4) print('fig4 saved') |
fig4 saved
本研究は、生活時間を男女別に分けることで日本のワークライフバランスの達成状況を検討した。
統計分析の解釈で初心者がやりがちな勘違いをまとめます。特に「相関と因果の混同」「p値の過信」は研究現場でもよく起きる落とし穴です。本文を読む前にも、読んだ後にも、目を通してみてください。
統計の基本用語を初心者向けに解説します。本文中で見慣れない言葉が出てきたら、ここに戻って確認してください。
統計手法について「何のためか」「結果をどう読むか」を初心者向けに解説します。
この研究をさらに発展させるための3つの方向性を示します。「今回わかったこと(X)」から「次に検証すべき仮説(Y)」を立て、「具体的に何をするか(Z)」まで考えてみましょう。
学んだだけでは身につきません。実際に手を動かすのが最強の学習方法です。本論文のスクリプトをベースに、以下のチャレンジに挑戦してみてください。難易度別に5つ用意しました。
本論文で学んだ手法は、研究の世界だけでなく、行政・企業・NPO の現場でも様々に活用されています。具体的なシーンを紹介します。
この論文を読んで初心者が抱きやすい疑問に、教育的観点から答えます。
この論文を理解できたか、クリックで確認しましょう。間違えても解説が出ます。
このページの分析は、この画面の中でそのまま実行できます。
Python をインストールする必要も、CSV をダウンロードする必要もありません。
下のセルの 「▶ ブラウザで実行」 を上から順に押すか、
「▶ 最初から全部実行」 で一気に流してください。
表示されるのは、本文の図表とまったく同じ計算の結果です
(動かしているのは再現スクリプト code/2021_H1_daijin.py そのもの)。
コードは書き換えられます。「✏️ 書き換える」で数字や変数を変えて ▶ を押すと、 結果がどう変わるかをその場で確かめられます(元に戻すボタンつき)。 ページを開いた時点で裏で実行環境の準備が始まっているので、待ち時間はほとんどありません。 初回だけ実行環境の取得にインターネット接続が必要です。