PHPで人口を推計する

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

2018 年 6 月、2017 年の推計値、統計データに更新した。
さらに、生産年齢人口減少に伴う企業(事業所)数の減少を推計できるようにした。

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

日本の人口推計

サンプル・プログラム

解説:準備

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

0034: //元となるCSVデータファイル名
0035: //人口・死亡率:2017年 http://www.stat.go.jp/data/nenkan/66nenkan/02.html
0036: //出生率:2020年の中位値 http://www.ipss.go.jp/pp-zenkoku/j/zenkoku2017/pp29_Report2.pdf
0037: define('FILE_DATA', './population2017.csv');
0038: 
0039: //推計開始年(元データの年次)
0040: define('YEAR_START', 2017);

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

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

0058: //従業者規模別民営事業所数(2014年)
0059: //http://www.stat.go.jp/data/nihon/07.html
0060: // num=事業所数, color=描画色
0061: $tableCompany = array(
0062: '1-4人'             => array('num'=>3225428,'color'=>'#006600'),
0063: '5-9人'             => array('num'=>1090283,'color'=>'#00AA00'),
0064: '10-19人'         => array('num'=>650018,   'color'=>'#00CC00'),
0065: '20-29人'         => array('num'=>230983,   'color'=>'#00FF00'),
0066: '30-49人'         => array('num'=>161096,   'color'=>'#00FF44'),
0067: '50-99人'         => array('num'=>101321,   'color'=>'#00FF88'),
0068: '100-199人'         => array('num'=>38678,    'color'=>'#00FFAA'),
0069: '200-299人'         => array('num'=>10387,    'color'=>'#00FFCC'),
0070: '300人以上'         => array('num'=>12247,    'color'=>'#00FFFF')
0071: );

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

解説:出生率

0160: /**
0161:  * 出生率の推計関数:推計開始年から一定
0162:  * @param array $items 推計表
0163:  * @return なし
0164: */
0165: function calcFertilityRatio1(&$items) {
0166:     global $MaxAge;
0167: 
0168:     for ($i = 1; $i < PERIOD$i++) {
0169:         $year = YEAR_START + $i;
0170:         for ($age = 0; $age <= $MaxAge$age++) {
0171:             $items[$year][$age]['fertility'] = $items[$year - 1][$age]['fertility'];
0172:         }
0173:     }
0174: }
0175: 
0176: /**
0177:  * 出生率の推計関数:毎年1%ずつ減少,0.9で一定
0178:  * @param array $items 推計表
0179:  * @return なし
0180: */
0181: function calcFertilityRatio2(&$items) {
0182:     global $MaxAge;
0183: 
0184:     $d = (-0.01);  //毎年増分
0185:     $t2 = 0.9;        //下限値
0186:     for ($i = 1; $i < PERIOD$i++) {
0187:         $year = YEAR_START + $i;
0188:         $total = 0;
0189:         for ($age = 0; $age <= $MaxAge$age++) {
0190:             $items[$year][$age]['fertility'] = $items[$year - 1][$age]['fertility'] * (1 + $d);
0191:             $total += $items[$year][$age]['fertility'];
0192:         }
0193:         if ($total <= $t2)  $d = 0;
0194:     }
0195: }
0196: 
0197: /**
0198:  * 出生率の推計関数:毎年1%ずつ増加,1.8で一定
0199:  * @param array $items 推計表
0200:  * @return なし
0201: */
0202: function calcFertilityRatio3(&$items) {
0203:     global $MaxAge;
0204: 
0205:     $d  = 0.01;       //毎年増分
0206:     $t1 = 1.8;        //上限値
0207:     for ($i = 1; $i < PERIOD$i++) {
0208:         $year = YEAR_START + $i;
0209:         $total = 0;
0210:         for ($age = 0; $age <= $MaxAge$age++) {
0211:             $items[$year][$age]['fertility'] = $items[$year - 1][$age]['fertility'] * (1 + $d);
0212:             $total += $items[$year][$age]['fertility'];
0213:         }
0214:         if ($total >= $t1)  $d = 0;
0215:     }
0216: }
0217: 
0218: /**
0219:  * 出生率の推計関数:0.9と1.8の間で増減
0220:  * @param array $items 推計表
0221:  * @return なし
0222: */
0223: function calcFertilityRatio4(&$items) {
0224:     global $MaxAge;
0225: 
0226:     $sign = (-1); //増減符号
0227:     $d  = 0.01;       //毎年増分
0228:     $t1 = 1.8;        //上限値
0229:     $t2 = 0.9;        //下限値
0230:     for ($i = 1; $i < PERIOD$i++) {
0231:         $year = YEAR_START + $i;
0232:         $total = 0;
0233:         for ($age = 0; $age <= $MaxAge$age++) {
0234:             $items[$year][$age]['fertility'] = $items[$year - 1][$age]['fertility'] * (1 + $d * $sign);
0235:             $total += $items[$year][$age]['fertility'];
0236:         }
0237:         if ($total >= $t1)  $sign = (-1);
0238:         if ($total <= $t2)  $sign = (+1);
0239:     }
0240: }

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

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

解説:死亡率

0253: /**
0254:  * 死亡率の推計関数:推計開始年から一定
0255:  * @param array $items 推計表
0256:  * @return なし
0257: */
0258: function calcDeathRatio1(&$items) {
0259:     global $MaxAge;
0260: 
0261:     for ($i = 1; $i < PERIOD$i++) {
0262:         $year = YEAR_START + $i;
0263:         for ($age = 0; $age <= $MaxAge$age++) {
0264:             $items[$year][$age]['death_male'] = $items[$year - 1][$age]['death_male'];
0265:             $items[$year][$age]['death_female'] = $items[$year - 1][$age]['death_female'];
0266:         }
0267:     }
0268: }
0269: 
0270: /**
0271:  * 死亡率の推計関数:推計開始年から毎年4‰ずつ減少
0272:  * @param array $items 推計表
0273:  * @return なし
0274: */
0275: function calcDeathRatio2(&$items) {
0276:     global $MaxAge;
0277: 
0278:     $d = (-0.004); //毎年増分
0279:     for ($i = 1; $i < PERIOD$i++) {
0280:         $year = YEAR_START + $i;
0281:         for ($age = 0; $age <= $MaxAge$age++) {
0282:             $items[$year][$age]['death_male'] = $items[$year - 1][$age]['death_male'] * (1 + $d);
0283:             $items[$year][$age]['death_female'] = $items[$year - 1][$age]['death_female'] * (1 + $d);
0284:         }
0285:     }
0286: }
0287: 
0288: /**
0289:  * 死亡率の推計関数:推計開始年から毎年4‰ずつ減少
0290:  * @param array $items 推計表
0291:  * @return なし
0292: */
0293: function calcDeathRatio3(&$items) {
0294:     global $MaxAge;
0295: 
0296:     $d = (+0.004); //毎年増分
0297:     for ($i = 1; $i < PERIOD$i++) {
0298:         $year = YEAR_START + $i;
0299:         for ($age = 0; $age <= $MaxAge$age++) {
0300:             $items[$year][$age]['death_male'] = $items[$year - 1][$age]['death_male'] * (1 + $d);
0301:             $items[$year][$age]['death_female'] = $items[$year - 1][$age]['death_female'] * (1 + $d);
0302:         }
0303:     }
0304: }

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

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

解説:事業所数

0306: /**
0307:  * 事業所数の推計関数:推計開始年から生産年齢人口に応じて変化
0308:  * @param array $items 推計表
0309:  * @return なし
0310: */
0311: function calcCompany(&$items) {
0312:     global $tableCompany;
0313: 
0314:     //初年度の生産年齢人口
0315:     $worker0 = 0;
0316:     for ($age = WORKER_AGE_MIN$age <= WORKER_AGE_MAX$age++) {
0317:         $worker0 += $items[YEAR_START][$age]['male'] + $items[YEAR_START][$age]['female'];
0318:     }
0319: 
0320:     //推計
0321:     for ($i = 0; $i < PERIOD$i++) {
0322:         $year = YEAR_START + $i;
0323:         $worker = 0;
0324:         for ($age = WORKER_AGE_MIN$age <= WORKER_AGE_MAX$age++) {
0325:             $worker += $items[$year][$age]['male'] + $items[$year][$age]['female'];
0326:         }
0327:         foreach ($tableCompany as $key=>$arr) {
0328:             $items[$year]['company'][$key] = $arr['num'] * ($worker / $worker0);
0329:         }
0330:     }
0331: }

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

解説:人口推計

0333: /**
0334:  * 人口推計+事業所数推計
0335:  * @param string $opt1 オプション1(出生率の推計関数名)
0336:  * @param string $opt2 オプション2(死亡率の推計関数名)
0337:  * @param string $opt3 オプション3(事業所数の推計関数名)
0338:  * @return array 人口推計結果/FALSE:データファイルがないなど
0339: */
0340: function calcPopulation($opt1$opt2$opt3) {
0341:     global $MaxAge;
0342: 
0343:     $items = array();
0344: 
0345:     //元となるデータファイルを読み込む
0346:     $infp = fopen(FILE_DATA, 'r');
0347:     if ($infp == FALSE)     return FALSE;
0348:     fgetcsv($infp, 9999, ',');      //ラベル行をスキップ
0349:     while (!feof($infp)) {
0350:         $arr = fgetcsv($infp, 9999, ',');
0351:         if (! is_numeric($arr[0]))   continue;
0352:         $age = $arr[0];
0353:         $items[YEAR_START][$age]['death_male'] = $arr[1] / 1000;   //年齢別死亡率(男性)
0354:         $items[YEAR_START][$age]['death_female'] = $arr[2] / 1000;   //年齢別死亡率(女性)
0355:         $items[YEAR_START][$age]['fertility'] = $arr[3];  //年齢別出生率
0356:         $items[YEAR_START][$age]['male']   = $arr[4] / 10;   //男性人口(単位:万人)
0357:         $items[YEAR_START][$age]['female'] = $arr[5] / 10; //女性人口(単位:万人)
0358:     }
0359:     fclose($infp);
0360:     $MaxAge = $age;      //最高齢
0361:     $opt1($items);       //出生率の推計
0362:     $opt2($items);       //死亡率の推計
0363: 
0364:     //人口推計
0365:     for ($i = 1; $i < PERIOD$i++) {
0366:         $year = YEAR_START + $i;
0367: 
0368:         //0歳
0369:         $items[$year][0]['male'] = 0;
0370:         $items[$year][0]['female'] = 0;
0371:         for ($age = 0; $age <= $MaxAge$age++) {
0372:             $n = $items[$year - 1][$age]['female'] * $items[$year - 1][$age]['fertility'];            //出生数
0373:             $items[$year][0]['male']   += ($n / 2);
0374:             $items[$year][0]['female'] += ($n / 2);
0375:         }
0376: 
0377:         //1歳~$MaxAge歳
0378:         for ($age = 1; $age <= $MaxAge$age++) {
0379:             $items[$year][$age]['male'] = $items[$year - 1][$age - 1]['male'] * (1 - $items[$year][$age]['death_male']);
0380:             $items[$year][$age]['female'] = $items[$year - 1][$age - 1]['female'] * (1 - $items[$year][$age]['death_female']);
0381:         }
0382:     }
0383:     $opt3($items);       //事業所数の推計
0384: 
0385:     return $items;
0386: }

ユーザー関数 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円(税込)
rakuten
ISBN 9784121024688
高度経済成長を支え、高い技術力を賞賛された日本の中小企業。だが、近年は急激な人口減少や中国・アジアとの競争などで、苦しい状況にある。既存の企業は後継者不足に悩み、起業の件数も激減している。一九八六年に約八七万あった製造業事業所は、この三〇年のうちにほぼ半減した。こうした状況に突破口はあるのかー。現場主義を貫く経営学者が、豊富な事例を通して、課題と今後の展望を論じる。
 

参考サイト

(この項おわり)
header