在今天這個數據驅動的世界中,有效的地理空間索引對於從共乘、物流到環境監測和災難應對等應用都是至關重要的。Uber 的 H3 是一個強大的開源空間索引系統,提供了一種獨特的基於六邊形網格的解決方案,使得地理空間分析變得無縫且查詢執行快速。與傳統的矩形網格系統不同,H3 的分層六邊形鋪設確保了均勻的空間覆蓋、更好的相鄰性和減少失真。這篇指南將探討 H3 的核心概念、安裝、功能、使用案例和最佳實踐,以幫助開發者和數據科學家充分利用其潛力。
學習目標
- 了解 Uber 的 H3 空間索引系統的基本原理及其相對於傳統網格系統的優勢。
- 學習如何在 Python、JavaScript 和其他語言中安裝和設置 H3 以用於地理空間應用。
- 探索 H3 的分層六邊形網格結構及其對空間準確性和索引的好處。
- 獲得使用 H3 核心功能的實踐經驗,如鄰居查找、多邊形索引和距離計算。
- 發現 H3 的現實應用,包括機器學習、災難應對和環境監測。
這篇文章是作為數據科學博客馬拉松的一部分發表的。
什麼是 Uber H3?
Uber H3 是一個由 Uber 開發的開源六邊形分層空間索引系統。它旨在有效地劃分和索引地理空間,使得高級地理空間分析、快速查詢和無縫可視化成為可能。與使用方形或矩形瓷磚的傳統網格系統不同,H3 使用六邊形,這提供了更優越的空間關係、更好的相鄰性,並在表示地球表面時最小化失真。
為什麼 Uber 開發 H3?
Uber 開發 H3 是為了解決地理空間計算中的關鍵挑戰,特別是在共乘、物流和基於位置的服務中。基於緯度-經度坐標、矩形網格或四叉樹的傳統方法往往在解析度不一致、空間查詢效率低下和真實世界空間關係的表現不佳等方面存在問題。H3 通過以下方式解決了這些限制:
- 提供均勻的分層六邊形網格,允許在不同解析度之間無縫擴展。
- 支持快速的最近鄰查找和高效的空間索引,用於需求預測、路由和供應分配。
- 支持高準確度和最小計算開銷的空間查詢和地理空間聚類。
如今,H3 被廣泛應用於 Uber 以外的應用,包括環境監測、地理空間分析和地理信息系統 (GIS)。
什麼是空間索引?
空間索引是一種用於有效結構化和組織地理空間數據的技術,允許快速的空間查詢和改進的數據檢索性能。它對於以下任務至關重要:
- 最近鄰查找
- 地理空間聚類
- 高效的地理空間聯接
- 基於區域的過濾
H3 通過使用六邊形網格系統來增強空間索引,這提高了空間準確性,提供了更好的相鄰性,並減少了傳統網格系統中的失真。
安裝指南 (Python、JavaScript、Go、C 等)
在開發環境中設置 H3
現在讓我們在開發環境中設置 H3:
# 創建虛擬環境
python -m venv h3_env
source h3_env/bin/activate # Linux/macOS
h3_env\Scripts\activate # Windows
# 安裝依賴項
pip install h3 geopandas matplotlib
數據結構和分層索引
接下來我們將詳細了解數據結構和分層索引:
六邊形網格系統
H3 的六邊形網格將地球劃分為 122 個基本單元 (解析度 0),包括 110 個六邊形和 12 個五邊形,以近似球面幾何。每個單元通過 aperture 7 分區進行分層細分,每個父六邊形包含 7 個子單元,這樣創建了 16 個解析度級別 (0-15),並且單元大小呈指數減小:
解析度 | 平均邊長 (公里) | 平均面積 (平方公里) | 每個父單元的單元數量 |
---|---|---|---|
0 | 1,107.712 | 4,250,546 | – |
5 | 8.544 | 252.903 | 16,807 |
9 | 0.174 | 0.105 | 40,353,607 |
15 | 0.0005 | 0.0000009 | 7^15 ≈ 4.7e12 |
以下代碼演示了 H3 的分層六邊形網格系統:
import folium
import h3
base_cell="8001fffffffffff" # 解析度 0 的五邊形
children = h3.cell_to_children(base_cell, res=1)
# 創建一個以基本六邊形中心為中心的地圖
base_center = h3.cell_to_latlng(base_cell)
GeoSpatialMap = folium.Map(location=[base_center[0], base_center[1]], zoom_start=9)
# 獲取六邊形邊界的函數
def get_hexagon_bounds(h3_address):
boundaries = h3.cell_to_boundary(h3_address)
return [[lat, lng] for lat, lng in boundaries]
# 添加基本六邊形
folium.Polygon(
locations=get_hexagon_bounds(base_cell),
color="red",
fill=True,
weight=2,
popup=f'基本: {base_cell}'
).add_to(GeoSpatialMap)
# 添加子六邊形
for child in children:
folium.Polygon(
locations=get_hexagon_bounds(child),
color="blue",
fill=True,
weight=1,
popup=f'子: {child}'
).add_to(GeoSpatialMap)
GeoSpatialMap
解析度級別和分層索引
分層索引結構通過父子關係支持多解析度分析。H3 支持分層解析度級別(從 0 到 15),允許數據在不同的粒度下進行索引。
以下代碼顯示了這種關係:
delhi_cell = h3.latlng_to_cell(28.6139, 77.2090, 9) # 新德里的坐標
# 向上遍歷層次結構
parent = h3.cell_to_parent(delhi_cell, res=8)
print(f"解析度 8 的父單元: {parent}")
# 向下遍歷層次結構
children = h3.cell_to_children(parent, res=9)
print(f"包含 {len(children)} 個子單元")
# 創建一個以新德里為中心的新地圖
delhi_map = folium.Map(location=[28.6139, 77.2090], zoom_start=15)
# 添加父六邊形(解析度 8)
folium.Polygon(
locations=get_hexagon_bounds(parent),
color="red",
fill=True,
weight=2,
popup=f'父: {parent}'
).add_to(delhi_map)
# 添加所有子六邊形(解析度 9)
for child_cell in children:
color="yellow" if child_cell == delhi_cell else 'blue'
folium.Polygon(
locations=get_hexagon_bounds(child_cell),
color=color,
fill=True,
weight=1,
popup=f'子: {child_cell}'
).add_to(delhi_map)
delhi_map
H3 索引編碼
H3 索引將地理空間數據編碼為一個 64 位無符號整數(通常表示為 15 字符的十六進制字符串,如 ‘89283082837ffff’)。H3 索引具有以下架構:
4 位 | 3 位 | 7 位 | 45 位 |
---|---|---|---|
模式和解析度 | 保留 | 基本單元 | 子數字 |
我們可以通過以下代碼理解編碼過程:
import h3
# 將坐標轉換為 H3 索引(解析度 9)
lat, lng = 37.7749, -122.4194 # 舊金山
h3_index = h3.latlng_to_cell(lat, lng, 9)
print(h3_index) # '89283082803ffff'
# 解構索引組件
## 獲取解析度
resolution = h3.get_resolution(h3_index)
print(f"解析度: {resolution}")
# 獲取基本單元號
base_cell = h3.get_base_cell_number(h3_index)
print(f"基本單元: {base_cell}")
# 檢查是否為五邊形
is_pentagon = h3.is_pentagon(h3_index)
print(f"是否為五邊形: {is_pentagon}")
# 獲取二十面體面
face = h3.get_icosahedron_faces(h3_index)
print(f"面號: {face}")
# 獲取子單元
child_cells = h3.cell_to_children(h3.cell_to_parent(h3_index, 8), 9)
print(f"子單元: {child_cells}")
核心功能
除了分層索引外,H3 的其他核心功能包括:
- 鄰居查找和遍歷
- 多邊形到 H3 索引
- H3 網格距離和 K-環
鄰居查找和遍歷
鄰居查找遍歷是指在 Uber 的 H3 六邊形網格系統中識別和導航相鄰單元。這使得空間查詢變得可能,例如“查找目標單元半徑內的所有單元”。這一概念可以通過以下代碼理解:
import h3
# 定義加爾各答的緯度、經度
lat, lng = 22.5744, 88.3629
resolution = 9
h3_index = h3.latlng_to_cell(lat, lng, resolution)
print(h3_index) # 例如 '89283082837ffff'
# 查找所有在 1 網格步長內的鄰居
neighbors = h3.grid_disk(h3_index, k=1)
print(len(neighbors)) # 7 (6 個鄰居 + 原始單元)
# 檢查邊緣相鄰性
is_neighbor = h3.are_neighbor_cells(h3_index, neighbors[0])
print(is_neighbor) # True 或 False
要生成這個可視化,我們可以簡單地使用以下代碼:
import h3
import folium
# 定義加爾各答的緯度、經度
lat, lng = 22.5744, 88.3629
resolution = 9 # H3 解析度
# 將緯度/經度轉換為 H3 索引
h3_index = h3.latlng_to_cell(lat, lng, resolution)
# 獲取鄰近的六邊形
neighbors = h3.grid_disk(h3_index, k=1)
# 初始化以給定位置為中心的地圖
m = folium.Map(location=[lat, lng], zoom_start=12)
# 將六邊形添加到地圖的函數
def add_hexagon(h3_index, color):
""" 將 H3 六邊形添加到 folium 地圖 """
boundary = h3.cell_to_boundary(h3_index)
boundary = [[lat, lng] for lat, lng in boundary]
folium.Polygon(
locations=boundary,
color=color,
fill=True,
fill_color=color,
fill_opacity=0.5
).add_to(m)
# 添加紅色的中心六邊形
add_hexagon(h3_index, "red")
# 添加藍色的鄰近六邊形
for neighbor in neighbors:
if neighbor != h3_index: # 避免重新上色中心
add_hexagon(neighbor, "blue")
# 顯示地圖
m
鄰居查找和遍歷的用例包括:
- 共乘:查找 5 分鐘車程內的可用司機。
- 空間聚合:計算洪水區域 10 公里內的總降雨量。
- 機器學習:生成需求預測模型的鄰域特徵。
多邊形到 H3 索引
將多邊形轉換為 H3 索引涉及識別所有在指定解析度下與多邊形完全或部分相交的六邊形單元。這對於在地理邊界內聚合數據等空間操作至關重要。這可以通過以下代碼理解:
import h3
# 定義一個多邊形(例如,舊金山的邊界框)
polygon_coords = h3.LatLngPoly(
[(37.708, -122.507), (37.708, -122.358), (37.832, -122.358), (37.832, -122.507)]
)
# 將多邊形轉換為 H3 單元(解析度 9)
resolution = 9
cells = h3.polygon_to_cells(polygon_coords, res=resolution)
print(f"總單元數: {len(cells)}")
# 輸出: ~ 1651
要可視化這一點,我們可以遵循以下代碼:
import h3
import folium
from h3 import LatLngPoly
# 定義加爾各答的邊界多邊形
kolkata_coords = LatLngPoly([
(22.4800, 88.2900), # 西南角
(22.4800, 88.4200), # 東南角
(22.5200, 88.4500), # 東
(22.5700, 88.4500), # 東北
(22.6200, 88.4200), # 北
(22.6500, 88.3500), # 西北
(22.6200, 88.2800), # 西
(22.5500, 88.2500), # 西南
(22.5000, 88.2700) # 返回起始區域
])
# 將多邊形轉換為 H3 單元
resolution = 9
cells = h3.polygon_to_cells(kolkata_coords, res=resolution)
# 創建一個以加爾各答為中心的 Folium 地圖
kolkata_map = folium.Map(location=[22.55, 88.35], zoom_start=12)
# 將每個 H3 單元作為多邊形添加
for cell in cells:
boundaries = h3.cell_to_boundary(cell)
boundaries = [[lat, lng] for lat, lng in boundaries]
folium.Polygon(
locations=boundaries,
color="blue",
weight=1,
fill=True,
fill_opacity=0.4,
popup=cell
).add_to(kolkata_map)
# 顯示地圖
kolkata_map
H3 網格距離和 K-環
網格距離測量從一個 H3 單元到另一個 H3 單元所需的最小步數,通過相鄰單元移動。與地理距離不同,它是一種基於六邊形網格連通性的拓撲度量。我們應該記住,更高的解析度會產生更小的步長,因此網格距離會更大。
import h3
from h3 import latlng_to_cell
# 定義兩個 H3 單元,解析度 9
cell_a = latlng_to_cell(37.7749, -122.4194, 9) # 舊金山
cell_b = latlng_to_cell(37.3382, -121.8863, 9) # 聖荷西
# 計算網格距離
distance = h3.grid_distance(cell_a, cell_b)
print(f"網格距離: {distance} 步")
# 輸出: 網格距離: 220 步 (大約)
我們可以通過以下代碼可視化這一點:
import h3
import folium
from h3 import latlng_to_cell
from shapely.geometry import Polygon
# 獲取 H3 多邊形邊界的函數
def get_h3_polygon(h3_index):
boundary = h3.cell_to_boundary(h3_index)
return [(lat, lon) for lat, lon in boundary]
# 定義兩個 H3 單元,解析度 6
cell_a = latlng_to_cell(37.7749, -122.4194, 6) # 舊金山
cell_b = latlng_to_cell(37.3382, -121.8863, 6) # 聖荷西
# 獲取六邊形邊界
polygon_a = get_h3_polygon(cell_a)
polygon_b = get_h3_polygon(cell_b)
# 計算網格距離
distance = h3.grid_distance(cell_a, cell_b)
# 創建一個以兩個位置為中心的 Folium 地圖
map_center = [(37.7749 + 37.3382) / 2, (-122.4194 + -121.8863) / 2]
m = folium.Map(location=map_center, zoom_start=9)
# 將 H3 六邊形添加到地圖
folium.Polygon(locations=polygon_a, color="blue", fill=True, fill_opacity=0.4, popup="舊金山 (H3)").add_to(m)
folium.Polygon(locations=polygon_b, color="red", fill=True, fill_opacity=0.4, popup="聖荷西 (H3)").add_to(m)
# 為中心點添加標記
folium.Marker([37.7749, -122.4194], popup="舊金山").add_to(m)
folium.Marker([37.3382, -121.8863], popup="聖荷西").add_to(m)
# 顯示距離
folium.Marker(map_center, popup=f"H3 網格距離: {distance} 步", icon=folium.Icon(color="green")).add_to(m)
# 顯示地圖
m
K-環(或網格圓盤)在 H3 中指的是所有在距離中心單元 k 步之內的六邊形單元。這包括:
- 中心單元本身(步長為 0)。
- 直接鄰居(步長為 1)。
- 逐漸增大的距離直到 k 步。
import h3
# 定義一個中心單元(舊金山,解析度 9)
central_cell = h3.latlng_to_cell(37.7749, -122.4194, 9)
k = 2
# 生成 K-環(在 2 步內的單元)
k_ring = h3.grid_disk(central_cell, k)
print(f"總單元數: {len(k_ring)}") # 例如 19 個單元
這可以通過以下代碼可視化:
import h3
import matplotlib.pyplot as plt
from shapely.geometry import Polygon
import geopandas as gpd
# 定義中心點(緯度、經度)為舊金山
lat, lng = 37.7749, -122.4194
resolution = 9 # 選擇解析度(例如,9)
# 獲取給定點的中心 H3 單元索引
center_h3 = h3.latlng_to_cell(lat, lng, resolution)
print("中心 H3 單元:", center_h3) # 示例輸出: '89283082837ffff'
# 定義 k 值(K-環的網格步數)
k = 2
# 生成 k-環的單元:所有在中心 H3 的 k 步內的單元
k_ring_cells = h3.grid_disk(center_h3, k)
print("總 k-環單元:", len(k_ring_cells))
# 對於標準六邊形(非五邊形),k=2 通常返回 19 個單元:
# 1(中心單元)+ 6(距離 1 的鄰居)+ 12(距離 2 的鄰居)
# 將每個 H3 單元轉換為 Shapely 多邊形以進行可視化
polygons = []
for cell in k_ring_cells:
boundary = h3.cell_to_boundary(cell)
poly = Polygon([(lng, lat) for lat, lng in boundary])
polygons.append(poly)
# 創建 GeoDataFrame 以繪製六邊形單元
gdf = gpd.GeoDataFrame({'h3_index': list(k_ring_cells)}, geometry=polygons)
# 使用 Matplotlib 繪製 k-環單元的邊界
fig, ax = plt.subplots(figsize=(8, 8))
gdf.boundary.plot(ax=ax, color="blue", lw=1)
# 通過繪製其邊界來突出顯示中心單元
central_boundary = h3.cell_to_boundary(center_h3)
central_poly = Polygon([(lng, lat) for lat, lng in central_boundary])
gpd.GeoSeries([central_poly]).boundary.plot(ax=ax, color="red", lw=2)
# 設置標題和標籤以清晰可視化
ax.set_title("H3 K-環可視化 (k = 2)")
ax.set_xlabel("經度")
ax.set_ylabel("緯度")
plt.show()
使用案例
雖然 H3 的使用案例僅限於創造力,但以下是一些示例:
高效的地理空間查詢
H3 在優化基於位置的查詢方面表現出色,例如計算動態地理邊界內的興趣點 (POIs)。
在這個用例中,我們演示了如何使用 H3 來分析和可視化舊金山的乘車密度。為了模擬現實世界的乘車數據,我們生成隨機的 GPS 坐標,並將每次乘車分配一個隨機的時間戳,以創建一個真實的數據集。每次乘車的緯度和經度都轉換為解析度為 10 的 H3 索引,這是一個細粒度的六邊形網格,有助於空間聚合。為了分析當地的乘車密度,我們選擇一個目標 H3 單元,並使用 h3.grid_disk 檢索所有附近的單元,這些單元位於兩個六邊形環內。為了可視化乘車的空間分佈,我們將 H3 六邊形疊加到 Folium 地圖上。
代碼實現
執行代碼如下:
import pandas as pd
import h3
import folium
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime, timedelta
import random
# 創建舊金山周圍的樣本 GPS 數據
center_lat, center_lng = 37.7749, -122.4194
# 生成合成乘車數據
num_rides = 1000
np.random.seed(42) # 以便重現
# 生成舊金山周圍的隨機坐標
lats = np.random.normal(center_lat, 0.02, num_rides) # 在中心周圍的正態分佈
lngs = np.random.normal(center_lng, 0.02, num_rides)
# 生成過去一周的時間戳
start_time = datetime.now() - timedelta(days=7)
timestamps = [start_time + timedelta(minutes=random.randint(0, 10080)) for _ in range(num_rides)]
timestamp_strs = [ts.strftime('%Y-%m-%d %H:%M:%S') for ts in timestamps]
# 創建 DataFrame
rides = pd.DataFrame({
'lat': lats,
'lng': lngs,
'timestamp': timestamp_strs
})
# 將坐標轉換為 H3 索引(解析度 10)
rides["h3"] = rides.apply(
lambda row: h3.latlng_to_cell(row["lat"], row["lng"], 10), axis=1
)
# 計算每個單元的乘車數量
pickup_counts = rides["h3"].value_counts().reset_index()
pickup_counts.columns = ["h3", "counts"]
# 查詢特定單元及其鄰居內的乘車數量
target_cell = h3.latlng_to_cell(37.7749, -122.4194, 10)
neighbors = h3.grid_disk(target_cell, k=2)
local_pickups = pickup_counts[pickup_counts["h3"].isin(neighbors)]
# 可視化空間查詢結果
map_center = h3.cell_to_latlng(target_cell)
m = folium.Map(location=map_center, zoom_start=15)
# 獲取六邊形邊界的函數
def get_hexagon_bounds(h3_address):
boundaries = h3.cell_to_boundary(h3_address)
return [[lat, lng] for lat, lng in boundaries]
# 添加目標單元
folium.Polygon(
locations=get_hexagon_bounds(target_cell),
color="red",
fill=True,
weight=2,
popup=f'目標單元: {target_cell}'
).add_to(m)
# 根據乘車數量的顏色強度添加鄰居單元
max_count = local_pickups["counts"].max()
min_count = local_pickups["counts"].min()
for _, row in local_pickups.iterrows():
if row["h3"] != target_cell:
intensity = (row["counts"] - min_count) / (max_count - min_count) if max_count > min_count else 0.5
color = f'#{int(255*(1-intensity)):02x}{int(200*(1-intensity)):02x}ff'
folium.Polygon(
locations=get_hexagon_bounds(row["h3"]),
color=color,
fill=True,
fill_opacity=0.7,
weight=1,
popup=f'單元: {row["h3"]}<br>乘車數量: {row["counts"]}'
).add_to(m)
# 使用 matplotlib 創建熱圖可視化
plt.figure(figsize=(12, 8))
plt.title("H3 網格熱圖:乘車密度")
# 根據乘車數量創建散點圖
for idx, row in local_pickups.iterrows():
center = h3.cell_to_latlng(row["h3"])
plt.scatter(center[1], center[0], s=row["counts"]/2,
c=row["counts"], cmap='viridis', alpha=0.7)
plt.colorbar(label="乘車數量")
plt.xlabel('經度')
plt.ylabel('緯度')
plt.grid(True)
# 顯示兩個可視化
m # 顯示 Folium 地圖
以上示例突顯了如何利用 H3 進行城市移動的空間分析。通過將原始 GPS 坐標轉換為六邊形網格,我們可以有效地分析乘車密度、檢測熱點並以有意義的方式可視化數據。H3 在處理不同解析度方面的靈活性使其成為共乘、物流和城市規劃應用中有價值的工具。
將 H3 與機器學習結合
H3 已經與機器學習結合以解決許多現實世界的問題。Uber 通過基於 H3 的機器學習模型將 ETA 預測誤差降低了 22%,而法國圖盧茲則使用 H3 + 機器學習來優化自行車道的佈局,增加了 18% 的乘客數量。
在這個用例中,我們演示了如何使用 H3 來分析和預測舊金山的交通擁堵,使用歷史 GPS 乘車數據和機器學習技術。為了模擬現實世界的交通狀況,我們生成隨機的 GPS 坐標,並為每次乘車分配一個隨機的時間戳和速度值。每次乘車的緯度和經度都轉換為解析度為 10 的 H3 索引,以便進行空間聚合和分析。我們從樣本單元及其相鄰單元中提取特徵,以分析當地的交通狀況。為了預測交通擁堵,我們使用基於 LSTM 的深度學習模型。該模型旨在處理歷史交通數據並預測擁堵概率。使用訓練好的模型,我們可以預測給定單元的擁堵概率。
代碼實現
執行代碼如下:
import h3
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import random
import tensorflow as tf
from tensorflow.keras.layers import LSTM, Conv1D, Dense
# 創建舊金山周圍的樣本 GPS 數據
center_lat, center_lng = 37.7749, -122.4194
num_rides = 1000
np.random.seed(42) # 以便重現
# 生成舊金山周圍的隨機坐標
lats = np.random.normal(center_lat, 0.02, num_rides)
lngs = np.random.normal(center_lng, 0.02, num_rides)
# 生成過去一周的時間戳
start_time = datetime.now() - timedelta(days=7)
timestamps = [start_time + timedelta(minutes=random.randint(0, 10080)) for _ in range(num_rides)]
timestamp_strs = [ts.strftime('%Y-%m-%d %H:%M:%S') for ts in timestamps]
# 生成隨機速度數據
speeds = np.random.uniform(5, 60, num_rides) # 速度以公里/小時為單位
# 創建 DataFrame
gps_data = pd.DataFrame({
'lat': lats,
'lng': lngs,
'timestamp': timestamp_strs,
'speed': speeds
})
# 將坐標轉換為 H3 索引(解析度 10)
gps_data["h3"] = gps_data.apply(
lambda row: h3.latlng_to_cell(row["lat"], row["lng"], 10), axis=1
)
# 將時間戳字符串轉換為日期時間對象
gps_data["timestamp"] = pd.to_datetime(gps_data["timestamp"])
# 按 5 分鐘的間隔聚合速度和計數
agg_data = gps_data.groupby(["h3", pd.Grouper(key="timestamp", freq="5T")]).agg(
avg_speed=("speed", "mean"),
vehicle_count=("h3", "count")
).reset_index()
# 示例:使用我們現有數據集中的一個單元
sample_cell = gps_data["h3"].iloc[0]
neighbors = h3.grid_disk(sample_cell, 2)
def get_kring_features(cell, k=2):
neighbors = h3.grid_disk(cell, k)
return {f"neighbor_{i}": neighbor for i, neighbor in enumerate(neighbors)}
# 特徵提取的佔位符函數
def fetch_features(neighbors, agg_data):
return np.random.rand(1, 6, len(neighbors)) # 1 個樣本,6 個時間步,對於每個鄰居的特徵
# 定義模型架構的骨架
def create_model(input_shape):
model = tf.keras.Sequential([
LSTM(64, return_sequences=True, input_shape=input_shape),
LSTM(32),
Dense(16, activation='relu'),
Dense(1, activation='sigmoid')
])
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=['accuracy'])
return model
# 預測函數(實際上會使用訓練好的模型)
def predict_congestion(cell, model, agg_data):
neighbors = h3.grid_disk(cell, k=2)
features = fetch_features(neighbors, agg_data)
return model.predict(features)[0][0]
# 創建一個骨架模型(未訓練)
input_shape = (6, 19) # 6 個時間步,19 個特徵(對於 k=2 的鄰居)
model = create_model(input_shape)
# 打印有關實際預測的資訊
print(f"樣本單元: {sample_cell}")
print(f"鄰居單元的數量 (k=2): {len(neighbors)}")
print("模型摘要:")
model.summary()
# 實際上,您會在使用它進行預測之前訓練模型
# 這只是顯示預測調用的樣子:
congestion_prob = predict_congestion(sample_cell, model, agg_data)
print(f"擁堵概率: {congestion_prob:.2%}")
這個示例演示了如何利用 H3 進行空間分析和交通預測。通過將 GPS 數據轉換為六邊形網格,我們可以有效地分析交通模式,從相鄰區域提取有意義的見解,並使用深度學習實時預測擁堵。這種方法可以應用於智慧城市規劃、共乘優化和智能交通管理系統。
災難應對和環境監測
洪水事件是最常見的自然災害之一,需要立即響應和資源分配。H3 可以通過整合各種數據來源,包括洪水區域地圖、人口密度、建築基礎設施和實時水位讀數,顯著改善洪水應對工作。
以下 Python 實現演示了如何使用 H3 進行洪水風險分析,通過整合淹水區域數據與建築基礎設施信息:
import h3
import folium
import pandas as pd
import numpy as np
from folium.plugins import MarkerCluster
# 創建樣本建築數據集
np.random.seed(42)
num_buildings = 50
# 在舊金山周圍創建建築
center_lat, center_lng = 37.7749, -122.4194
building_types = ['residential', 'commercial', 'hospital', 'school', 'government']
building_weights = [0.6, 0.2, 0.1, 0.07, 0.03] # 機率權重
# 生成建築數據
buildings_df = pd.DataFrame({
'lat': np.random.normal(center_lat, 0.005, num_buildings),
'lng': np.random.normal(center_lng, 0.005, num_buildings),
'type': np.random.choice(building_types, size=num_buildings, p=building_weights),
'capacity': np.random.randint(10, 1000, num_buildings)
})
# 在解析度 10 下添加 H3 索引
buildings_df['h3_index'] = buildings_df.apply(
lambda row: h3.latlng_to_cell(row['lat'], row['lng'], 10),
axis=1
)
# 創建一些洪水單元(讓我們使用一些建築所在的單元)
flood_cells = set(buildings_df['h3_index'].sample(10))
# 創建一個以我們坐標的平均值為中心的地圖
center_lat = buildings_df['lat'].mean()
center_lng = buildings_df['lng'].mean()
flood_map = folium.Map(location=[center_lat, center_lng], zoom_start=16)
# 獲取六邊形邊界的函數
def get_hexagon_bounds(h3_address):
boundaries = h3.cell_to_boundary(h3_address)
return [[lat, lng] for lat, lng in boundaries]
# 添加洪水區域單元
for cell in flood_cells:
folium.Polygon(
locations=get_hexagon_bounds(cell),
color="blue",
fill=True,
fill_opacity=0.4,
weight=2,
popup=f'洪水單元: {cell}'
).add_to(flood_map)
# 添加建築標記
for idx, row in buildings_df.iterrows():
if row['h3_index'] in flood_cells:
color="red"
icon = 'warning' if row['type'] in ['hospital', 'school'] else 'info-sign'
prefix = 'glyphicon'
else:
color="green"
icon = 'home'
prefix = 'glyphicon'
folium.Marker(
location=[row['lat'], row['lng']],
popup=f"建築類型: {row['type']}<br>容量: {row['capacity']}",
tooltip=f"{row['type']} (容量: {row['capacity']})",
icon=folium.Icon(color=color, icon=icon, prefix=prefix)
).add_to(flood_map)
# 添加作為 HTML 元素的圖例
legend_html="""
<div style="position: fixed;
bottom: 50px; left: 50px; width: 200px; height: 120px;
border:2px solid grey; z-index:9999; font-size:14px;
background-color:white; padding: 10px;
border-radius: 5px;">
<b>洪水影響分析</b> <br>
<i class="glyphicon glyphicon-stop" style="color:blue"></i> 洪水區域 <br>
<i class="glyphicon glyphicon-home" style="color:green"></i> 安全建築 <br>
<i class="glyphicon glyphicon-info-sign" style="color:red"></i> 受影響建築 <br>
<i class="glyphicon glyphicon-warning-sign" style="color:red"></i> 重要設施 <br>
</div>
"""
flood_map.get_root().html.add_child(folium.Element(legend_html))
# 顯示地圖
flood_map
這段代碼提供了一種有效的方法來可視化和分析洪水影響,使用 H3 空間索引和 Folium 地圖。通過整合空間數據聚類和互動可視化,它增強了災難應對規劃和城市風險管理策略。這種方法可以擴展到其他地理空間挑戰,例如野火風險評估或交通規劃。
H3 的優勢和劣勢
以下表格提供了基於行業實施和技術評估的 H3 優勢和限制的詳細分析:
方面 | 優勢 | 劣勢 |
---|---|---|
幾何屬性 | 六邊形單元提供均勻的距離度量,鄰居等距。比方形/矩形網格更好地近似圓形。全球最小化面積和形狀失真。 | 無法完全將地球劃分為六邊形,需使用 12 個五邊形單元,這會產生不規則的相鄰模式。儘管旨在“粗略相等”,但並不是一個真正的等面積系統。 |
分層結構 | 根據需要有效地改變精度(解析度)級別。所有解析度的緊湊 64 位地址 – 父子樹沒有共享父級。 | 解析度之間的分層嵌套並不完美。在相鄰尺度上可能會出現微小的不連續性(間隙/重疊)。對於需要精確包含的用例(例如,地塊數據)來說,這是有問題的。 |
性能 | 基於 H3 的方法可以比基於幾何的操作便宜多達 90 倍。顯著提高了大型數據集的處理效率。網格系統中可預測單元之間的快速計算。 | 在高解析度下處理大面積需要大量計算資源。在精度和性能之間存在權衡 – 更高的解析度消耗更多資源。 |
空間分析 | 從鄰域到區域尺度的多解析度分析。標準化格式以整合異構數據源。均勻的相鄰關係簡化了鄰域搜索。 | 多邊形覆蓋是近似的,邊界處可能存在潛在間隙。精度限制取決於所選的解析度級別。多邊形交集需要特殊處理。 |
實施 | 簡單的 API 及內置工具(地理圍欄多邊形填充、六邊形壓縮、GeoJSON 輸出)- 非常適合並行執行。單元 ID 可以用作標準 SQL 函數中的列。 | 處理五邊形單元需要專門的代碼。將現有工作流程適應 H3 可能很複雜。數據質量依賴性影響分析準確性。 |
應用 | 優化用於:地理空間分析、流動性分析、物流、交付服務、電信、保險風險評估和環境監測。 | 不太適合需要精確邊界定義的應用。對於專門的製圖目的可能不是最佳選擇。對於資源有限的實時應用可能涉及計算複雜性。 |
結論
Uber 的 H3 空間索引系統是一個強大的地理空間分析工具,提供了一個六邊形網格結構,使得高效的空間查詢、多解析度分析和與現代數據工作流程的無縫整合成為可能。它的優勢在於均勻的幾何形狀、分層設計和處理大規模數據集的速度和精度。從共乘優化到災難應對和環境監測,H3 在各行各業中證明了其多功能性。
然而,像任何技術一樣,H3 也有其局限性,例如處理五邊形單元、近似多邊形邊界和在高解析度下的計算需求。通過了解其優勢和劣勢,開發者可以有效地利用 H3 進行需要可擴展和準確的地理空間洞察的應用。
隨著地理空間技術的發展,H3 的開源生態系統可能會看到進一步的增強,包括與機器學習模型的整合、實時分析和 3D 空間索引。H3 不僅僅是一個工具,而是構建更智能的地理空間解決方案的基礎,在這個越來越數據驅動的世界中。
常見問題
A. 請訪問官方 H3 文檔或在 GitHub 上探索開源示例。Uber 的工程博客還提供了有關 H3 實際應用的見解。
A. 是的!憑藉其快速的索引和鄰居查找能力,H3 對於實時地理空間應用(如實時交通監控或災難應對協調)非常高效。
A. 是的!H3 非常適合機器學習應用。通過將原始 GPS 數據轉換為六邊形特徵(例如,每個單元的交通密度),您可以將空間模式整合到需求預測或擁堵預測等預測模型中。
A. 核心 H3 庫是用 C 語言編寫的,但它有 Python、JavaScript、Go、Java 等的綁定。這使其在各種地理空間工作流程中具有靈活性。
A. 雖然用六邊形完美地鋪設一個球體是不可能的,但 H3 在每個解析度下引入了 12 個五邊形單元來填補間隙。為了最小化它們對大多數數據集的影響,該系統將這些五邊形策略性地放置在海洋或不太重要的區域。
本文中顯示的媒體不屬於 Analytics Vidhya,並由作者自行決定使用。
本文由 AI 台灣 運用 AI 技術編撰,內容僅供參考,請自行核實相關資訊。
歡迎加入我們的 AI TAIWAN 台灣人工智慧中心 FB 社團,
隨時掌握最新 AI 動態與實用資訊!