国勢調査の人口データをQGISを利用してPostGISに投入する

## はじめに

国勢調査の人口データを利用する機会が多く、その度ごとにe-Statからダウンロードして利用していたのですが、さすがに、それでは複雑な処理などが難しいので、PostGISに投入してみました。この記事の内容の多くは、[PostGISを使ってSQLだけで面積按分:準備編（QGISを使ってCSVデータとShapeデータ結合してPostgreSQLに投入）](https://qiita.com/takahi/items/9d44966b10d6257d8b2d)という記事に基づいていますが、いくつか自分なりのノウハウを見つけたため、新しく記事にします。

## 動作環境

この記事は、以下の環境において動作確認しています。それぞれのソフトは、最近のバージョンならほぼ問題無く動くと思います。WindowsやLinuxにおいてもほぼ同様のことが出来るはずですが、細かい差異は各自で読み換えてください。

- macOS Catalina 10.15.7
- QGIS 3.16
- 以下は Homebrewにてインストール
 - PostgreSQL 13.1
 - PostGIS 3.1.0


## データのダウンロード

「[e-Stat 政府統計の総合窓口](https://www.e-stat.go.jp)」からダウンロードします。毎回どこを見たらいいのか分からなくなるので、以下で手順を丁寧に説明します。ここでは250mメッシュで集計されたデータを利用しますが、利用目的に応じて、他のデータを選択してください。

データは、CSV形式で人口データが登録された「人口等基本集計に関する事項」と、統計を集計するエリア情報を含んだ境界データとに分かれています。ここでは、必要なエリアを選んでそれぞれのデータをダウンロードします。興味がある場所が複数のエリアに跨がっている場合もあります。その場合は、複数のエリアのデータをダウンロードしてください。

- Step1: トップページから「地図 地図上に統計データを表示（統計GIS）」をクリック
![スクリーンショット 2021-01-28 13.50.46.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/43024971-4640-3271-3955-14d0f7a77631.jpeg)

### 人口データをダウンロード

- Step2: 「統計データをダウンロード」をクリック
![スクリーンショット 2021-01-28 13.55.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/a4c45532-521b-39f8-1635-0dfe23d9e668.jpeg)

- Step3: 「国勢調査」→「2015年」→「5次メッシュ（250mメッシュ）」をクリックしてデータを絞り込む

![スクリーンショット 2021-01-28 13.59.09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/0adc4ce7-1c31-ef54-1c5a-5fadb431b3fc.jpeg)


- Step4: 「その１　人口等基本集計に関する事項」をクリック。データの仕様についてはその横の「定義書」からアクセスできる。

![スクリーンショット 2021-01-28 14.02.08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/a1660883-ed77-2f2b-1a1b-970f41fd3a03.jpeg)

- Step5: 目的のデータを探してダウンロード

データは、以下の地図にある1次メッシュごとにまとめられています。この地図はページ上部の「1次メッシュ枠情報」ボタンから閲覧できるので、自分が必要なデータのメッシュ番号を見つけてください。
![スクリーンショット 2021-01-28 14.06.14.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/cb5f5a8a-fc87-6b30-f510-685c0c2cb197.jpeg)

データを探すためには、「都道府県で絞込み」「メッシュコードで絞込み」機能を使うことで必要なデータが見つけやすくなります。データを見つけたら「CSV」というリンクをクリックしてデータをダウンロードしてください。

![スクリーンショット 2021-01-28 14.06.18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/577bbab8-9c15-f4d0-95d0-9116f77d01eb.jpeg)

### 境界データをダウンロード
- Step6: Step2の[地図で見る統計(統計GIS)](https://www.e-stat.go.jp/gis)に戻り、「境界データダウンロード」をクリック

![スクリーンショット 2021-01-28 14.18.52.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/d4f28f00-eba0-6b20-2f78-baca1eca5a14.jpeg)

- Step7: 「5次メッシュ（250mメッシュ）」、「世界測地系緯度経度・Shapefile」と絞り込む

![スクリーンショット 2021-01-28 14.22.52.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/83f9ad20-4b39-d247-27f2-4c16f7c0345b.jpeg)

-Step8: 対象地域の境界データをダウンロード。

人口データと同様にエリアを絞り込むなどして、必要なデータを選択しダウンロードする。ZIPファイルがダウンロードされるのでデータを解凍する。

![スクリーンショット 2021-01-28 14.26.10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/da433c82-5b74-c28c-2db5-506c6510ca83.jpeg)

## データの事前処理

国勢調査データCSVファイルは癖が強いので、利用する前にテキストファイルの段階でより使いやすいように書き換えます。ここでは、ヘッダとnull値を使いやすい形に置き換えます。

### ヘッダの調整
オリジナルCSVファイルにはヘッダが2行あり、1行目は`T000876001`という感じの記号なのでこれは使いません。2行目は、日本語で分かりやすいのですが、SQLを操作するツールによっては日本語の扱いに不安があるので、新しくヘッダを作成しました。


|オリジナル（1行目）|オリジナル（2行目）|今回作成したヘッダ|
|------------|--------------------------------------------------|----------------------------------|
| KEY_CODE   |                                                  | KEY_CODE                         |
| HTKSYORI   |                                                  | HTKSYORI                         |
| HTKSAKI    |                                                  | HTKSAKI                          |
| GASSAN     |                                                  | GASSAN                           |
| T000876001 | 人口総数                                         | population                       |
| T000876002 | 人口総数　男                                     | population_m                     |
| T000876003 | 人口総数　女                                     | population_f                     |
| T000876004 | ０〜１４歳人口総数                               | population_0_to_14               |
| T000876005 | ０〜１４歳人口　男                               | population_0_to_14_m             |
| T000876006 | ０〜１４歳人口　女                               | population_0_to_14_f             |
| T000876007 | １５歳以上人口総数                               | population_over_15               |
| T000876008 | １５歳以上人口　男                               | population_over_15_m             |
| T000876009 | １５歳以上人口　女                               | population_over_15_f             |
| T000876010 | １５〜６４歳人口総数                             | population_15_to_64              |
| T000876011 | １５〜６４歳人口　男                             | population_15_to_64_m            |
| T000876012 | １５〜６４歳人口　女                             | population_15_to_64_f            |
| T000876013 | ２０歳以上人口総数                               | population_over_20               |
| T000876014 | ２０歳以上人口　男                               | population_over_20_m             |
| T000876015 | ２０歳以上人口　女                               | population_over_20_f             |
| T000876016 | ６５歳以上人口総数                               | population_over_65               |
| T000876017 | ６５歳以上人口　男                               | population_over_65_m             |
| T000876018 | ６５歳以上人口　女                               | population_over_65_f             |
| T000876019 | ７５歳以上人口総数                               | population_over_75               |
| T000876020 | ７５歳以上人口　男                               | population_over_75_m             |
| T000876021 | ７５歳以上人口　女                               | population_over_75_f             |
| T000876022 | 外国人人口総数                                   | population_foreign               |
| T000876023 | 外国人人口　男                                   | population_foreign_m             |
| T000876024 | 外国人人口　女                                   | population_foreign_f             |
| T000876025 | 世帯総数                                         | total_households                 |
| T000876026 | 一般世帯数                                       | general_households               |
| T000876027 | １人世帯の一般世帯数                             | one-person_households            |
| T000876028 | ２人世帯の一般世帯数                             | two-person_households            |
| T000876029 | ３人世帯の一般世帯数                             | three-person_households          |
| T000876030 | ４人世帯の一般世帯数                             | four-person_households           |
| T000876031 | ５人世帯の一般世帯数                             | five-person_households           |
| T000876032 | ６人世帯の一般世帯数                             | six-person_households            |
| T000876033 | ７人以上世帯の一般世帯数                         | seven-more-person_households     |
| T000876034 | 親族のみの一般世帯数                             | households_with_relatives        |
| T000876035 | 核家族の一般世帯数                               | households_of_nuclear_family     |
| T000876036 | 核家族以外の一般世帯数                           | households_of_non-nuclear_family |
| T000876037 | ６歳未満世帯員のいる一般世帯数                   | households_with_under-6_member   |
| T000876038 | ６５歳以上世帯員のいる一般世帯数                 | households_with_over-65_member   |
| T000876039 | 世帯主の年齢が２０〜２９歳の１人世帯の一般世帯数 | one-person_households_20_to_29   |
| T000876040 | 高齢単身の一般世帯数                             | elderly_one-person_households    |
| T000876041 | 高齢夫婦のみの一般世帯数                         | households_of_elderly_couples    |

ということで、CSVファイルの1、2行目を削除し、代わりに以下の1行をヘッダとして追加します。

```csv:置き換えるヘッダ
KEY_CODE,HTKSYORI,HTKSAKI,GASSAN,population,population_m,population_f,population_0_to_14,population_0_to_14_m,population_0_to_14_f,population_over_15,population_over_15_m,population_over_15_f,population_15_to_64,population_15_to_64_m,population_15_to_64_f,population_over_20,population_over_20_m,population_over_20_f,population_over_65,population_over_65_m,population_over_65_f,population_over_75,population_over_75_m,population_over_75_f,population_foreign,population_foreign_m,population_foreign_f,total_households,general_households,one-person_households,two-person_households,three-person_households,four-person_households,five-person_households,six-person_households,seven-more-person_households,households_with_relatives,households_of_nuclear_family,households_of_non-nuclear_family,households_with_under-6_member,households_with_over-65_member,one-person_households_20_to_29,elderly_one-person_households,households_of_elderly_couples

```


### nullデータの表現を修正
オリジナルのCSVデータは、値のない項目が`*`で埋められています。このまま読み込むと、これを含むデータは数値として認識されないので、エディタの置換機能で、`*`を全て削除します。

以下では、ここまで修正したCSVファイルをデータとして利用します。

## QGISへのデータ読み込み

ダウンロードして事前処理を済ませたCSVファイル、Shapeファイルを、QGISに読み込みます。新規プロジェクトを作成したうえで、以下の要領で操作を進めます。

### CSVファイルの読み込み
メニューから「レイヤ」→「レイヤを追加」→「CSVテキストレイヤを追加」と進め、先ほど編集したファイルをファイル名に設定します。この時、「レコードとフィールドのオプション」において「最初の行はフィールド名」がチェックされていること、「ジオメトリ定義」として「ジオメトリなし」が選ばれていることを確認してください。オプションを確認した後、「追加」を押してデータを読み込ませます。

![スクリーンショット 2021-01-28 15.54.00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/060237af-b11b-48e1-74e7-32aa15e4e026.jpeg)

### Shapeファイルの読み込み

メニューから「レイヤ」→「レイヤを追加」→「ベクタレイヤを追加」と進め、先ほどダウンロードしたShapeファイルをファイル名に設定します。今回、オプションなどは意識する必要はないと思います。

![スクリーンショット 2021-01-28 16.00.08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/de36cc61-3bd8-389e-0d4d-31cc49cbd819.jpeg)


### データの結合
ここまでの段階で、レイヤとしてShapeファイルの境界図形とCSVファイル（これは地図上には表示されない）が読み込まれていると思います。次の段階として、この二つのデータを境界図形のKEY_CODEとCSVファイルのKEY_CODEを紐付けることで結合します。

具体的には、まず境界図形レイヤを右クリック→プロパティを呼び出します。

![スクリーンショット 2021-01-28 16.08.21.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/2367c2ff-b2b1-123e-fbe6-2923b04968d0.jpeg)

次に、プロパティの左のメニューから「テーブル結合」を選び、「＋」ボタンを押します。

![スクリーンショット 2021-01-28 16.15.20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/3fad576c-1cc9-2475-8503-f9fc5ca717ad.jpeg)

「ベクタ結合を追加」の画面で、「結合するレイヤ」としてCSVファイルのレイヤを設定、結合基準の属性、ターゲット属性をそれぞれ`KEY_CODE`に設定します。また、複数の国勢調査データを読み込んだ時を考えて、「カスタムフィールド名の接頭辞」のチェックを入れ、値を空白にします。

![スクリーンショット 2021-01-28 16.15.50.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/555a2c30-980b-cf26-df03-ec531f2110f2.jpeg)

ここまで設定してから、「OK」を押し、データの結合を完了します。

## QGIS上での人口データの表示

この項は必須ではないのですが、QGISに読み込んだ人口データのQGIS上の表示を下図のように整えます。

![スクリーンショット 2021-01-28 16.33.28.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/88210fe1-de11-bc7d-e1ed-6154b4158281.jpeg)

まずは、プロパティから「シンボロジ」を選択し、種類を「連続値による定義」、値を「population」、「カラーランプ」として適当なグラデーションを選びます。「モード」や「クラス」はデータに応じて適当に設定してください。また、不透明度を設定します。

![スクリーンショット 2021-01-28 16.16.59.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/3dd79a5b-66f3-6354-84c3-5cc9e348aa59.jpeg)

私は更にここから、「シンボル」→「シンプル塗りつぶし」→「ストロークスタイル」を「ペンなし」に設定します。

![スクリーンショット 2021-01-28 16.42.47.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/c36be2f6-b193-0fc3-8f85-602e346d0300.jpeg)

次に、プロパティの「ラベル」から「単一定義（single）」をえらび、値として「population」を設定します。拡大したときだけ数字が表示されるように、レンダリングのラベルオプションの「縮尺に応じた表示設定」を有効にし、最少縮尺を1:25000くらいに設定します。

![スクリーンショット 2021-01-28 16.47.31.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/8aa36ced-31b0-683f-bf92-2f93ad0d1d8c.jpeg)

あとは、背景地図として地理院地図などを設定することで、QGISにて地図と重ねた人口の表示が可能になります。


## PostGISに読み込ませるためのデータ書きだし（初回）

国勢調査データを、PostGISに読み込みやすいPostgreSQL SQL dump形式で書き出します。Shapeファイルなど、寄り汎用的な規格で書き出す方法もありますが、データ投入を目的とする場合は、このやり方がいちばん素直だと思います。


まずは、人口レイヤを右クリックして「エクスポート」→「地物の保存」を選びます。

![スクリーンショット 2021-01-28 17.00.11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/044efc6a-e369-ba70-930e-8b66ca2ca6ef.jpeg)

「ベクタレイヤを名前を付けて保存」というウィンドウが出てくるので、形式を「PostgreSQL SQL dump」にします。書き出す**ファイル名は、SQLに読み込んだときのテーブル名になる**ようなので、それも考慮して適切に設定します。「レイヤ名」の欄があるのですが、今は入力できないようになっています。参照座標系（CRS）は、元データのままなら`EPSG:4612 (JGD2000)`なのですが、データベースに投入した後、他のデータと組み合わせて処理することを考えると、ここで`EPSG:4326 (WGS84)`に変更してしまってもいいかもしれません。

![スクリーンショット 2021-01-28 17.02.42.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/96e1d4a4-539f-45b4-7424-a2cc74b0ae8a.jpeg)


## データベースへの読み込み

まずは、投入する先のデータベースを作成します。`createdb`コマンドでデータベースを作成し、そのデータベースにログインした状態で、`create extension postgis;` とすることで、PostGIS拡張を有効にします。

```bash:データベース作成
$ createdb census-2015
$ psql -d census-2015
psql (13.1)
Type "help" for help.

census-2015=# create extension postgis;
CREATE EXTENSION
census-2015=# \q
$
```


つぎに、実際にデータを投入します。`-f`オプションに続いて、QGISから書き出したファイル名を指定することで、データが投入できます。データ投入作業は少し時間がかかります。また、この段階でindex（空間indexも含む）も作成されます。

```bash:データ投入
$ psql -d census-2015 -f population.sql 
```

## PostGISに読み込ませるためのデータ書きだし（2回目以降）

複数の領域のデータを投入する場合、PostGISの同じテーブルに複数のエリアのデータを書き込みたいことがあると思います。この場合は、二回目以降はSQL dumpの際の設定を少し変え、データの追記が出来るようにします。具体的には、`CREATE_SCHEMA`、`CREATE_TABLE`、`DROP_TABLE`を全て``NO``にします。さらに、ファイル名がレイヤ名に使われるという仕様上、ファイル名は初回のファイルと同一にする必要があります。

![スクリーンショット 2021-01-28 17.45.09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/ecd92abf-6e1d-8eba-953b-4c95059fc8a7.jpeg)

このようにして書き出したファイルを、初回と同様にデータ投入します。

## データの確認

最後に、投入されたデータを確認します。pgAdmin 4で確認してみると、エリアごとのメッシュが作られ、値として人口データが投入されていることが分かります。あとは、GISでの視覚化やデータ分析などでデータをご活用下さい。

![スクリーンショット 2021-01-28 18.14.42.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53416/167c8d48-0a21-b4cc-7fb0-89f5c7b192d9.jpeg)