PHPで人口を推計する

(1/1)
2012年2月、国立社会保障・人口問題研究所が日本の将来推計人口を計算し直し、2060年には65歳以上が4割に達するとして話題になった。この推計は妥当性があるのだろうか。
そこで今回は、PHPを使って人口の推計を行うシミュレーション・プログラムを作ってみることにする。

(2025年6月7日)コロナ禍以降出生率が急減していることから,出生率が毎年3%ずつ減少,0.7で一定とするシナリオを追加
(2025年1月19日)データを2023年版に更新,PHP8.4対応

サンプル・プログラムの実行例

日本の人口推計

目次

サンプル・プログラム

圧縮ファイルの内容
population.phpサンプル・プログラム本体。
pahooInputData.phpデータ入力に関わる関数群。
使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。
population2011.csv統計データ 2011年版
population2017.csv統計データ 2017年版
population2018.csv統計データ 2018年版
population2019.csv統計データ 2019年版
population2020.csv統計データ 2020年版
population2021.csv統計データ 2021年版
population2022.csv統計データ 2022年版
population2023.csv統計データ 2023年版
population.php 更新履歴
バージョン 更新日 内容
2.6.0 2025/06/07 calcFertilityRatio21()関数を追加
2.5.4 2025/01/19 データを2023年版に更新,PHP8.4対応
2.5.3 2023/12/20 データを2022年版に更新,pahooInputData導入
2.5.2 2023/05/05 グラフにフッタを追加
2.5.1 2023/02/12 データを2021年に更新
pahooInputData.php 更新履歴
バージョン 更新日 内容
1.8.1 2025/03/15 validRegexPattern() -- debug
1.8.0 2024/11/12 validRegexPattern() 追加
1.7.0 2024/10/09 validURL() validEmail() 追加
1.6.0 2024/10/07 isButton() -- buttonタグに対応
1.5.0 2024/01/28 exitIfExceedVersion() 追加

解説:準備

グラフ描画には JpGraph を利用する。導入方法については、「PHPとJpGraphで人口ピラミッドを表示する」を参照のこと。

population.php

  66: // 元となるCSVデータファイル名
  67: // 人口・死亡率:2023年 https://www.stat.go.jp/data/nenkan/74nenkan/02.html
  68: // 出生率:2022年 https://www.ipss.go.jp/syoushika/tohkei/Popular/Popular2024.asp?chap=4
  69: define('FILE_DATA', './population2023.csv');
  70: 
  71: // 推計開始年(元データの年次)
  72: define('YEAR_START', 2021);

プログラム本体は "population.php"、初期値として使うデータが "population2023.csv" に入っている。同じディレクトリにおいて実行すること。

"population2023.csv" の各列の構造は以下の通り。いずれも2023年時点の値である。
  1. 年齢
  2. その年齢における男性の死亡率(千人あたり)
  3. その年齢における女性の死亡率(千人あたり)
  4. その年齢における出生率(女性一人あたり)
  5. その年齢における男性人口(千人)
  6. その年齢における女性人口(千人)
人口と死亡率については日本統計年鑑(総務省統計局)を参考にした。100歳超の死亡率は分からないので、適当に設定した。出生率については、人口統計資料集(国立社会保障・人口問題研究所)の「女性の年齢(各歳)別出生率」を採用した。

population.php

  90: // 従業者規模別民営事業所数(2016年)
  91: // http://www.stat.go.jp/data/nihon/07.html
  92: // num=事業所数, color=描画色
  93: $tableCompany = array(
  94: '1-4人'         => array('num'=>3047110,'color'=>'#006600'),
  95: '5-9人'         => array('num'=>1057293,'color'=>'#00AA00'),
  96: '10-19人'       => array('num'=>649836, 'color'=>'#00CC00'),
  97: '20-29人'       => array('num'=>232601, 'color'=>'#00FF00'),
  98: '30-49人'       => array('num'=>163074, 'color'=>'#00FF44'),
  99: '50-99人'       => array('num'=>100428, 'color'=>'#00FF88'),
 100: '100-199人'     => array('num'=>39002,  'color'=>'#00FFAA'),
 101: '200-299人'     => array('num'=>10454,  'color'=>'#00FFCC'),
 102: '300人以上'     => array('num'=>12223,  'color'=>'#00FFFF')
 103: );

生産年齢人口減少に伴う企業(事業所)数の減少を推計するため、従業者規模別民営事業所数は2016年度の数字を連想配列 $tableCompany に格納した。棒グラフで描くときの描画色もあわせて格納している。

解説:出生率

population.php

 207: /**
 208:  * 出生率の推計関数:推計開始年から一定
 209:  * @param   array $items 推計表
 210:  * @return  なし
 211: */
 212: function calcFertilityRatio1(&$items) {
 213:     global $MaxAge;
 214: 
 215:     for ($i = 1$i < PERIOD$i++) {
 216:         $year = YEAR_START + $i;
 217:         for ($age = 0$age <$MaxAge$age++) {
 218:             $items[$year][$age]['fertility'] = $items[$year - 1][$age]['fertility'];
 219:         }
 220:     }
 221: }

population.php

 223: /**
 224:  * 出生率の推計関数:毎年1%ずつ減少,0.9で一定
 225:  * @param   array $items 推計表
 226:  * @return  なし
 227: */
 228: function calcFertilityRatio2(&$items) {
 229:     global $MaxAge;
 230: 
 231:     $d = (-0.01);   // 毎年増分
 232:     $t2 = 0.9;      // 下限値
 233:     for ($i = 1$i < PERIOD$i++) {
 234:         $year = YEAR_START + $i;
 235:         $total = 0;
 236:         for ($age = 0$age <$MaxAge$age++) {
 237:             $items[$year][$age]['fertility'] = $items[$year - 1][$age]['fertility'* (1 + $d);
 238:             $total +$items[$year][$age]['fertility'];
 239:         }
 240:         if ($total <$t2)   $d = 0;
 241:     }
 242: }

population.php

 244: /**
 245:  * 出生率の推計関数:毎年3%ずつ減少,0.7で一定
 246:  * @param   array $items 推計表
 247:  * @return  なし
 248: */
 249: function calcFertilityRatio21(&$items) {
 250:     global $MaxAge;
 251: 
 252:     $d = (-0.03);   // 毎年増分
 253:     $t2 = 0.7;      // 下限値
 254:     for ($i = 1$i < PERIOD$i++) {
 255:         $year = YEAR_START + $i;
 256:         $total = 0;
 257:         for ($age = 0$age <$MaxAge$age++) {
 258:             $items[$year][$age]['fertility'] = $items[$year - 1][$age]['fertility'* (1 + $d);
 259:             $total +$items[$year][$age]['fertility'];
 260:         }
 261:         if ($total <$t2)   $d = 0;
 262:     }
 263: }

population.php

 265: /**
 266:  * 出生率の推計関数:毎年1%ずつ増加,1.8で一定
 267:  * @param   array $items 推計表
 268:  * @return  なし
 269: */
 270: function calcFertilityRatio3(&$items) {
 271:     global $MaxAge;
 272: 
 273:     $d  = 0.01;     // 毎年増分
 274:     $t1 = 1.8;      // 上限値
 275:     for ($i = 1$i < PERIOD$i++) {
 276:         $year = YEAR_START + $i;
 277:         $total = 0;
 278:         for ($age = 0$age <$MaxAge$age++) {
 279:             $items[$year][$age]['fertility'] = $items[$year - 1][$age]['fertility'* (1 + $d);
 280:             $total +$items[$year][$age]['fertility'];
 281:         }
 282:         if ($total >$t1)  $d = 0;
 283:     }
 284: }

population.php

 286: /**
 287:  * 出生率の推計関数:0.9と1.8の間で増減
 288:  * @param   array $items 推計表
 289:  * @return  なし
 290: */
 291: function calcFertilityRatio4(&$items) {
 292:     global $MaxAge;
 293: 
 294:     $sign = (-1);   // 増減符号
 295:     $d  = 0.01;     // 毎年増分
 296:     $t1 = 1.8;      // 上限値
 297:     $t2 = 0.9;      // 下限値
 298:     for ($i = 1$i < PERIOD$i++) {
 299:         $year = YEAR_START + $i;
 300:         $total = 0;
 301:         for ($age = 0$age <$MaxAge$age++) {
 302:             $items[$year][$age]['fertility'] = $items[$year - 1][$age]['fertility'* (1 + $d * $sign);
 303:             $total +$items[$year][$age]['fertility'];
 304:         }
 305:         if ($total >$t1)  $sign = (-1);
 306:         if ($total <$t2)   $sign = (+1);
 307:     }
 308: }

シミュレーションでは、出生率の推移を幾つか選択できるようになっている。出生率を推計表 $items に返す関数を用意し、グローバル変数 $SelectOption1 に設定してやれば選択できるようになる。

出生率の変動によって人口推計結果が大幅に変わるので、適宜関数を用意してみてほしい。

解説:死亡率

population.php

 321: /**
 322:  * 死亡率の推計関数:推計開始年から一定
 323:  * @param   array $items 推計表
 324:  * @return  なし
 325: */
 326: function calcDeathRatio1(&$items) {
 327:     global $MaxAge;
 328: 
 329:     for ($i = 1$i < PERIOD$i++) {
 330:         $year = YEAR_START + $i;
 331:         for ($age = 0$age <$MaxAge$age++) {
 332:             $items[$year][$age]['death_male'] = $items[$year - 1][$age]['death_male'];
 333:             $items[$year][$age]['death_female'] = $items[$year - 1][$age]['death_female'];
 334:         }
 335:     }
 336: }

population.php

 338: /**
 339:  * 死亡率の推計関数:推計開始年から毎年4‰ずつ減少
 340:  * @param   array $items 推計表
 341:  * @return  なし
 342: */
 343: function calcDeathRatio2(&$items) {
 344:     global $MaxAge;
 345: 
 346:     $d = (-0.004);  // 毎年増分
 347:     for ($i = 1$i < PERIOD$i++) {
 348:         $year = YEAR_START + $i;
 349:         for ($age = 0$age <$MaxAge$age++) {
 350:             $items[$year][$age]['death_male'] = $items[$year - 1][$age]['death_male'* (1 + $d);
 351:             $items[$year][$age]['death_female'] = $items[$year - 1][$age]['death_female'* (1 + $d);
 352:         }
 353:     }
 354: }

population.php

 356: /**
 357:  * 死亡率の推計関数:推計開始年から毎年4‰ずつ減少
 358:  * @param   array $items 推計表
 359:  * @return  なし
 360: */
 361: function calcDeathRatio3(&$items) {
 362:     global $MaxAge;
 363: 
 364:     $d = (+0.004);  // 毎年増分
 365:     for ($i = 1$i < PERIOD$i++) {
 366:         $year = YEAR_START + $i;
 367:         for ($age = 0$age <$MaxAge$age++) {
 368:             $items[$year][$age]['death_male'] = $items[$year - 1][$age]['death_male'* (1 + $d);
 369:             $items[$year][$age]['death_female'] = $items[$year - 1][$age]['death_female'* (1 + $d);
 370:         }
 371:     }
 372: }

シミュレーションでは、死亡率の推移を幾つか選択できるようになっている。死亡率を推計表 $items に返す関数を用意し、グローバル変数 $SelectOption2 に設定してやれば選択できるようになる。

死亡率の変動によって人口推計結果が大幅に変わるので、適宜関数を用意してみてほしい。

解説:事業所数

population.php

 374: /**
 375:  * 事業所数の推計関数:推計開始年から生産年齢人口に応じて変化
 376:  * @param   array $items 推計表
 377:  * @return  なし
 378: */
 379: function calcCompany(&$items) {
 380:     global $tableCompany;
 381: 
 382:     // 初年度の生産年齢人口
 383:     $worker0 = 0;
 384:     for ($age = WORKER_AGE_MIN$age <WORKER_AGE_MAX$age++) {
 385:         $worker0 +$items[YEAR_START][$age]['male'+ $items[YEAR_START][$age]['female'];
 386:     }
 387: 
 388:     // 推計
 389:     for ($i = 0$i < PERIOD$i++) {
 390:         $year = YEAR_START + $i;
 391:         $worker = 0;
 392:         for ($age = WORKER_AGE_MIN$age <WORKER_AGE_MAX$age++) {
 393:             $worker +$items[$year][$age]['male'+ $items[$year][$age]['female'];
 394:         }
 395:         foreach ($tableCompany as $key=>$arr) {
 396:             $items[$year]['company'][$key] = $arr['num'* ($worker / $worker0);
 397:         }
 398:     }
 399: }

事業所数は、先に計算した生産年齢人口に比例して、 $tableCompany が減少していくという単純な推計式とした。

解説:人口推計

population.php

 401: /**
 402:  * 人口推計+事業所数推計
 403:  * @param   string $opt1 オプション1(出生率の推計関数名)
 404:  * @param   string $opt2 オプション2(死亡率の推計関数名)
 405:  * @param   string $opt3 オプション3(事業所数の推計関数名)
 406:  * @return  array 人口推計結果/FALSE:データファイルがないなど
 407: */
 408: function calcPopulation($opt1, $opt2, $opt3) {
 409:     global $MaxAge;
 410: 
 411:     $items = array();
 412: 
 413:     // 元となるデータファイルを読み込む
 414:     $infp = fopen(FILE_DATA, 'r');
 415:     if ($infp == FALSE)     return FALSE;
 416:     fgetcsv($infp, 9999, ',', '"', '\\');       // ラベル行をスキップ
 417:     while (! feof($infp)) {
 418:         $arr = fgetcsv($infp, 9999, ',', '"', '\\');
 419:         if ($arr == FALSE)  break;
 420:         if (! is_numeric($arr[1]))  continue;
 421:         $age = $arr[0];
 422:         $items[YEAR_START][$age]['death_male'] = $arr[1] / 1000;    // 年齢別死亡率(男性)
 423:         $items[YEAR_START][$age]['death_female'] = $arr[2] / 1000;  // 年齢別死亡率(女性)
 424:         $items[YEAR_START][$age]['fertility'] = $arr[3];    // 年齢別出生率
 425:         $items[YEAR_START][$age]['male']   = $arr[4] / 10;  // 男性人口(単位:万人)
 426:         $items[YEAR_START][$age]['female'] = $arr[5] / 10;  // 女性人口(単位:万人)
 427:     }
 428:     fclose($infp);
 429:     $MaxAge = $age;     // 最高齢
 430:     $opt1($items);      // 出生率の推計
 431:     $opt2($items);      // 死亡率の推計
 432: 
 433:     // 人口推計
 434:     for ($i = 1$i < PERIOD$i++) {
 435:         $year = YEAR_START + $i;
 436: 
 437:         // 0歳
 438:         $items[$year][0]['male'] = 0;
 439:         $items[$year][0]['female'] = 0;
 440:         for ($age = 0$age <$MaxAge$age++) {
 441:             $n = $items[$year - 1][$age]['female'* $items[$year - 1][$age]['fertility'];          // 出生数
 442:             $items[$year][0]['male']   += ($n / 2);
 443:             $items[$year][0]['female'+= ($n / 2);
 444:         }
 445: 
 446:         // 1歳~$MaxAge歳
 447:         for ($age = 1$age <$MaxAge$age++) {
 448:             $items[$year][$age]['male'] = $items[$year - 1][$age - 1]['male'* (1 - $items[$year][$age]['death_male']);
 449:             $items[$year][$age]['female'] = $items[$year - 1][$age - 1]['female'* (1 - $items[$year][$age]['death_female']);
 450:         }
 451:     }
 452:     $opt3($items);      // 事業所数の推計
 453: 
 454:     return $items;
 455: }

ユーザー関数 calcPopulation で人口推計を行い、結果を配列 $items に代入している。後続の関数は、この配列を表やグラフで出力しているだけである。

まず、冒頭で紹介した初期値データ・ファイル FILE_DATA を読み込む。そして、選択された関数により出生率と死亡率を計算し、推計表 $items に代入する。
次に、このデータを元に、毎年の年齢別人口を計算していく。
0歳人口は、年齢毎に前年の女性人口と出生率を乗算し、男女半数ずつに分けて代入する。
1歳以降の人口は、年齢毎に前年の男女別人口と男女別死亡率を乗算し、代入する。

考察

出生率が一定で、死亡率が毎年4‰減少(平均寿命が伸びる)する場合が、冒頭で紹介した国立社会保障・人口問題研究所の4割という値に近くなる。
ただ、国立社会保障・人口問題研究の推計では50年後の男性の平均寿命が84歳(現在79歳)、女性が91歳(現在86歳)となっており、いくらなんでも長生きし過ぎなのではないかと感じる。
そこで本プログラムでは、死亡率が毎年4‰増加(平均寿命が縮む)というオプションを用意してみた。この場合、50~100年後には高齢者比率が減少する。
本プログラムでは各年齢の死亡率が一律に減少/増加するような関数しか用意していないが、高齢者ほど死亡率が高くなるようにすると、高齢者比率の減少は早く訪れる。

出生率については、当たり前のことだが、いま急に増やすことができたとしても、その効果が現れるのは数十年後になる。死亡率や出生率を多少変化させたところで、40~50年後に高齢者割合が極大になる事態は避けられない。
むしろ出生率を急に増やすと、一時的に生産年齢人口が低下するため、現役世代への負担が重くなるという事態に陥る。
日本の人口推計
生産年齢人口比率は、すべてのシナリオで2050年から回復を見せるが、総人口が減少しているから、事業所数は減少し続ける。出生率が1.8なければ、急速に減少するから、わが国の将来の経済へのダメージが大きくなると推測できる。

余談

2012年2月現在、社会保障と税の一体改革が国会の主な議題になっている。年金財政の試算を示すかどうかで、政府と野党の間で駆け引きが行われているが、この推計を元に、自力で年金財政や医療保険財政のシミュレーションを行うのも面白いだろう。
年金財政は、基礎年金勘定、国民年金勘定、厚生年金勘定に加え、各共済組合などの帳簿があるので、計算はかなり複雑になる。基礎数値は「厚生労働省年金局 年金財政ホームページ」が参考になる。

簡単に試算したところでは、団塊ジュニアが65歳以上になる25年後から財政が急激に悪化することが確認できた。
ただ、このまま婚姻率が上がらないと、3号被保険者の数がそれほど増えない一方、出生率も極端に低下するだろうから、推計のブレ幅はかなり大きいと言える。

参考書籍

表紙 日本の中小企業
著者 関 満博
出版社 中央公論新社
サイズ 新書
発売日 2017年12月21日頃
価格 880円(税込)
ISBN 9784121024688
日本経済を支える数多くの中小企業。だが、近年は人口減少や、中国・アジアとの競争などがあり、かなり厳しい状態に追い込まれている。起業は減り、既存の企業も承継に苦しんでいる。なぜ、そのような事態に陥ってしまったのか? 今後の展望はあるのか? 経営学者が現場を徹底的に見て回り、課題と展望を論じる。
 

参考サイト

(この項おわり)
header