データサイエンス

foliumで位置情報を可視化

foliumは地図上に位置情報をマッピングできるPythonのパッケージです。
このページでは、前回スマホで取得した位置情報履歴をfoliumで可視化します。

位置情報のプロット

位置情報はテーブルデータ形式ですが、データに間違いがないかや処理が正しいかを確認するためには、地図上にプロットするのが最適です。
Pythonのfoliumパッケージを使用することで、OpenStreetMap上に位置情報をマッピングできます。

可視化結果

foliumにより位置情報を速度別に色を変えて地図上にマッピングした結果。渋谷駅と新橋駅の間を鉄道(JR山手線)と路線バス(都01系統)で移動した際の位置情報をマッピングした結果である。背景の地図はオープンライセンスのOpenStreetMapを使用している。渋谷駅と新橋駅周辺では乗り換え等のために歩いているため黒色(停止)や緑色(徒歩)のプロットが多数存在している。交通機関により移動速度が異なるため、路線バス乗車中は青色、鉄道乗車中は赤色になっている。鉄道は急に止まれないため、駅周辺は加減速や停止状態のプロットが存在する。地下区間で位置情報を取得できないため、山手線の渋谷ー目黒間では位置情報のプロットが途絶えている箇所がある。

上の画像は、GPS2CSVというiPhoneのアプリを使用して取得した位置情報をfoliumを使用してOpenStreetMapの地図上にマッピングしたものです。
データは渋谷駅と新橋駅の間を鉄道(JR山手線)と路線バス(都01系統)で移動した際の移動履歴を使用しています。

交通手段がわかるように速度別に色分けしてプロットしています。
渋谷駅と新橋駅周辺の黒色(0km/h)や緑色(≦10km/h)は乗り換えの際の徒歩移動です。
路線バスは鉄道より低速なので、ほぼ全区間で青色(≦50km/h)になっており、バス停や信号前後でわずかに緑色(≦10km/h)のプロットが見られます。
鉄道での移動は路線バスより高速であり、駅間では赤色(>50km/h)になっていますが、駅前後の加減速区間が長いため、駅前後では青色(≦50km/h)の区間もそれなりに見られます。

ちなみに、山手線西側の渋谷ー目黒間で位置情報が途絶えているのは、地下区間を通るためです。
携帯電話の電波が届いていても地下区間では位置情報を確認できず、プロットが途絶えています。
このため、地下鉄での移動時は位置情報を取得できずにプロットが飛ぶため、位置情報の追跡が困難です。

地上区間であっても、障害物などでGPSの精度が悪化する場合は位置情報がズレます。
たとえば、中央上部の「霞が関」の文字の左下の溜池交差点付近では、道路の上を首都高が走っているため実際の走行経路からずれています。

以上のように位置情報を速度別に取得することで、位置情報履歴から交通手段の特定ができます。
今回の場合は路線バスと鉄道の走行ルートが大きく異なるため、見た目でもどちらで移動しているかはわかりますが、電車と道路が並行している場合でも速度別に見ると交通手段を推定することができます。

【参考】コード

以下ではfolium関数を使用して位置情報を可視化したコードです。
データはこちらのページで取得したスマホの位置情報を可視化したものです。

Python
import pandas as pd
import geopandas as gpd
import numpy as np
import re
import folium # マッピング用
# データの読み込み
file_path = '../00_data/GPS_241109_SJIS_LF.CSV'
df = pd.read_csv(file_path, encoding='cp932')
# 日付情報の取得
regex = '../00_data/GPS_([0-9]{6})_SJIS_LF.CSV'
date = re.sub(regex, r'\1', file_path)

# 関数定義:速度に応じて色を返す
def speed2color(speed):
    if speed == 0: # 停止
        c = 'black'
    elif speed <= 10: # 徒歩
        c = 'green'
    elif speed <= 50: # 路線バス
        c = 'blue'
    else:
        c = 'red' # 鉄道
    return c

# 関数定義:foliumで地図上に位置情報をプロット
def mapping_apply(df):
    # デフォルトの中心とズーム
    default_location = [df['lat'].mean(), df['lng'].mean()]
    default_zomm = 12
    # foliumで地図を表示
    folium_map = folium.Map(
        location=default_location,
        zoom_start=default_zomm
        )
    # apply関数で各行の位置情報を地図上にプロット
    df.apply(lambda row: folium.Circle(
        location=[row['lat'], row['lng']],
        color=speed2color(row['速度']),
        radius=5,
        ).add_to(folium_map), axis=1)
    return folium_map

# 地図上に位置情報をマッピング
folium_map = mapping_apply(df=df)
display(folium_map)

# マッピング結果の出力
out_path = f'../02_work/01_移動履歴生データマッピング/01_移動履歴生データマッピング_{date}.html'
folium_map.save(out_path)

参考文献

Folium 0.18.0 documentation, folium 2024/11/18閲覧
foliumの基本的な使い方とオープンデータ活用 Qiita 2024/11/18閲覧

-データサイエンス
-, , , , , ,