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

解説:出生率

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

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

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

解説:死亡率

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

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

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

解説:事業所数

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

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

解説:人口推計

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

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

参考サイト

(この項おわり)
header