PR

Pythonで旅行モデルコースを自動生成する|距離・移動時間から最適ルートを作る方法

本ページにはプロモーションが含まれます。

python-travel-route-generator プログラミング
スポンサーリンク

旅行のモデルコースを作るとき、どの順番でスポットを回ると効率的なのか、徒歩で移動できる距離なのか、どれくらい時間がかかるのかといった判断は意外と難しいものです。情報を調べながら地図を見比べ、距離を計算し、移動時間を推測する作業は、慣れていないと時間がかかります。

しかし Python を使えば、スポットの位置情報から距離を計算し、移動時間を算出し、最短ルートを自動で並べ替えることで、現実的なモデルコースを自動生成できます。この記事では、前回作成した folium の旅行地図を活用しながら、距離と移動時間をもとに「最適な旅の順番」を自動で決める方法を丁寧に解説します。

旅行ブログの質を高めたい方や、効率的な旅程を作りたい方、Python を使って旅行計画を自動化してみたい方に役立つ内容です。

旅行モデルコースを自動生成するとは?

旅行の計画を立てるとき、どの順番でスポットを回ると効率的なのか、徒歩で移動できる距離なのか、どれくらい時間がかかるのかといった判断は、思っている以上に手間がかかります。地図を開きながら距離を調べ、移動時間を推測し、順番を入れ替えながら最適なルートを探す作業は、慣れていないと時間がかかり、感覚に頼ってしまうことも少なくありません。

しかし、Python を使えばこの作業を自動化できます。スポットの位置情報から距離を計算し、移動時間を算出し、最短距離になるようにスポットを並べ替えることで、現実的で効率の良いモデルコースを自動生成できます。旅行計画の「なんとなく」を「データに基づいた判断」に変えることができるのが、Python を使う大きなメリットです。

本記事では、前回作成した folium の旅行地図で扱ったスポット情報や距離計算を活用しながら、Python で旅行モデルコースを自動生成する方法を丁寧に解説します。旅行ブログの質を高めたい方、効率的な旅程を作りたい方、あるいは Python を使って旅行計画を自動化してみたい方に役立つ内容です。

モデルコース自動生成の基本ロジック

旅行モデルコースを自動生成するためには、まず「どの順番でスポットを回ると効率的か」を決める仕組みが必要になります。人が手作業で旅程を作る場合、地図を見ながら距離を調べ、移動時間を推測し、順番を入れ替えながら最適なルートを探します。しかし、この作業は時間がかかり、感覚に頼ってしまうことも多いのが実情です。

Python を使うと、この「順番決め」をデータに基づいて自動化できます。スポットの緯度・経度から距離を計算し、移動時間を算出し、最も近いスポットを順番に選んでいくことで、無駄の少ないルートを作ることができます。これは旅行計画における“最適化”の基本的な考え方であり、シンプルながら実用性が高い方法です。

距離と移動時間を使う理由

旅行の順番を決める際に最も重要なのは、スポット間の距離と移動時間です。距離が短ければ移動が楽になり、移動時間が短ければ1日に回れるスポット数が増えます。特に都市部の観光では、徒歩で移動できる範囲かどうかが旅の快適さに直結します。

Python では geopy を使うことで、緯度・経度から正確な距離を計算できます。さらに、徒歩・自転車・車などの移動速度を設定することで、移動時間も自動で算出できます。これらの情報を組み合わせることで、現実的な旅程を作るための基礎データが揃います。

最短距離で並べ替える「近い順アルゴリズム」

今回の記事では、最もシンプルで理解しやすい「近い順アルゴリズム」を使います。これは、現在いるスポットから最も近いスポットを次の目的地に選び、残りのスポットがなくなるまで繰り返す方法です。

この方法は、旅行計画において非常に実用的です。複雑な最適化アルゴリズムを使わなくても、都市観光や半日〜1日のモデルコースであれば十分に効率的なルートが作れます。Python での実装も簡単で、コードが短く、初心者でも理解しやすいのが特徴です。

旅行計画における“順番の最適化”とは

旅行の順番を最適化するということは、単に距離を短くするだけではありません。移動時間、歩きやすさ、スポットの滞在時間、開館時間など、複数の要素が関係します。今回の記事では距離と移動時間に焦点を当てていますが、Python を使えばこれらの要素を追加して、より高度なモデルコースを作ることも可能です。

まずは「距離と移動時間を使って順番を決める」という基本ロジックを理解することで、旅行計画の自動化がどのように進むのかを実感できるはずです。

スポット情報を準備する

モデルコースを自動生成するためには、まず「どのスポットを回るのか」を Python が理解できる形で整理する必要があります。

旅行計画では、スポット名だけでなく、緯度・経度といった位置情報が欠かせません。

これらをまとめておくことで、距離計算やルート生成がスムーズに行えるようになります。

スポットのデータ構造(名前・緯度・経度)

Python で扱いやすい形にするため、スポットは次のような構造でまとめます。

  • スポット名
  • 緯度(latitude)
  • 経度(longitude)

この3つが揃っていれば、距離計算や地図描画に必要な情報がすべて揃います。

旅行ブログではスポット名だけを扱うことが多いですが、Python でモデルコースを作る場合は「位置情報」が必須になります。

緯度・経度は Google Maps や OpenStreetMap で簡単に調べられます。

Pythonで扱いやすいリスト形式にする

Python では、スポットをリストとしてまとめるのが最もシンプルで扱いやすい方法です。

spots = [
    ["浅草寺", 35.7148, 139.7967],
    ["東京スカイツリー", 35.7100, 139.8107],
    ["上野公園", 35.7142, 139.7730],
    ["築地場外市場", 35.6655, 139.7708]
]

このように、スポットをひとまとめにしておくことで、後の処理(距離計算・ルート生成)が非常に簡単になります。

実際の旅行スポット例(東京観光)

今回は例として、東京の代表的な観光スポットを使います。

  • 浅草寺
  • 東京スカイツリー
  • 上野公園
  • 築地場外市場

いずれも徒歩や電車で移動しやすく、モデルコースの例として扱いやすいスポットです。もちろん、あなたの旅行記事に合わせてスポットを自由に入れ替えることができます。

スポット情報が揃ったら、次は距離と移動時間を計算していきます。

距離と移動時間を計算する

モデルコースを自動生成するためには、スポット同士の距離と移動時間を正確に把握する必要があります。距離が分かれば「歩ける範囲かどうか」が判断でき、移動時間が分かれば「1日で回れるかどうか」が分かります。Python では、緯度・経度から距離を計算できる geopy が非常に便利です。

距離と移動時間は、モデルコース生成の“基礎データ”となる重要な要素です。

geopy のインストール

距離計算には geopy を使用します。

pip install geopy

インストールが完了すると、緯度・経度から地球上の距離を簡単に計算できるようになります。

スポット間の距離を計算する

geopy の geodesic を使うと、2地点間の距離をキロメートル単位で取得できます。

from geopy.distance import geodesic

def calc_distance(a, b):
    return geodesic((a[1], a[2]), (b[1], b[2])).km

この関数は、スポット情報(名前・緯度・経度)を受け取り、距離を返します。

徒歩・自転車・車の移動時間を算出する

距離が分かったら、次は移動時間を計算します。 移動速度の目安は次のとおりです。

  • 徒歩:4 km/h
  • 自転車:15 km/h
  • 車:40 km/h(都市部の平均)

Python では、距離 ÷ 速度 × 60 で移動時間(分)を算出できます。

def calc_time(distance_km, speed_kmh):
    return distance_km / speed_kmh * 60

計算結果の確認方法

スポット一覧を使って、距離と移動時間を計算してみます。

spots = [
    ["浅草寺", 35.7148, 139.7967],
    ["東京スカイツリー", 35.7100, 139.8107],
    ["上野公園", 35.7142, 139.7730],
    ["築地場外市場", 35.6655, 139.7708]
]

for i in range(len(spots) - 1):
    start = spots[i]
    end = spots[i + 1]

    d = calc_distance(start, end)
    walk = calc_time(d, 4)

    print(f"{start[0]} → {end[0]}: {d:.2f} km / 徒歩 {walk:.0f} 分")

このように、距離と移動時間をセットで計算することで、
「歩ける距離なのか」「移動にどれくらい時間がかかるのか」が明確になります。

Pythonで最短ルートを自動生成する

ここまでで、スポット情報・距離・移動時間の計算ができるようになりました。 次のステップは、これらのデータを使って 「どの順番で回ると効率的か」 を自動で決めることです。

旅行計画では、順番を決める作業が最も時間のかかる部分ですが、Python を使えばこの工程をシンプルなロジックで自動化できます。

近いスポットを順番に選ぶアルゴリズム

今回採用するのは、旅行計画で最も実用的な 近い順アルゴリズム です。

  1. 最初のスポットをスタート地点とする
  2. 現在地から最も近いスポットを次の目的地に選ぶ
  3. 残りのスポットがなくなるまで繰り返す

この方法は、都市観光や半日〜1日のモデルコースで特に効果的です。 複雑な最適化アルゴリズムを使わなくても、十分に効率的なルートが作れます。

Pythonコード(コピペOK)

以下は、スポットを最短距離順に並べ替える完全なコードです。

from geopy.distance import geodesic

# スポット一覧(名前, 緯度, 経度)
spots = [
    ["浅草寺", 35.7148, 139.7967],
    ["東京スカイツリー", 35.7100, 139.8107],
    ["上野公園", 35.7142, 139.7730],
    ["築地場外市場", 35.6655, 139.7708]
]

# 距離計算関数
def calc_distance(a, b):
    return geodesic((a[1], a[2]), (b[1], b[2])).km

# 最短距離で並べ替える
def generate_route(spots):
    route = [spots[0]]  # 最初のスポット
    remaining = spots[1:]

    while remaining:
        last = route[-1]
        next_spot = min(remaining, key=lambda x: calc_distance(last, x))
        route.append(next_spot)
        remaining.remove(next_spot)

    return route

# ルート生成
route = generate_route(spots)

# 結果表示
for i in range(len(route) - 1):
    start = route[i]
    end = route[i + 1]
    d = calc_distance(start, end)
    print(f"{start[0]} → {end[0]}: {d:.2f} km")

自動生成されたモデルコースの出力例

浅草寺 → 東京スカイツリー: 1.50 km
東京スカイツリー → 上野公園: 3.80 km
上野公園 → 築地場外市場: 6.20 km

このように、Python がスポットを「近い順」に並べ替え、
無駄の少ないモデルコースを自動で作成してくれます。

所要時間の合計を計算する

距離だけでなく、移動時間も合計しておくと旅程の現実性が高まります。

def calc_time(distance_km, speed_kmh=4):
    return distance_km / speed_kmh * 60

total_time = 0

for i in range(len(route) - 1):
    d = calc_distance(route[i], route[i+1])
    total_time += calc_time(d)

print(f"総移動時間(徒歩): {total_time:.0f} 分")

これで「1日で回れるかどうか」が判断できます。

folium地図にモデルコースを反映する

Pythonで自動生成したモデルコースは、地図に描画することで一気に「旅行記事として使える形」になります。 読者は地図を見ることで、スポットの位置関係や移動ルートを直感的に理解できるため、旅行ブログの満足度が大きく向上します。

ここでは、前章で作成した route を folium に反映し、 「順番つきのマーカー」と「ルート線」を描く方法をまとめます。

ルート線を地図に描く

まずは、モデルコースの順番どおりに線を引きます。

import folium

# 地図の初期位置(東京駅付近)
m = folium.Map(
    location=[35.6812, 139.7671],
    zoom_start=12,
    tiles=None
)

# OpenTopoMap を追加
folium.TileLayer(
    tiles="https://tile.opentopomap.org/{z}/{x}/{y}.png",
    attr="© OpenTopoMap (CC-BY-SA)",
    name="OpenTopoMap"
).add_to(m)

# ルート線の座標
route_coords = [(lat, lon) for _, lat, lon in route]

# ルート線を描く
folium.PolyLine(
    locations=route_coords,
    color="red",
    weight=6,
    opacity=0.8
).add_to(m)

赤い線でルートを描くことで、
「どの順番で移動するのか」がひと目で分かるようになります。

順番つきマーカーを追加する

モデルコースは「順番」が重要なので、
マーカーに番号をつけて表示します。

for idx, (name, lat, lon) in enumerate(route, start=1):
    folium.Marker(
        location=[lat, lon],
        popup=f"{idx}. {name}",
        icon=folium.Icon(color="blue")
    ).add_to(m)

これで、

  1. 浅草寺
  2. 東京スカイツリー
  3. 上野公園
  4. 築地場外市場

のように、順番つきで表示されます。

ポップアップに距離・移動時間を入れる

読者にとって便利なのは、
「次のスポットまで何分かかるか」が分かることです。

def calc_time(distance_km, speed_kmh=4):
    return distance_km / speed_kmh * 60

for i in range(len(route) - 1):
    start = route[i]
    end = route[i + 1]

    d = calc_distance(start, end)
    t = calc_time(d)

    folium.Popup(f"{start[0]} → {end[0]}: {d:.2f} km / 徒歩 {t:.0f} 分")

これをマーカーや線に組み込むことで、
「移動の負担」まで地図上で把握できるようになります。

地図を保存する

最後に、地図をHTMLとして保存します。

m.save("tokyo_auto_route.html")

各スポットをクリックすると、下図のようにポップアップが表示されます。

folium07_

応用編|テーマ別モデルコースを自動生成する

ここまでで、Python を使って「最短距離で効率よく回るモデルコース」を自動生成できるようになりました。 しかし、実際の旅行では「効率」だけでなく、旅のテーマによって最適な順番が変わることがあります。

  • グルメ中心で回りたい
  • カフェを巡りたい
  • 歩きやすいルートにしたい
  • 家族向けに移動距離を短くしたい

こうしたテーマ別のモデルコースも、Python の条件分岐を使えば簡単に自動生成できます。

テーマ別モデルコースの考え方

テーマ別モデルコースを作るには、スポットに「タグ」を付けて分類します。

例:

  • グルメ:"food"
  • カフェ:"cafe"
  • 観光:"sightseeing"
  • 歩きやすい:距離が短いスポットだけ選ぶ

Python では、タグを使ってスポットをフィルタリングし、 その後に「近い順アルゴリズム」を適用することで、テーマ別のルートが作れます。

スポットにタグを追加する

まずはスポット情報にタグを追加します。

spots = [
    ["浅草寺", 35.7148, 139.7967, "sightseeing"],
    ["東京スカイツリー", 35.7100, 139.8107, "sightseeing"],
    ["上野公園", 35.7142, 139.7730, "sightseeing"],
    ["築地場外市場", 35.6655, 139.7708, "food"],
    ["銀座カフェ", 35.6717, 139.7650, "cafe"]
]

タグを追加するだけで、テーマ別のフィルタリングが可能になります。

テーマでスポットを絞り込む

例えば「グルメ中心コース」を作りたい場合は、 food タグのスポットだけを抽出します。

def filter_spots(spots, theme):
    return [s for s in spots if s[3] == theme]

使い方:

food_spots = filter_spots(spots, "food")

同様に、カフェなら "cafe" を指定します。

テーマ別ルートを生成する

フィルタリングしたスポットを、
これまでの「近い順アルゴリズム」に渡すだけでテーマ別ルートが完成します。

food_route = generate_route(food_spots)

カフェなら:

cafe_route = generate_route(filter_spots(spots, "cafe"))

歩きやすいコース(距離制限あり)

距離が短いスポットだけでコースを作ることもできます。

def filter_by_distance(spots, base, max_km=2):
    return [s for s in spots if calc_distance(base, s) <= max_km]

例:浅草寺から半径 2km 以内のスポットだけでコースを作る

easy_spots = filter_by_distance(spots, spots[0], max_km=2)
easy_route = generate_route(easy_spots)

これで「歩きやすいモデルコース」が自動生成できます。

家族向けコース(移動距離を短くする)

家族向けのコースでは、移動距離を短くすることが重要です。

距離が短いスポットを優先するアルゴリズムに変更することもできますが、 まずは「距離が短いスポットだけを選ぶ」方法がシンプルで実用的です。

family_spots = filter_by_distance(spots, spots[0], max_km=3)
family_route = generate_route(family_spots)

テーマ別モデルコースのまとめ

テーマ別モデルコースは、次の流れで簡単に作れます。

  1. スポットにタグを付ける
  2. テーマでスポットをフィルタリングする
  3. 近い順アルゴリズムで並べ替える
  4. folium で地図に描画する

Pythonコード(コピペOK)

今までのコードをまとめたものは下記になります。

from geopy.distance import geodesic
import folium

# ---------------------------------------------------------
# スポット情報(名前, 緯度, 経度, タグ)
# ---------------------------------------------------------
spots = [
    ["築地場外市場", 35.6655, 139.7708, "food"],
    ["月島もんじゃストリート", 35.6645, 139.7840, "food"],
    ["アメ横グルメ街", 35.7112, 139.7745, "food"],
    ["銀座寿司店", 35.6710, 139.7640, "food"],
    ["豊洲市場", 35.6450, 139.7708, "food"]
]

# ---------------------------------------------------------
# 距離計算
# ---------------------------------------------------------
def calc_distance(a, b):
    return geodesic((a[1], a[2]), (b[1], b[2])).km

# ---------------------------------------------------------
# 移動時間計算(徒歩4km/h)
# ---------------------------------------------------------
def calc_time(distance_km, speed_kmh=4):
    return distance_km / speed_kmh * 60

# ---------------------------------------------------------
# 近い順アルゴリズム
# ---------------------------------------------------------
def generate_route(spots):
    best_route = None
    best_total = float("inf")

    # 全スポットを起点にして最短ルートを探す
    for start_index in range(len(spots)):
        route = [spots[start_index]]
        remaining = spots[:start_index] + spots[start_index+1:]

        while remaining:
            last = route[-1]
            next_spot = min(remaining, key=lambda x: calc_distance(last, x))
            route.append(next_spot)
            remaining.remove(next_spot)

        # 総距離を計算
        total = sum(calc_distance(route[i], route[i+1]) for i in range(len(route)-1))

        if total < best_total:
            best_total = total
            best_route = route

    return best_route

# ---------------------------------------------------------
# テーマ別ルート生成(food)
# ---------------------------------------------------------
theme = "food"
filtered = [s for s in spots if s[3] == theme]
route = generate_route(filtered)

# ---------------------------------------------------------
# folium 地図にテーマ別ルートを描画
# ---------------------------------------------------------
m = folium.Map(
    location=[35.6812, 139.7671],
    zoom_start=12,
    tiles=None
)

# OpenTopoMap
folium.TileLayer(
    tiles="https://tile.opentopomap.org/{z}/{x}/{y}.png",
    attr="© OpenTopoMap (CC-BY-SA)",
    name="OpenTopoMap"
).add_to(m)

# ルート線
route_coords = [(lat, lon) for _, lat, lon, _ in route]

folium.PolyLine(
    locations=route_coords,
    color="red",
    weight=6,
    opacity=0.8
).add_to(m)

for idx in range(len(route)):
    name, lat, lon, tag = route[idx]

    # 次のスポットがある場合のみ距離と時間を計算
    if idx < len(route) - 1:
        d = calc_distance(route[idx], route[idx+1])
        t = calc_time(d)
        info = f"{d:.2f} km / 徒歩 {t:.0f} 分"
    else:
        info = "ここが最終スポットです"

    popup_html = f"""
    <div style='width:260px;'>
        <b>{idx+1}. {name} ({tag})</b><br>
        {info}
    </div>
    """

    folium.Marker(
        location=[lat, lon],
        popup=folium.Popup(popup_html, max_width=300),
        icon=folium.Icon(color="blue")
    ).add_to(m)

# 保存
m.save(f"tokyo_route_{theme}.html")

print(f"\n地図を 'tokyo_route_{theme}.html' として保存しました。")

実行すると、以下のような地図が出力されます。
(※銀座のスポットをクリックしてポップアップを表示させた例)

route-gene01

まとめ

Python を使ってモデルコースを自動生成できるようになると、旅の計画がぐっと楽になります。

スポットの位置関係や移動距離をもとに、無駄なく回れる順番を自動で作ってくれるので、「どこから回ればいいんだろう?」と悩む時間が減ります。

さらに、距離や徒歩時間を計算して地図上にルートを描くことで、読者は旅の流れを直感的にイメージできます。

スポットにテーマを付ければ、グルメ中心のコースやカフェ巡りなど、目的に合わせた旅のスタイルも簡単に作れます。

ルートが交差しにくいよう最適化したり、スポット情報を常に表示するラベルを使ったりと、地図の見やすさにもこだわりました。

コードはそのままコピペして使えるので、「自分の旅を Python で作る」楽しさをぜひ体験してみてください。

スポンサーリンク
タイトルとURLをコピーしました