PHPで人口を推計する

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

(2023年12月20日)データを2022年版に更新,pahooInputData導入
(2023年5月5日)グラフにフッタを追加した。
(2023年2月12日)2021年の統計データに更新した。

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

日本の人口推計

目次

サンプル・プログラム

圧縮ファイルの内容
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年版
population.php 更新履歴
バージョン 更新日 内容
2.5.3 2023/12/20 データを2022年版に更新,pahooInputData導入
2.5.2 2023/05/05 グラフにフッタを追加
2.5.1 2023/02/12 データを2021年に更新
2.5 2022/11/01 データを2020年に更新
2.4 2021/04/23 データを2019年に更新
pahooInputData.php 関数/メソッド一覧
関数/メソッド 機能 詳細
exitIfLessVersion PHPが指定したバージョン未満ならメッセージを表示して強制終了する.
isCommandLine コマンドラインから起動されたかどうかを求める.
isButton HTML FORMで指定したボタンが押されたかどうかを求める. filter_input()関数および $argv を参照する.
getParam HTML FORMで指定したINPUTの内容を取り出す. filter_input()関数および $argv を参照する.
validNumber 数値バリデーションを行う. 数値が整数か小数かを指定し,最小値と最大値を指定する.
getValidNumber HTML FORMで指定したINPUTの内容を数値として取り出す(バリデーション付き) filter_input()関数および $argv を参照する.
validString 文字列バリデーションを行う. filter_input()関数および $argv を参照する.文字列の最小長,最大長,排除または受容するパターンを指定する.
getValidString HTML FORMで指定したINPUTの内容を文字列として取り出す(バリデーション付き) filter_input()関数および $argv を参照する.
getPasswordHash パスワード・ハッシュをつくる.
veryfyPassword パスワードがハッシュに合致するかどうかを求める.
roundFloat 小数を指定した桁数で丸めて文字列として返す。 与えた小数の有効桁数より指定桁数が多いときには,末尾に0をサプレスする.

解説:準備

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

  66: //元となるCSVデータファイル名
  67: //人口・死亡率:2021年 https://www.stat.go.jp/data/nenkan/72nenkan/02.html
  68: //出生率:2020年の中位値 https://www.ipss.go.jp/syoushika/tohkei/Popular/P_Detail2022.asp?fname=T04-09.htm
  69: define('FILE_DATA', './population2022.csv');
  70: 
  71: //推計開始年(元データの年次)
  72: define('YEAR_START', 2021);

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

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

  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 に格納した。棒グラフで描くときの描画色もあわせて格納している。

解説:出生率

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

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

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

 264: /**
 265:  * 出生率の推計関数:0.9と1.8の間で増減
 266:  * @param   array $items 推計表
 267:  * @return  なし
 268: */
 269: function calcFertilityRatio4(&$items) {
 270:     global $MaxAge;
 271: 
 272:     $sign = (-1);   //増減符号
 273:     $d  = 0.01;     //毎年増分
 274:     $t1 = 1.8;      //上限値
 275:     $t2 = 0.9;      //下限値
 276:     for ($i = 1$i < PERIOD$i++) {
 277:         $year = YEAR_START + $i;
 278:         $total = 0;
 279:         for ($age = 0$age <$MaxAge$age++) {
 280:             $items[$year][$age]['fertility'] = $items[$year - 1][$age]['fertility'* (1 + $d * $sign);
 281:             $total +$items[$year][$age]['fertility'];
 282:         }
 283:         if ($total >$t1)  $sign = (-1);
 284:         if ($total <$t2)   $sign = (+1);
 285:     }
 286: }

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

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

解説:死亡率

 299: /**
 300:  * 死亡率の推計関数:推計開始年から一定
 301:  * @param   array $items 推計表
 302:  * @return  なし
 303: */
 304: function calcDeathRatio1(&$items) {
 305:     global $MaxAge;
 306: 
 307:     for ($i = 1$i < PERIOD$i++) {
 308:         $year = YEAR_START + $i;
 309:         for ($age = 0$age <$MaxAge$age++) {
 310:             $items[$year][$age]['death_male'] = $items[$year - 1][$age]['death_male'];
 311:             $items[$year][$age]['death_female'] = $items[$year - 1][$age]['death_female'];
 312:         }
 313:     }
 314: }

 316: /**
 317:  * 死亡率の推計関数:推計開始年から毎年4‰ずつ減少
 318:  * @param   array $items 推計表
 319:  * @return  なし
 320: */
 321: function calcDeathRatio2(&$items) {
 322:     global $MaxAge;
 323: 
 324:     $d = (-0.004);  //毎年増分
 325:     for ($i = 1$i < PERIOD$i++) {
 326:         $year = YEAR_START + $i;
 327:         for ($age = 0$age <$MaxAge$age++) {
 328:             $items[$year][$age]['death_male'] = $items[$year - 1][$age]['death_male'* (1 + $d);
 329:             $items[$year][$age]['death_female'] = $items[$year - 1][$age]['death_female'* (1 + $d);
 330:         }
 331:     }
 332: }

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

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

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

解説:事業所数

 352: /**
 353:  * 事業所数の推計関数:推計開始年から生産年齢人口に応じて変化
 354:  * @param   array $items 推計表
 355:  * @return  なし
 356: */
 357: function calcCompany(&$items) {
 358:     global $tableCompany;
 359: 
 360:     //初年度の生産年齢人口
 361:     $worker0 = 0;
 362:     for ($age = WORKER_AGE_MIN$age <WORKER_AGE_MAX$age++) {
 363:         $worker0 +$items[YEAR_START][$age]['male'+ $items[YEAR_START][$age]['female'];
 364:     }
 365: 
 366:     //推計
 367:     for ($i = 0$i < PERIOD$i++) {
 368:         $year = YEAR_START + $i;
 369:         $worker = 0;
 370:         for ($age = WORKER_AGE_MIN$age <WORKER_AGE_MAX$age++) {
 371:             $worker +$items[$year][$age]['male'+ $items[$year][$age]['female'];
 372:         }
 373:         foreach ($tableCompany as $key=>$arr) {
 374:             $items[$year]['company'][$key] = $arr['num'* ($worker / $worker0);
 375:         }
 376:     }
 377: }

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

解説:人口推計

 379: /**
 380:  * 人口推計+事業所数推計
 381:  * @param   string $opt1 オプション1(出生率の推計関数名)
 382:  * @param   string $opt2 オプション2(死亡率の推計関数名)
 383:  * @param   string $opt3 オプション3(事業所数の推計関数名)
 384:  * @return  array 人口推計結果/FALSE:データファイルがないなど
 385: */
 386: function calcPopulation($opt1, $opt2, $opt3) {
 387:     global $MaxAge;
 388: 
 389:     $items = array();
 390: 
 391:     //元となるデータファイルを読み込む
 392:     $infp = fopen(FILE_DATA, 'r');
 393:     if ($infp == FALSE)     return FALSE;
 394:     fgetcsv($infp, 9999, ',');      //ラベル行をスキップ
 395:     while (! feof($infp)) {
 396:         $arr = fgetcsv($infp, 9999, ',');
 397:         if ($arr == FALSE)  break;
 398:         if (! is_numeric($arr[1]))  continue;
 399:         $age = $arr[0];
 400:         $items[YEAR_START][$age]['death_male'] = $arr[1] / 1000;    //年齢別死亡率(男性)
 401:         $items[YEAR_START][$age]['death_female'] = $arr[2] / 1000;  //年齢別死亡率(女性)
 402:         $items[YEAR_START][$age]['fertility'] = $arr[3];    //年齢別出生率
 403:         $items[YEAR_START][$age]['male']   = $arr[4] / 10;  //男性人口(単位:万人)
 404:         $items[YEAR_START][$age]['female'] = $arr[5] / 10;  //女性人口(単位:万人)
 405:     }
 406:     fclose($infp);
 407:     $MaxAge = $age;     //最高齢
 408:     $opt1($items);      //出生率の推計
 409:     $opt2($items);      //死亡率の推計
 410: 
 411:     //人口推計
 412:     for ($i = 1$i < PERIOD$i++) {
 413:         $year = YEAR_START + $i;
 414: 
 415:         //0歳
 416:         $items[$year][0]['male'] = 0;
 417:         $items[$year][0]['female'] = 0;
 418:         for ($age = 0$age <$MaxAge$age++) {
 419:             $n = $items[$year - 1][$age]['female'* $items[$year - 1][$age]['fertility'];          //出生数
 420:             $items[$year][0]['male']   += ($n / 2);
 421:             $items[$year][0]['female'+= ($n / 2);
 422:         }
 423: 
 424:         //1歳~$MaxAge歳
 425:         for ($age = 1$age <$MaxAge$age++) {
 426:             $items[$year][$age]['male'] = $items[$year - 1][$age - 1]['male'* (1 - $items[$year][$age]['death_male']);
 427:             $items[$year][$age]['female'] = $items[$year - 1][$age - 1]['female'* (1 - $items[$year][$age]['death_female']);
 428:         }
 429:     }
 430:     $opt3($items);      //事業所数の推計
 431: 
 432:     return $items;
 433: }

ユーザー関数 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