まずは隗よりDX(第1回)人口密度を出してみる(前半)
タイトルは「先づ隗より始めよ」という格言のもじりです。
古代の中国北部に燕(えん)という国があり、そこの王様は優秀な人物を求めていました。
そこに、隗(かい)という男が訪れ、「優秀な人物を集めるために、まずは自分程度の平凡な者を登用してみて下さい」と述べたそうです。
その逸話から、「先づ隗より始めよ」という格言が、「壮大な事業を始めるには、まず簡単なことから着手しろ(または、言い出した者から着手しろ)」という意味で用いられるようになりました。
最近は、「地方自治体のデジタル化」という目標が掲げられがちですが、具体的に何をすべきか、いまひとつ分からない部分があります。正直、自分は全然分かっていませんし、市政に関わるほとんど全員が、まだ不十分な理解にとどまっている気がします。
そこで、実践を通して理解を深めることにしました。
(1)課題の設定から始めよう
『イシューからはじめよ』という本でも有名になったように、どんな仕事でも解決すべき課題を発見することが大事です。
プログラミングやDXは、所詮は「手段」ですから、「目的」の解決に利用するものです。
手段を勉強すること自体が目的になると、それが何の役に立つか実感できず、非常につまらないです。
つまらないとすぐやめてしまうので、結局何も身に付かない。自分の経験を振り返ってみても、身に付かなかったプログラミング言語は、たいてい勉強すること自体が目的になっていました。
今回は、町丁字(たとえば「紙敷1丁目」など)ごとの人口密度を出してみます。これは、町の性質を知るのに必要なデータなのですが、自分が見た限りでは、松戸市のウェブサイトに掲載されていませんでした。
「必要なのに無くて困る」というイライラ感が、解決すべき課題(目的)を発見するカギです。
今回は、「町丁字ごとの人口密度のデータが必要なのに、無くて困る。だから、町丁字ごとの人口密度のデータを算出したい」
この解決が目的になります。
人口密度は、面積と人口から計算できます。
手作業で地道に計算してもいいのですが、めちゃくちゃ時間がかかります(松戸市内の町丁字は250くらいあります)。
その手間を省くのがコンピュータの本来の仕事です。余談ですが、「コンピュータ(computer)」は「計算機」という意味です。ウェブサイトを表示するのは、本来は「おまけ」的な機能でした。
簡単に言うと、同じ公式で繰り返し行う計算を一瞬で終わらせることが、プログラミングやDXという手段の本質です。
「必要な手作業が多すぎる」という面倒くささが、プログラミングという手段を選ぶカギになります。
まとめ:
・プログラミングやDXは、手段にすぎない
・まずは解決すべき課題を見つける
・プログラミングという手段は、イライラ感と面倒くささから生まれる
(2)利用するデータ
さて、上で述べたように、人口密度は、面積と人口から計算できます。
町丁字ごとの人口密度を求めるには、町丁字ごとの面積と、町丁字ごとの人口が必要です。
(2-1)町丁字ごとの人口
町丁字ごとの人口は、松戸市のウェブサイトに載っていました。
縦軸が町丁字の名前、横軸が性別・年齢ごとの人口です。
これで、町丁字ごとの人口は手に入りました。
(2-2)町丁字ごとの面積
これは、市のサイトに載っていないようです(自分が見落としているのかも知れません)。
当初、正確な人口密度はどうしても計算できないと諦め、地図から大まかな面積を計算して、概算値を出していました(イライラ感と面倒くささに耐えての力技は、プログラマーにとっては美徳になりません)
ところが最近、おもしろいサイトを発見しました。
(沖縄県八重山郡と表示されてしまいますが、千葉のページに繋がってます)
「Geoshapeリポジトリ」というプロジェクトによって、デジタルな地図上で活用できるデータがまとめられています。
12207は松戸市のコード(マイナンバーみたいなもの)です。
右端のTopoJSONは、JSONというデータ形式で地図情報をまとめたものです(ここでは深く立ち入りません。簡単に言うと、「人口:300人」のように、数値と名札を一対一対応させたデータの集合体です)
さて、ここまで来ればあとは簡単……と思いきや、
TopoJSON、人間にとっては、なかなかハードな形式です。
コンピュータを通した作業には便利なのですが……
(3)データを観察する
段落を区切って心機一転、TopoJSONを読み解いてみましょう。
TopoJSONはJSONの一種。
JSONは、こんな形式です。
{
"id": 1,
"name": "tanaka",
"attribute": {
"gender": "male",
"phone_number": "xxxxxxxxxxx",
"birth": "1991/01/01"
}
}
先述したように、「名札:数値」が対応しています。
数学の「x=1」のようなものです。
もうちょっと分りやすく、具体的な例にしましょう。
バーモントカレーの材料で考えてみます。
・バーモントカレー<甘口>…1/2箱(115g)
・牛肉(角切り)…250g
・玉ねぎ(中)…2個(400g)
・じゃがいも(中)…1・1/2個(230g)
・にんじん(中)…1/2本(100g)
・サラダ油…大さじ1
・水…850ml
これをコンピュータが扱いやすい統一規格で表すと、
{
"バーモントカレーのルウ": 115,
"牛肉": 250,
"野菜": {
"玉ねぎ": 400,
"じゃがいも": 230,
"にんじん": 100
}
"サラダ油":1,
"水":850
}
こんな感じです。
(プロの方から見ると、説明に色々と突っ込み所が多いでしょうが、今日は「初めてプログラミング言語を見た」という方にイメージを豊かにしてもらうことが目標なので、大目に見てください)
上のコードを観察していると、
{ } はJSONを囲む記号
JSONの中に、より小さなJSONを入れ子にできる。それも { } でくくる
: は名札と数値の対応関係を示す記号(数学でx=1と書くようなもの)
, (カンマ)は「名札:数値」のペアを並列に並べるときの記号
だと分かります。
さて、この基礎知識を抑えたうえで、先ほどの巨大なTopoJSONを紐解いていきましょう。
あれを手元のエディターにコピペして、改行してみました。
ちなみに、「エディター」とは、一般に文章を書くソフトを言います。「メモ帳」や「Word」などです。ただ、プログラミングの文脈では、特にプログラミング言語を打ち込むソフトを指して言うことが多いです。
元のデータをコピペし、改行する作業だけなら、パソコンに最初から入っている「メモ帳」でもできます。
ただ、プログラミング専用のエディターだと、自動で文法を解釈して、色分けしてくれるので便利です。
先ほど発見した、
{ } はJSONを囲む記号
: は名札と数値の対応関係を示す記号
, は「名札:数値」のペアを並列に並べるときの記号
という文法を踏まえて、改行し、入れ子になってる部分は段落を一段落とすと、非常にスッキリしますね。
どうやら、"town"という名札に対応して、入れ子のJSONがあり、その中には "geometryCollection"という形式で、町丁字ごとのデータが格納されているようです。
そして、町丁字ごとのデータには "properties (性質)"という名札のもと、さらに小さな入れ子のJSONが。
そこには、町丁字ごとの名前、コード番号、面積、人口、世帯数など重要なデータが整理されています。
こうして整理すると非常に分かり良く、宝の山を発見した海賊のような気分になります。
さて、ここから町丁字のデータを抽出しましょう。
人間にとって面倒だけど、同じ公式を繰り返せば終わる作業。ここでプログラミング言語が本領を発揮します。
(4)プログラミングの威力を知る
必要なコードをあらかじめ準備しておきました。
今回は、詳しい内容に立ち入りません。かいつまんで説明します。
(4-1)function って何だ?
ここでは、 function を作っています。function は、ふつう「関数」と訳されます。また、「機能」という意味でもあります。
プログラミング言語で繰り返し行う処理は、「関数」にしてしまうのです。
そうすると、関数の名前を呼ぶだけで、複雑な処理を何度でもやってもらえます。
またまたカレーに喩えると、
function 野菜を切る(野菜){
(野菜)を掴む
まな板に(野菜)を置く
包丁を取る
包丁を(野菜)に押し当てて、引く
}
と定義しておけば、
「野菜を切る(にんじん)」と書くと、一瞬で「にんじんを掴む→まな板ににんじんを置く→包丁を取る→包丁をにんじんに押し当てて、引く」をやってもらえます。
同様に、「野菜を切る(玉ねぎ)」と書くと、「玉ねぎを掴む→まな板に玉ねぎを置く→包丁を取る→包丁を玉ねぎに押し当てて、引く」ができます。
一旦「野菜を切る」関数を定義してしまえば、どんな野菜にも対応できます。季節限定メニューでナスを使うことになっても、「野菜を切る(ナス)」と書くだけなので、楽々対応できます。
また、カレー以外の料理を作るときにも転用できます。
先ほどから述べている「同じ公式を繰り返せば終わる作業」を素早く片付ける技術は、この関数(function)に支えられています。
(4-2)for って何だ?
もうひとつ、 for だけ扱って今回は終わりにします。
ここでの for は、「~のために」という意味ではなく、「(ある条件)まで」という意味です。
今日は覚えていただかなくても大丈夫ですが、
for (i=0; i<1000; i++){
処理X
}
この構文を使うと、「i=0から、iを1つずつ増やしていく。iが1000未満の間は、処理Xを繰り返す」という意味になります。
要は、同じ処理Xを1000回繰り返すことができます。
カレーの場合、
for (i=0; i<玉ねぎの個数; i++){
野菜を切る(玉ねぎ)
}
これで全ての玉ねぎを一瞬で切ることができます。
まとめ:
プログラミング言語を用いると、関数や for 文のおかげで、繰り返し処理を一瞬で終わらせられる
(4の補足)
ここは読み飛ばしても大丈夫です。気になる方のために、先ほどのコードを一応ざっと説明します。
全体像は、このようになっています。
function myFunction() {
const URL = "https://geoshape.ex.nii.ac.jp/ka/topojson/12/h27ka12207.topojson";
var dataText = UrlFetchApp.fetch(URL).getContentText();
var dataJson = JSON.parse(dataText);
var preTowns = dataJson['objects']['town']['geometries'];
var postTowns = new Array (preTowns.length);
const SSID = '■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■';
var sheet = SpreadsheetApp.openById(SSID).getSheets()[0];
for (i=0; i<postTowns.length; i++){
postTowns[i] = new Array (5);
postTowns[i][0] = preTowns[i]['properties']["KEY_CODE"];
postTowns[i][1] = preTowns[i]['properties']["S_NAME"];
postTowns[i][2] = preTowns[i]['properties']["AREA"];
postTowns[i][3] = preTowns[i]['properties']["JINKO"];
postTowns[i][4] = preTowns[i]['properties']["SETAI"];
sheet.appendRow(postTowns[i]);
}
}
まず、
function myFunction() {
この中で、この関数が行う処理を定義している
}
がこのコードの大きな構造です。
そして、その中は上・中・下に分かれています。
「上」の部分では、
const URL = "https://geoshape.ex.nii.ac.jp/ka/topojson/12/h27ka12207.topojson";
var dataText = UrlFetchApp.fetch(URL).getContentText();
var dataJson = JSON.parse(dataText);
var preTowns = dataJson['objects']['town']['geometries'];
topojson (前の段落で述べた、巨大な地図データの羅列) をインターネットから呼んできて、'geometries' 以降の部分だけをコピペする。
そうすると、欲しかった町丁字のデータだけが手元に残る。
先ほどの図のうち、この部分です(↓ 赤枠の中)。
そして、「中」の部分は、
var postTowns = new Array (preTowns.length);
const SSID = '■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■';
var sheet = SpreadsheetApp.openById(SSID).getSheets()[0];
最初の行では、扱いやすい形の「箱」の集合を作りました。
new Array という構文で、配列(array)を作れます。
「配列」とは、同じ形式の箱の集合体です。
今の段階では、こういうイメージで大丈夫です。
同じ大きさの小さなお皿に、JSONのデータを取り分けていきます。
2行目・3行目では、自分のGoogle スプレッドシートのIDを渡して、データを整理する表を準備しました。
「下」の部分では、
for (i=0; i<postTowns.length; i++){
postTowns[i] = new Array (5);
postTowns[i][0] = preTowns[i]['properties']["KEY_CODE"];
postTowns[i][1] = preTowns[i]['properties']["S_NAME"];
postTowns[i][2] = preTowns[i]['properties']["AREA"];
postTowns[i][3] = preTowns[i]['properties']["JINKO"];
postTowns[i][4] = preTowns[i]['properties']["SETAI"];
sheet.appendRow(postTowns[i]);
}
配列にデータを入れ(=お皿にカレーを盛り付け)、それをスプレッドシートに書き込んでいます。
ここでは、for 文に250周くらい(町丁字の数だけ)作業してもらっています。
こういった、単純作業の繰り返しは、プログラミング言語が本領発揮する場面です。
(4-3)結果
できました。
これで、町丁字ごとの面積が分かります。
(2-1)で手に入れた、町丁字ごとの最新の人口と合わせれば、人口密度を求められるはず。
ここから先は、後編で解説します。
今日はここまでとします。読んでくださり、ありがとうございました。