🔖

交通事故統計情報のオープンデータの緯度経度について

2024/03/17に公開

警察庁の交通事故統計情報のオープンデータに含まれるの緯度経度について
データをマッピングする際に桁数の分け方でちょっと苦労したのでメモします。
https://www.npa.go.jp/publications/statistics/koutsuu/opendata/index_opendata.html

定義書

緯度経度データの定義には以下のように書いてあります。

項目名 地点 緯度(北緯)
説明 交通事故が発生した場所の緯度をいう。 緯度は世界測地系(度分秒)とする。
項目名 地点 経度(東経)
説明 交通事故が発生した場所の経度をいう。経度は世界測地系(度分秒)とする。

実際のデータ

実際のデータは次のような形式で入っています。
地点_緯度(北緯) : 9桁固定長文字列(例:333440727)
地点_経度(東経) : 10桁固定長文字列(例:1302240656)

桁毎の意味

地点_緯度(北緯) :ddmmss.sss
地点_経度(東経) :dddmmss.sss
(d度、m分、s秒)

GIS系の人には常識なのかもしれませんが、上記のような区切りになっていました。
そこで、緯度は、2桁、2桁、5桁で区切り、経度は、3桁、2桁、5桁で区切ります。
それを60進数から10進数に変換します。秒のところがポイントで

sssss/3600000

で計算します。

下記は、ChatGPTに作ってもらったサンプルコード(Python)です。
foliumとpandasをインストールしていない場合は、pipでインストールしてください。

pip install folium
pip install pandas
import folium
import pandas as pd

# Adjusted function to convert from the specific DMS formats to decimal degrees
def convert_dms_to_dd(dms, is_longitude=False):
    # Adding leading zeros to ensure correct string length
    dms_str = str(dms).zfill(10) if is_longitude else str(dms).zfill(9)
    if is_longitude:
        degrees = int(dms_str[:3])
        minutes = int(dms_str[3:5])
        seconds = float(dms_str[5:])
    else:
        degrees = int(dms_str[:2])
        minutes = int(dms_str[2:4])
        seconds = float(dms_str[4:])
    
    return degrees + (minutes / 60.0) + (seconds / 3600000.0)

# Load the data
csv_file_path = 'honhyo_2022.csv'
data_df = pd.read_csv(csv_file_path, encoding='cp932')

# Filter for specific prefectural and municipality codes
prefecture_code = 90
municipality_code = 133
filtered_data = data_df[(data_df['都道府県コード'] == prefecture_code) & (data_df['市区町村コード'] == municipality_code)]

# Apply conversion from DMS to decimal degrees
filtered_data['latitude'] = filtered_data['地点 緯度(北緯)'].apply(lambda x: convert_dms_to_dd(x))
filtered_data['longitude'] = filtered_data['地点 経度(東経)'].apply(lambda x: convert_dms_to_dd(x, is_longitude=True))

# Create a map centered around the average location
map_center = [filtered_data['latitude'].mean(), filtered_data['longitude'].mean()]
m = folium.Map(location=map_center, zoom_start=12)

# Add markers for each accident location
for idx, row in filtered_data.iterrows():
    folium.Marker([row['latitude'], row['longitude']], popup='Accident').add_to(m)

# Save or show the map
m.save('accident_map_dms.html')  # Saves the map to an HTML file

Discussion