国勢調査から5歳階級の人口推移を調べる

 人口統計は最も重要な基幹統計の一つである.総務省の e-Stat は確かに有用であるが,かゆいところに手が届かない.例えば「市区町村ごと,年齢5歳階級ごとの人口構成の国勢調査ごとの推移を知りたい」という要求には全く無力である.

 主として技術的な理由によるものと,統計調査の粒度の細かさによる.技術的な理由としては,データベースの画面表示セル数の上限を容易に超えてしまうデータ量になってしまうことである.しかし,根本的な理由は調査の粒度の細かさである.

 2005 年以前と 2010 年以降とでは調査の精度が違う.今後は高精度なデータファイルが e-Stat に掲載されていくものと思われるが,2005 年以前に関しては都道府県より細かい粒度は存在しない.そこを求めると手作業になってしまい,現実的ではない.国立社会保障・人口問題研究所ならデータを持っているかもしれない.

 2020 年は国勢調査の年にあたる.総務省にはできるだけ細かい粒度でのデータ掲載を望むものである.

国勢調査のデータファイル

大正 9 年(1920 年)から平成 17 年(2005 年)まで

 都道府県別の統計はない.全国のみである.男女別の統計がある.下図の 17 番のファイルをダウンロードする.ファイル名は 05017 である.ワークシート 2 枚からなる.JH17017-01 というワークシートが目的である.

 今回はこのデータを使う.

平成17年国勢調査「17 年齢(5歳階級),男女別人口及び人口性比-全国(大正9年~平成17年)」
平成17年国勢調査「17 年齢(5歳階級),男女別人口及び人口性比-全国(大正9年~平成17年)」

平成 7 年(1995 年)から平成 17 年(2005 年)まで

 都道府県別の統計のみで,市区町村の粒度はない.男女別の統計がある.

平成 22 年(2010 年)以降

 市区町村の粒度で各年齢,男女別のデータが存在する.本来,このレベルで調査・公開してもらいたい.

データクレンジング

 よく見る積み上げ棒グラフでは5歳ごとの年齢階級(5歳階級)でデータ系列を分類している.しかし,この表記だとグラフ作成はしやすいが解釈が難しくなる.少子高齢化の正体が見えづらいのは,これが原因ではないか.

 本来,年齢は生まれた年と現在との差で計算される相対的な値に過ぎない.だから,生まれた年を5年毎の階級(生年階級とでも言おうか)に区切ってデータ系列にしてみたらどうだろう.

5歳階級を生年に変換

 年度から年齢階級を引き算するだけである.例えば,2015 年度の 0-4 歳階級は 2015 となる.DATEDIFF 関数の逆の使い方をやるわけだ.できた列のタイトルを BirthYear としておこう.

年度は横軸となる

 これは通常のグラフと変わらない.

データ系列の要素数は同じでなくてはならない

 1920 年から始まった国勢調査は 2005 年で 18 回目である.だからデータ系列の要素数も 18 でなくてはならない.

 何を当たり前のことを,と思うかも知れない.しかし,意外と盲点である.さもないとグラフの表記が狂う.横軸の位置が定まらないのである.グラフにおいてこれは致命的だ.

 その目でもう一度テーブルを見直すと,不足しているデータがあることに気がつく.生年でフィルターをかけた際に抽出されてくるレコードは 18 件あるだろうか?もし不足しているなら追加する必要がある.

直積を作るには SQL が向いている

 テーブルに新たな行を追加するには EXCEL ならループの中で ListRows.Add メソッドを使うだろう.だが,EXCEL ではこういう作業はまだ苦手だ.分かっている人はすぐにピンとくると思うが,これは直積を作ることに他ならない.こういう作業は SQL にやらせた方がうまく行く.

 そこで一旦テーブルを txt ファイルにエクスポートして SQL Server にインポートする.

一時テーブルでマスターを作成

 使い捨てのマスターテーブルなので,一時テーブルに生年と年度を書き込む.この一時テーブルには35 件(1835 年から 2005 年まで 5 年ごと)× 18 件(1920 年から 2005 年まで 5 年ごと)で 630 件のデータが入る.このマスターに対して左外部結合を行う.

 下記クエリは生年と年度の直積を作成するものである.

DROP	TABLE IF EXISTS #SERIES;
CREATE	TABLE #SERIES(BIRTHYEAR INT NOT NULL);
INSERT	INTO #SERIES VALUES (1835),
(1840),
(1845),
(1850),
(1855),
(1860),
(1865),
(1870),
(1875),
(1880),
(1885),
(1890),
(1895),
(1900),
(1905),
(1910),
(1915),
(1920),
(1925),
(1930),
(1935),
(1940),
(1945),
(1950),
(1955),
(1960),
(1965),
(1970),
(1975),
(1980),
(1985),
(1990),
(1995),
(2000),
(2005);

DROP	TABLE IF EXISTS #FISCALYEAR;
CREATE	TABLE #FISCALYEAR(FISCALYEAR INT NOT NULL);
INSERT	INTO #FISCALYEAR VALUES(1920),
(1925),
(1930),
(1935),
(1940),
(1945),
(1950),
(1955),
(1960),
(1965),
(1970),
(1975),
(1980),
(1985),
(1990),
(1995),
(2000),
(2005);

WITH CTE(BirhtYear, FiscalYear)
AS(SELECT	* 
FROM	#SERIES
CROSS	JOIN #FISCALYEAR)

SELECT	*
FROM	CTE
ORDER	BY BirhtYear, FiscalYear;
(35 行処理されました)

(18 行処理されました)

(630 行処理されました)

マスターに人口テーブルを全結合

 次は生年と年度の直積に人口テーブルを全結合するクエリである.左外部結合ではなく全結合するのは 1945 年の国勢調査のみ,年齢階級の集計区分が異なるためである.

SELECT	* 
FROM	CTE
FULL	JOIN	dbo.[T_Population(1920-2005)]
ON		CTE.BirhtYear = dbo.[T_Population(1920-2005)].BirthYear
AND		CTE.FiscalYear = dbo.[T_Population(1920-2005)].FiscalYear
ORDER	BY CTE.BirhtYear, CTE.FiscalYear;
(648 行処理されました)

 この 1945 年のデータをどう扱うべきだろうか?ここで一旦,元のデータに戻ろう.

 1945 年は終戦の年である.なぜこの時の国勢調査のみ, 1 歳から 5 歳という年齢階級で集計されたのかは,定かでない.他の年はすべて 0 歳から 4 歳という年齢階級で集計されているのにである.推測だが,日本人の年齢の数え方に「数え年」があるためではないだろうか.

 境界の年齢にある人口の分だけ集計値がずれるが,グラフの見やすさを優先する.基のデータが存在しない以上,やむを得ない.

 戦後 10 年間の年齢の集計には注釈が多い.「数え年」,「沖縄」など戦後の混乱が続いていることを伺わせる.

 一旦人口テーブルを削除しよう.

DROP TABLE dbo.[T_Population(1920-2005)];
コマンドは正常に完了しました。

 元の EXCEL ファイルの 1945 年の年齢階級を 1 歳ずつ減らして修正する.その後年度から年齢階級を引き算して生年を算出する.

 テキストファイルをエクスポートして SQL Server にインポートする.ファイル末尾に余計な空行があるためメモ帳で削除しておく.

インポートに成功した
インポートに成功した

 以下のクエリを実行して結果を確認する.

DROP	TABLE IF EXISTS #SERIES;
CREATE	TABLE #SERIES(BIRTHYEAR INT NOT NULL);
INSERT	INTO #SERIES VALUES (1835),
(1840),
(1845),
(1850),
(1855),
(1860),
(1865),
(1870),
(1875),
(1880),
(1885),
(1890),
(1895),
(1900),
(1905),
(1910),
(1915),
(1920),
(1925),
(1930),
(1935),
(1940),
(1945),
(1950),
(1955),
(1960),
(1965),
(1970),
(1975),
(1980),
(1985),
(1990),
(1995),
(2000),
(2005);

DROP	TABLE IF EXISTS #FISCALYEAR;
CREATE	TABLE #FISCALYEAR(FISCALYEAR INT NOT NULL);
INSERT	INTO #FISCALYEAR VALUES(1920),
(1925),
(1930),
(1935),
(1940),
(1945),
(1950),
(1955),
(1960),
(1965),
(1970),
(1975),
(1980),
(1985),
(1990),
(1995),
(2000),
(2005);

WITH CTE(BirhtYear, FiscalYear)
AS(SELECT	* 
FROM	#SERIES
CROSS	JOIN #FISCALYEAR)

SELECT	* 
FROM	CTE
FULL	JOIN	dbo.T_Population_1920_2005
ON		CTE.BirhtYear = dbo.T_Population_1920_2005.BirthYear
AND		CTE.FiscalYear = dbo.T_Population_1920_2005.FiscalYear
ORDER	BY CTE.BirhtYear, CTE.FiscalYear;

DROP	TABLE IF EXISTS #SERIES;
DROP	TABLE IF EXISTS #FISCALYEAR;
(35 行処理されました)

(18 行処理されました)

(630 行処理されました)

 結果を「ヘッダー付きでコピー」して EXCEL に貼り付け,テーブルに変換する.大量の NULL が見えるが,「検索と置換」で 0 に一括置換しておこう.

NULLを0に置換
NULLを0に置換

 下図にあるように,よく見ると C 列,D 列,E 列は不要だ.削除する.

不要なC, D, E 列を削除する
不要なC, D, E 列を削除する

まず年度を昇順ソート,ついで生年を降順ソート

 グラフを作成する前にテーブルをソートするのだが,順番がある.まず「年度」を昇順ソート,ついで「生年」を降順ソートである.

 年度は横軸の並ぶ順序を決めるものであり,生年はデータ系列の PlotOrder を決めるものである.EXCEL の仕様に合わせている.

まず「年度」で昇順ソート
まず「年度」で昇順ソート
次に「生年」で降順ソート
次に「生年」で降順ソート

 後の行程でフィルターをかけた際に処理が楽になる.必ずやっておこう.これでグラフ作成の準備が完了した.

EXCEL によるグラフ作成

 データ系列が多いため VBA でグラフを作成する.その際の基本方針を述べておく.

基本方針

グラフタイプは積み上げ棒グラフ

 日本の人口を5歳の生年ごとに塗り分けたい.実数を表現するのであるから積み上げ棒グラフが最適である.

 総数なら積み上げ縦棒グラフ,男女別なら積み上げ横棒グラフである.

 後で調べて分かったのだが,EXCEL では積み上げグラフと集合グラフの組み合わせは相性が非常に悪く,両者の組み合わせを一つのグラフで表現するにはテーブルの構造を完全に破壊しなければならず,データの可逆性が失われる.EXCEL の限界である.

データ系列の追加

 これまでも述べてきたように,テーブルに生年でフィルターをかけ,抽出された行を一つのデータ系列として追加する.それをループする.

 ループカウンターは 2005 から開始し,1935 で終わり,5 ずつ減算する.

オブジェクトテーマカラーの指定

オブジェクトテーマカラーは 60 色

 EXCEL のオブジェクトテーマカラーは全部で 60 色ある.今回扱うデータ系列数は 35 である.全部の色を使い切ることはないはずだが,既に死亡していなくなった過去世代の階級はグレーのグラデーションとしたい.

 2005 年時点でいなくなった階級は 1915 年生まれ以前である.というか,1920 年から調査が始まったのだから当然といえば当然だ.

 どこまでグレーとし,どこからカラーにするかはグラフを作りながら考えよう.まずは手を動かすことだ.

EXCELのテーマカラー
EXCELのテーマカラー

 上図を見ると,グレーの系統は 4 つ,青の系統は 3 つある.重複として考えると実際に使用できる色は 5 系統 25 色である.意外に少ない.

25 年周期とするのが合理的

 隣接する年齢階級は同系統のグラデーションとしたい.4 色で 20 年,5 色で 25 年だから,計算上は 1 系統 4 色でも間に合う.しかし,データの特徴をよく見ると,1 系統 5 色 25 年周期とするのが合理的と思われる.

  • 2000 年生まれ以降を青の系統 2 色
  • 1975 年生まれ以降を緑の系統 5 色
  • 1950 年生まれ以降をゴールドの系統 5 色
  • 1925 年生まれ以降をオレンジの系統 5 色
  • それ以前は白の系統 5 色の循環

 理由は不明だが,EXCEL による色指定と html での色指定が一致しない.この原因について追求するのはまた別の機会にしよう.

コードの実際

Option Explicit

Sub PopulationChart()

Dim mySht1      As Worksheet
Dim mySht2      As Worksheet
Dim myLstObj    As ListObject
Dim myCht       As Chart

Set mySht1 = Worksheets("Sheet3")
Set myLstObj = mySht1.ListObjects(1)
Set mySht2 = Worksheets.Add(after:=mySht1)
Set myCht = mySht2.Shapes.AddChart2(Style:=-1, _
                              XlChartType:=xlColumnStacked, _
                                     Left:=0, _
                                      Top:=0, _
                                    Width:=400, _
                                   Height:=400).Chart

Dim i           As Long
Dim j           As Long
Dim myRng1      As Range

Dim FiscalYear()    As Long
Dim Population()    As Long

Dim mySeries    As Series

For i = 2005 To 1835 Step -5
    With myLstObj
        .Range.AutoFilter field:=1, Criteria1:=i
        Set myRng1 = Intersect(.DataBodyRange, _
                               .Range.SpecialCells(Type:=xlCellTypeVisible))
        If myRng1 Is Nothing Then
        Else
            For j = 0 To myRng1.Rows.Count - 1
                ReDim Preserve FiscalYear(j)
                ReDim Preserve Population(j)
                FiscalYear(j) = myRng1.Cells(j + 1, 2)
                Population(j) = myRng1.Cells(j + 1, 3)
            Next j
            Set mySeries = myCht.SeriesCollection.NewSeries
            With mySeries
                .Name = i
                .XValues = FiscalYear
                .Values = Population
            End With
        End If
        .Range.AutoFilter field:=1
    End With
Next i

Dim myAxis      As Axis
Dim myChtGrp    As ChartGroup

With myCht
    With .ChartTitle
        .Caption = "日本人口の年齢階級推移"
        .Left = 0
    End With
    Set myAxis = .Axes(xlCategory)
    With myAxis
        .Format.Line.Visible = msoFalse
        .MajorGridlines.Format.Line.Visible = msoFalse
    End With
    Set myAxis = .Axes(xlValue)
    With myAxis
        .DisplayUnit = xlTenThousands
        .Format.Line.Visible = msoFalse
        .MaximumScale = 125000000
        .MajorUnit = .MaximumScale / 5
        .MajorGridlines.Format.Line.Visible = msoFalse
        With .DisplayUnitLabel
            .Orientation = xlHorizontal
        End With
    End With
    With .PlotArea
        .Format.Fill.Visible = msoFalse
        .Format.Line.Visible = msoFalse
        .Left = -8
        .Width = 400
    End With
    With .ChartArea
        .Format.Fill.ForeColor.ObjectThemeColor = msoThemeColorBackground1
        .Format.TextFrame2.TextRange.Font.Name = "TimesNewRoman"
    End With
    Set myChtGrp = .ChartGroups(1)
    With myChtGrp
        .GapWidth = 0
    End With
    For Each mySeries In .SeriesCollection
        With mySeries
            Debug.Print .Format.Fill.ForeColor.RGB
            Select Case .Name
            Case "2005"
                .Format.Fill.ForeColor.RGB = RGB(47, 85, 151)
            Case "2000"
                .Format.Fill.ForeColor.RGB = RGB(32, 56, 100)
            Case "1995"
                .Format.Fill.ForeColor.RGB = RGB(226, 240, 217)
            Case "1990"
                .Format.Fill.ForeColor.RGB = RGB(197, 224, 180)
            Case "1985"
                .Format.Fill.ForeColor.RGB = RGB(169, 209, 142)
            Case "1980"
                .Format.Fill.ForeColor.RGB = RGB(84, 130, 53)
            Case "1975"
                .Format.Fill.ForeColor.RGB = RGB(56, 87, 35)
            Case "1970"
                .Format.Fill.ForeColor.RGB = RGB(255, 242, 204)
            Case "1965"
                .Format.Fill.ForeColor.RGB = RGB(255, 230, 153)
            Case "1960"
                .Format.Fill.ForeColor.RGB = RGB(255, 217, 102)
            Case "1955"
                .Format.Fill.ForeColor.RGB = RGB(191, 144, 0)
            Case "1950"
                .Format.Fill.ForeColor.RGB = RGB(127, 96, 0)
            Case "1945"
                .Format.Fill.ForeColor.RGB = RGB(251, 229, 214)
            Case "1940"
                .Format.Fill.ForeColor.RGB = RGB(248, 203, 173)
            Case "1935"
                .Format.Fill.ForeColor.RGB = RGB(244, 177, 131)
            Case "1930"
                .Format.Fill.ForeColor.RGB = RGB(197, 90, 17)
            Case "1925"
                .Format.Fill.ForeColor.RGB = RGB(132, 60, 12)
            Case "1920"
                .Format.Fill.ForeColor.RGB = RGB(242, 242, 242)
            Case "1915"
                .Format.Fill.ForeColor.RGB = RGB(217, 217, 217)
            Case "1910"
                .Format.Fill.ForeColor.RGB = RGB(191, 191, 191)
            Case "1905"
                .Format.Fill.ForeColor.RGB = RGB(166, 166, 166)
            Case "1900"
                .Format.Fill.ForeColor.RGB = RGB(127, 127, 127)
            Case "1895"
                .Format.Fill.ForeColor.RGB = RGB(242, 242, 242)
            Case "1890"
                .Format.Fill.ForeColor.RGB = RGB(217, 217, 217)
            Case "1885"
                .Format.Fill.ForeColor.RGB = RGB(191, 191, 191)
            Case "1880"
                .Format.Fill.ForeColor.RGB = RGB(166, 166, 166)
            Case "1875"
                .Format.Fill.ForeColor.RGB = RGB(127, 127, 127)
            Case "1870"
                .Format.Fill.ForeColor.RGB = RGB(242, 242, 242)
            Case "1865"
                .Format.Fill.ForeColor.RGB = RGB(217, 217, 217)
            Case "1860"
                .Format.Fill.ForeColor.RGB = RGB(191, 191, 191)
            Case "1855"
                .Format.Fill.ForeColor.RGB = RGB(166, 166, 166)
            Case "1850"
                .Format.Fill.ForeColor.RGB = RGB(127, 127, 127)
            Case "1845"
                .Format.Fill.ForeColor.RGB = RGB(242, 242, 242)
            Case "1840"
                .Format.Fill.ForeColor.RGB = RGB(217, 217, 217)
            Case "1835"
                .Format.Fill.ForeColor.RGB = RGB(191, 191, 191)
            End Select
        End With
    Next mySeries
End With
End Sub

結果

日本人口の年齢階級推移(国勢調査より筆者作成)
日本人口の年齢階級推移(国勢調査より筆者作成)

 1925 年生まれが 1945 年調査で急減している.もちろん第2次世界大戦が影響している.

 続いて 1950 年生まれが急増している.これが団塊世代である.25 年後の 1975 年生まれ,これが団塊ジュニア世代である.

 このサイクルで行けば 2000 年頃に第3次ベビーブームが来るはずだった.しかし実際には少子化が進行しており,この時点で日本の将来はほぼ決まった.

 要因は様々なことが言われている.少子化対策はもちろん必要だ.だが,そろそろ「不都合な真実」から目を背けるのではなく,正面から向き合う方向に舵を切るべきだ.

“国勢調査から5歳階級の人口推移を調べる” への1件の返信

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください