犯罪統計や交通事故のジオコーディング

Python

ジオコーディングが簡単にできるライブラリの話は先日書いた。

千葉県警が犯罪発生情報をオープンデータとして配布している。まあオープンデータにするなら、文字コードはUTF-8に改行コードはLFにしておいてほしいが、配布されているファイルはSJIS + CRLFなので、適当なツールでUTF-8 + LFにしてから以下の適当なPythonに通せば、Googleマップにレイヤーとして載せられる。row[2]は抜き出したい警察署の名前をいれてください。

#!/usr/bin/python3

import csv
import json
import jageocoder

jageocoder.init()

with open(f'crimes.csv', 'w') as output_file:
    writer = csv.writer(output_file, quoting=csv.QUOTE_ALL)
    writer.writerow(['WKT','名前','説明'])

    for file in ['オートバイ盗', 'ひったくり', '自転車盗', '自動車盗', '自動販売機ねらい', '車上ねらい', '部品ねらい']:
        with open(f'{file}.csv') as input_file:
            reader = csv.reader(input_file)
            death = []
            injury = []
            for row in reader:
                if row[2] == '市川':
                    results = jageocoder.search(row[5] + row[6] + row[7])
                    lon, lat = results['candidates'][0]['x'], results['candidates'][0]['y']
                    writer.writerow([f'POINT ({lon} {lat})',f'{file}'])

一方で、警察庁は交通事故統計をオープンデータとして配布している。こちらは「本票」となっているファイルに交通事故の詳細データが入っているので、以下のようなPythonで抜き出して、こちらもGoogleマップに載せられる。row[1]で都道府県コード、row[2]で警察署コードを指定できるので、同じページで配布されている各種コード表を参照して、抜き出したい都道府県・警察署を指定してくだされ。

#!/usr/bin/python3

import csv
import math
from decimal import Decimal, ROUND_HALF_UP

year=2021

def dms2deg(dms):
    # 度分秒から度への変換
    print(dms)
    h = int(dms[0])
    m = int(dms[1])
    s = float(dms[2])
    deg = Decimal(str(h + (m / 60) + (s / 3600))).quantize(Decimal('0.0001'), rounding=ROUND_HALF_UP)
    return deg

def deg2dms(deg):
    # 度から度分秒への変換
    h = math.modf(deg)[1]
    m = math.modf(math.modf(deg)[0] * 60)[1]
    s = math.modf(math.modf(deg)[0] * 60)[0]*60
    if Decimal(str(s)).quantize(Decimal('0'), rounding=ROUND_HALF_UP) == 60:
        s = 0
        m = m + 1
    if Decimal(str(m)).quantize(Decimal('0'), rounding=ROUND_HALF_UP) == 60:
        m = 0
        h = h + 1
    dms_tap = (int(Decimal(h).quantize(Decimal('0'), rounding=ROUND_HALF_UP)),
                int(Decimal(m).quantize(Decimal('0'), rounding=ROUND_HALF_UP)),
                int(Decimal(s).quantize(Decimal('0'), rounding=ROUND_HALF_UP)))
    return dms_tap

with open(f'honhyo_{year}.csv') as f:
    reader = csv.reader(f)
    death = []
    injury = []
    for row in reader:
        if row[1] == '44': #千葉県
            if row[2] == '105': #市川警察署
                lat = dms2deg([row[54][0:2], row[54][2:4], row[54][4:6] + '.' + row[54][6:]])
                lon = dms2deg([row[55][0:3], row[55][3:5], row[55][5:7] + '.' + row[55][7:]])
                if int(row[5]) >= 1: #死亡事故
                    death.append([lat, lon])
                else: #負傷事故
                    injury.append([lat, lon])

with open(f'death_{year}.csv', 'w') as f:
    writer = csv.writer(f, quoting=csv.QUOTE_ALL)
    writer.writerow(['WKT','名前','説明'])
    for lat,lon in death:
        writer.writerow(['POINT ({} {})'.format(lon,lat),f'死亡事故({year}年)'])

with open(f'injury_{year}.csv', 'w') as f:
    writer = csv.writer(f, quoting=csv.QUOTE_ALL)
    writer.writerow(['WKT','名前','説明'])
    for lat,lon in injury:
        writer.writerow(['POINT ({} {})'.format(lon,lat),f'負傷事故({year}年)'])

こんな感じに見ることが可能。