refactor(officefile): 按 md/latex/word 三层结构重组文档目录
将 Markdown 源文件移入 md/,LaTeX 工作目录保留在 latex/, Word 导出移入 word/;删除临时脚本、调试截图和空 stub。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,544 @@
|
||||
# 02.2 空间推理
|
||||
|
||||
## 核心问题
|
||||
|
||||
> 机器如何理解和处理空间关系?
|
||||
> 图算法在空间分析中有哪些应用?
|
||||
> 如何进行连通性分析和路径优化?
|
||||
|
||||
---
|
||||
|
||||
## 概念讲解
|
||||
|
||||
### 空间关系类型
|
||||
|
||||
```
|
||||
空间关系分类
|
||||
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ 1. 拓扑关系 │
|
||||
│ - 相邻 (Adjacent): A与B共享边界 │
|
||||
│ - 包含 (Contains): A完全包含B │
|
||||
│ - 重叠 (Overlaps): A与B部分重叠 │
|
||||
│ - 相离 (Disjoint): A与B不相交 │
|
||||
│ │
|
||||
│ 2. 距离关系 │
|
||||
│ - 欧氏距离: 直线距离 │
|
||||
│ - 曼哈顿距离: 城市街区距离 │
|
||||
│ - 阻力距离: 穿越不同地形的代价 │
|
||||
│ - 时间距离: 行驶时间成本 │
|
||||
│ │
|
||||
│ 3. 方向关系 │
|
||||
│ - 绝对方向: 北、南、东、西 │
|
||||
│ - 相对方向: 前、后、左、右 │
|
||||
│ - 方位角: 0-360度的精确方向 │
|
||||
│ │
|
||||
│ 4. 模式关系 │
|
||||
│ - 聚集: 要素密集分布 │
|
||||
│ - 离散: 要素分散分布 │
|
||||
│ - 随机: 要素随机分布 │
|
||||
│ - 规则: 要素有规律分布 │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 图表示与空间推理
|
||||
|
||||
空间问题常可转换为图问题:
|
||||
|
||||
```
|
||||
空间 → 图的转换
|
||||
|
||||
空间场景 图表示
|
||||
─────────── ───────
|
||||
源地A ──廊道──→ 源地B 节点A ──边──→ 节点B
|
||||
│ │
|
||||
└──廊道──→ 源地C └──边──→ 节点C
|
||||
```
|
||||
|
||||
**空间问题的图抽象**:
|
||||
|
||||
| 空间问题 | 图表示 | 算法 |
|
||||
|---------|--------|------|
|
||||
| 最短路径 | 节点=位置,边=路径 | Dijkstra, A* |
|
||||
| 连通性分析 | 节点=斑块,边=廊道 | BFS, DFS, 并查集 |
|
||||
| 设施选址 | 节点=候选点,边=需求 | p-median, p-center |
|
||||
| 覆盖问题 | 节点=服务点,边=覆盖范围 | 最大覆盖 |
|
||||
| 网络流 | 节点=源/汇,边=管道 | 最大流最小割 |
|
||||
|
||||
---
|
||||
|
||||
## 设计原理
|
||||
|
||||
### 连通性分析
|
||||
|
||||
连通性是生态网络分析的核心:
|
||||
|
||||
```python
|
||||
class ConnectivityAnalyzer:
|
||||
"""
|
||||
连通性分析器
|
||||
|
||||
核心:使用图算法分析空间连通性
|
||||
"""
|
||||
|
||||
def __init__(self, resistance_surface):
|
||||
"""
|
||||
Args:
|
||||
resistance_surface: 阻力面栅格
|
||||
"""
|
||||
self.resistance = resistance_surface
|
||||
self.graph = None
|
||||
|
||||
def build_graph(self):
|
||||
"""将阻力面转换为图"""
|
||||
import networkx as nx
|
||||
|
||||
# 创建图
|
||||
self.graph = nx.Graph()
|
||||
|
||||
rows, cols = self.resistance.shape
|
||||
|
||||
# 添加节点和边
|
||||
for i in range(rows):
|
||||
for j in range(cols):
|
||||
node_id = i * cols + j
|
||||
|
||||
# 添加节点
|
||||
self.graph.add_node(node_id, pos=(i, j))
|
||||
|
||||
# 添加边(8邻域)
|
||||
for di in [-1, 0, 1]:
|
||||
for dj in [-1, 0, 1]:
|
||||
if di == 0 and dj == 0:
|
||||
continue
|
||||
|
||||
ni, nj = i + di, j + dj
|
||||
if 0 <= ni < rows and 0 <= nj < cols:
|
||||
neighbor_id = ni * cols + nj
|
||||
|
||||
# 边权重 = 平均阻力
|
||||
weight = (
|
||||
self.resistance[i, j] +
|
||||
self.resistance[ni, nj]
|
||||
) / 2
|
||||
|
||||
self.graph.add_edge(
|
||||
node_id, neighbor_id,
|
||||
weight=weight
|
||||
)
|
||||
|
||||
return self.graph
|
||||
|
||||
def least_cost_path(self, source, target):
|
||||
"""计算最小阻力路径"""
|
||||
if self.graph is None:
|
||||
self.build_graph()
|
||||
|
||||
# Dijkstra算法
|
||||
path = nx.shortest_path(
|
||||
self.graph,
|
||||
source=source,
|
||||
target=target,
|
||||
weight='weight'
|
||||
)
|
||||
|
||||
return path
|
||||
|
||||
def connectivity_metrics(self, sources):
|
||||
"""
|
||||
计算连通性指标
|
||||
|
||||
Args:
|
||||
sources: 源地节点列表
|
||||
|
||||
Returns:
|
||||
连通性指标字典
|
||||
"""
|
||||
if self.graph is None:
|
||||
self.build_graph()
|
||||
|
||||
metrics = {}
|
||||
|
||||
# 1. 整体连通性 (图的连通分量数)
|
||||
components = list(nx.connected_components(
|
||||
self.graph.subgraph(sources)
|
||||
))
|
||||
metrics['n_components'] = len(components)
|
||||
|
||||
# 2. 最大连通分量大小
|
||||
if components:
|
||||
metrics['largest_component'] = max(len(c) for c in components)
|
||||
else:
|
||||
metrics['largest_component'] = 0
|
||||
|
||||
# 3. 平均最短路径长度
|
||||
if len(sources) > 1:
|
||||
subgraph = self.graph.subgraph(sources)
|
||||
if nx.is_connected(subgraph):
|
||||
metrics['avg_path_length'] = nx.average_shortest_path_length(
|
||||
subgraph, weight='weight'
|
||||
)
|
||||
else:
|
||||
metrics['avg_path_length'] = float('inf')
|
||||
|
||||
# 4. 网络密度
|
||||
n = len(sources)
|
||||
if n > 1:
|
||||
max_edges = n * (n - 1) / 2
|
||||
actual_edges = self.graph.subgraph(sources).number_of_edges()
|
||||
metrics['density'] = actual_edges / max_edges
|
||||
else:
|
||||
metrics['density'] = 0
|
||||
|
||||
return metrics
|
||||
```
|
||||
|
||||
### 最短路径算法
|
||||
|
||||
空间分析中最常用的图算法:
|
||||
|
||||
```python
|
||||
"""
|
||||
最短路径算法比较
|
||||
"""
|
||||
import heapq
|
||||
from typing import Dict, List, Tuple, Set
|
||||
|
||||
class ShortestPathAlgorithms:
|
||||
"""最短路径算法集合"""
|
||||
|
||||
def __init__(self, graph: Dict):
|
||||
"""
|
||||
Args:
|
||||
graph: {node: {neighbor: weight, ...}, ...}
|
||||
"""
|
||||
self.graph = graph
|
||||
|
||||
def dijkstra(self, start: str, goal: str = None) -> Tuple[Dict, Dict]:
|
||||
"""
|
||||
Dijkstra算法:经典最短路径
|
||||
|
||||
适合:非负权重图
|
||||
复杂度:O((V+E)logV)
|
||||
"""
|
||||
# 优先队列:(距离, 节点)
|
||||
pq = [(0, start)]
|
||||
visited = set()
|
||||
distances = {start: 0}
|
||||
parents = {start: None}
|
||||
|
||||
while pq:
|
||||
current_dist, current = heapq.heappop(pq)
|
||||
|
||||
if current in visited:
|
||||
continue
|
||||
visited.add(current)
|
||||
|
||||
if current == goal:
|
||||
break
|
||||
|
||||
for neighbor, weight in self.graph.get(current, {}).items():
|
||||
if neighbor in visited:
|
||||
continue
|
||||
|
||||
new_dist = current_dist + weight
|
||||
|
||||
if new_dist < distances.get(neighbor, float('inf')):
|
||||
distances[neighbor] = new_dist
|
||||
parents[neighbor] = current
|
||||
heapq.heappush(pq, (new_dist, neighbor))
|
||||
|
||||
return distances, parents
|
||||
|
||||
def reconstruct_path(self, parents: Dict, start: str, goal: str) -> List:
|
||||
"""从parents字典重建路径"""
|
||||
path = []
|
||||
current = goal
|
||||
|
||||
while current is not None:
|
||||
path.append(current)
|
||||
current = parents.get(current)
|
||||
|
||||
path.reverse()
|
||||
|
||||
if path[0] == start:
|
||||
return path
|
||||
return []
|
||||
|
||||
def a_star(self, start: str, goal: str,
|
||||
heuristic: callable) -> Tuple[Dict, Dict]:
|
||||
"""
|
||||
A*算法:带启发式的最短路径
|
||||
|
||||
适合:有目标节点的图,有可用启发式
|
||||
复杂度:O(b^d) 实际通常比Dijkstra快
|
||||
"""
|
||||
def h(node):
|
||||
return heuristic(node, goal)
|
||||
|
||||
# f(n) = g(n) + h(n)
|
||||
pq = [(h(start), 0, start)]
|
||||
visited = set()
|
||||
g_score = {start: 0} # 实际距离
|
||||
parents = {start: None}
|
||||
|
||||
while pq:
|
||||
f, g, current = heapq.heappop(pq)
|
||||
|
||||
if current in visited:
|
||||
continue
|
||||
visited.add(current)
|
||||
|
||||
if current == goal:
|
||||
break
|
||||
|
||||
for neighbor, weight in self.graph.get(current, {}).items():
|
||||
if neighbor in visited:
|
||||
continue
|
||||
|
||||
tentative_g = g + weight
|
||||
|
||||
if tentative_g < g_score.get(neighbor, float('inf')):
|
||||
g_score[neighbor] = tentative_g
|
||||
f_score = tentative_g + h(neighbor)
|
||||
parents[neighbor] = current
|
||||
heapq.heappush(pq, (f_score, tentative_g, neighbor))
|
||||
|
||||
return g_score, parents
|
||||
|
||||
# 空间启发式函数
|
||||
def euclidean_heuristic(node_pos: Tuple, goal_pos: Tuple) -> float:
|
||||
"""欧氏距离启发式"""
|
||||
import math
|
||||
return math.sqrt(
|
||||
(node_pos[0] - goal_pos[0])**2 +
|
||||
(node_pos[1] - goal_pos[1])**2
|
||||
)
|
||||
|
||||
def manhattan_heuristic(node_pos: Tuple, goal_pos: Tuple) -> float:
|
||||
"""曼哈顿距离启发式(适合网格)"""
|
||||
return abs(node_pos[0] - goal_pos[0]) + abs(node_pos[1] - goal_pos[1])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 代码示例
|
||||
|
||||
### 生态廊道识别
|
||||
|
||||
```python
|
||||
"""
|
||||
基于空间推理的生态廊道识别
|
||||
"""
|
||||
import numpy as np
|
||||
from typing import List, Tuple
|
||||
import heapq
|
||||
|
||||
def extract_corridors_mcr(resistance_surface: np.ndarray,
|
||||
sources: List[Tuple[int, int]]) -> List[dict]:
|
||||
"""
|
||||
使用最小累积阻力(MCR)方法提取生态廊道
|
||||
|
||||
Args:
|
||||
resistance_surface: 阻力面栅格
|
||||
sources: 源地坐标列表 [(row, col), ...]
|
||||
|
||||
Returns:
|
||||
廊道列表
|
||||
"""
|
||||
rows, cols = resistance_surface.shape
|
||||
|
||||
# 计算成本距离
|
||||
cost_distance = compute_cost_distance(resistance_surface, sources)
|
||||
|
||||
# 提取廊道(低阻力通道)
|
||||
corridors = []
|
||||
|
||||
for i, source1 in enumerate(sources):
|
||||
for source2 in sources[i+1:]:
|
||||
# 找到两源之间的最低阻力路径
|
||||
path = extract_lowest_resistance_path(
|
||||
cost_distance, resistance_surface, source1, source2
|
||||
)
|
||||
|
||||
if path:
|
||||
corridors.append({
|
||||
'source_a': source1,
|
||||
'source_b': source2,
|
||||
'path': path,
|
||||
'cost': sum(resistance_surface[p] for p in path)
|
||||
})
|
||||
|
||||
return corridors
|
||||
|
||||
def compute_cost_distance(resistance: np.ndarray,
|
||||
sources: List[Tuple[int, int]]) -> np.ndarray:
|
||||
"""
|
||||
计算成本距离(到最近源地的累积阻力)
|
||||
|
||||
使用Dijkstra算法的变种
|
||||
"""
|
||||
rows, cols = resistance.shape
|
||||
cost = np.full((rows, cols), np.inf)
|
||||
|
||||
# 优先队列:(累积成本, row, col)
|
||||
pq = []
|
||||
|
||||
# 初始化源地
|
||||
for source_row, source_col in sources:
|
||||
cost[source_row, source_col] = 0
|
||||
heapq.heappush(pq, (0, source_row, source_col))
|
||||
|
||||
# 8方向
|
||||
directions = [(-1, 0), (1, 0), (0, -1), (0, 1),
|
||||
(-1, -1), (-1, 1), (1, -1), (1, 1)]
|
||||
|
||||
visited = np.zeros((rows, cols), dtype=bool)
|
||||
|
||||
while pq:
|
||||
current_cost, row, col = heapq.heappop(pq)
|
||||
|
||||
if visited[row, col]:
|
||||
continue
|
||||
visited[row, col] = True
|
||||
|
||||
for dr, dc in directions:
|
||||
nr, nc = row + dr, col + dc
|
||||
|
||||
if 0 <= nr < rows and 0 <= nc < cols:
|
||||
# 计算移动成本
|
||||
if dr != 0 and dc != 0: # 对角移动
|
||||
move_cost = resistance[nr, nc] * 1.414
|
||||
else:
|
||||
move_cost = resistance[nr, nc]
|
||||
|
||||
new_cost = current_cost + move_cost
|
||||
|
||||
if new_cost < cost[nr, nc]:
|
||||
cost[nr, nc] = new_cost
|
||||
heapq.heappush(pq, (new_cost, nr, nc))
|
||||
|
||||
return cost
|
||||
|
||||
def extract_lowest_resistance_path(cost_distance: np.ndarray,
|
||||
resistance: np.ndarray,
|
||||
start: Tuple[int, int],
|
||||
end: Tuple[int, int]) -> List[Tuple[int, int]]:
|
||||
"""
|
||||
从成本距离表面提取最低阻力路径
|
||||
"""
|
||||
path = [end]
|
||||
current = end
|
||||
|
||||
while current != start:
|
||||
row, col = current
|
||||
best_neighbor = None
|
||||
best_cost = cost_distance[current]
|
||||
|
||||
# 检查邻域
|
||||
for dr in [-1, 0, 1]:
|
||||
for dc in [-1, 0, 1]:
|
||||
if dr == 0 and dc == 0:
|
||||
continue
|
||||
|
||||
nr, nc = row + dr, col + dc
|
||||
if (0 <= nr < cost_distance.shape[0] and
|
||||
0 <= nc < cost_distance.shape[1]):
|
||||
if cost_distance[nr, nc] < best_cost:
|
||||
best_cost = cost_distance[nr, nc]
|
||||
best_neighbor = (nr, nc)
|
||||
|
||||
if best_neighbor is None:
|
||||
break
|
||||
|
||||
path.append(best_neighbor)
|
||||
current = best_neighbor
|
||||
|
||||
path.reverse()
|
||||
return path if path[0] == start else []
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 案例分析
|
||||
|
||||
### ENAgent中的廊道识别
|
||||
|
||||
ENAgent使用空间推理提取生态廊道:
|
||||
|
||||
```python
|
||||
class ENAgentCorridorExtractor:
|
||||
"""ENAgent的廊道提取模块"""
|
||||
|
||||
def extract_corridors(self, mcr_surface, sources, width_threshold=500):
|
||||
"""
|
||||
基于MCR表面提取廊道
|
||||
|
||||
Args:
|
||||
mcr_surface: 最小累积阻力表面
|
||||
sources: 源地列表
|
||||
width_threshold: 廊道最小宽度
|
||||
|
||||
Returns:
|
||||
廊道字典
|
||||
"""
|
||||
corridors = []
|
||||
|
||||
# 对每对源地提取路径
|
||||
for i in range(len(sources)):
|
||||
for j in range(i + 1, len(sources)):
|
||||
path = self._extract_path_between_sources(
|
||||
mcr_surface, sources[i], sources[j]
|
||||
)
|
||||
|
||||
if path:
|
||||
# 分析廊道宽度
|
||||
width = self._calculate_corridor_width(
|
||||
mcr_surface, path
|
||||
)
|
||||
|
||||
if width >= width_threshold:
|
||||
corridors.append({
|
||||
'from': sources[i]['id'],
|
||||
'to': sources[j]['id'],
|
||||
'path': path,
|
||||
'width': width,
|
||||
'quality': self._assess_quality(
|
||||
mcr_surface, path
|
||||
)
|
||||
})
|
||||
|
||||
return corridors
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 反思与延伸
|
||||
|
||||
### 思考问题
|
||||
|
||||
1. **算法选择**:什么时候用Dijkstra,什么时候用A*?
|
||||
|
||||
2. **空间尺度**:空间推理如何处理多尺度问题?
|
||||
|
||||
3. **计算效率**:大规模空间数据的图算法如何优化?
|
||||
|
||||
4. **动态变化**:空间环境变化时,如何高效更新推理结果?
|
||||
|
||||
### 延伸阅读
|
||||
|
||||
- **"Network Flows"** (Ahuja, Magnanti, Orlin) - 网络流理论
|
||||
- **"Geometric Algorithms"** - 几何算法
|
||||
- NetworkX文档 - Python图算法库
|
||||
|
||||
---
|
||||
|
||||
## 关键要点
|
||||
|
||||
1. **空间关系有四类**:拓扑、距离、方向、模式
|
||||
2. **图算法是空间推理的核心工具**
|
||||
3. **连通性分析**使用图的结构特性
|
||||
4. **最短路径**有多个算法变种,各有适用场景
|
||||
5. **MCR分析**本质是图上的最短路径问题
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1451
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,90 @@
|
||||
# 第三部分:空间智能
|
||||
|
||||
## 本部分目标
|
||||
|
||||
理解AI如何"理解"和操作空间:
|
||||
- 空间数据的多种表征方式
|
||||
- 空间推理的计算方法
|
||||
- 多准则决策分析的原理
|
||||
- 空间优化问题的建模与求解
|
||||
- 不确定性量化的方法
|
||||
|
||||
---
|
||||
|
||||
## 章节导航
|
||||
|
||||
| 章节 | 文件 | 核心内容 | 实践 |
|
||||
|-----|------|---------|------|
|
||||
| 02.1 | [空间表征](./02.1-spatial-representation.md) | 栅格/矢量、图表示、多尺度、空间索引 | QGIS图层处理 |
|
||||
| 02.2 | [空间推理](./02.2-spatial-reasoning.md) | 邻近性、连通性、图算法 | 生态廊道识别 |
|
||||
| 02.3 | [多准则决策](./02.3-multi-criteria-decision.md) | 权重、标准化、敏感性分析 | 生态系统服务评估 |
|
||||
| 02.4 | [空间优化](./02.4-spatial-optimization.md) | 目标函数、约束、启发式搜索 | 生态网络优化 |
|
||||
| 02.5 | [不确定性量化](./02.5-uncertainty-quantification.md) | 不确定性来源、传播、可视化 | 抵抗面敏感性分析 |
|
||||
|
||||
---
|
||||
|
||||
## 核心概念图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 空间智能体系 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────┐ ┌───────────────┐ │
|
||||
│ │ 空间表征 │ ───→ │ 空间推理 │ │
|
||||
│ │ - 栅格/矢量 │ │ - 拓扑关系 │ │
|
||||
│ │ - 图表示 │ │ - 距离/方向 │ │
|
||||
│ │ - 多尺度 │ │ - 邻域分析 │ │
|
||||
│ └───────────────┘ └───────────────┘ │
|
||||
│ │ │ │
|
||||
│ └───────────┬───────────┘ │
|
||||
│ │ │
|
||||
│ ↓ │
|
||||
│ ┌───────────────┐ │
|
||||
│ │ 多准则决策 │ │
|
||||
│ │ - 权重分析 │ │
|
||||
│ │ - 标准化 │ │
|
||||
│ │ - 敏感性 │ │
|
||||
│ └───────┬───────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────┴───────────┐ │
|
||||
│ ↓ ↓ │
|
||||
│ ┌───────────────┐ ┌───────────────┐ │
|
||||
│ │ 空间优化 │ │ 不确定性量化 │ │
|
||||
│ │ - 目标函数 │ │ - 误差传播 │ │
|
||||
│ │ - 约束处理 │ │ - 蒙特卡洛 │ │
|
||||
│ │ - 启发式 │ │ - 可视化 │ │
|
||||
│ └───────────────┘ └───────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 实践案例
|
||||
|
||||
### 实践案例02:构建生态系统服务评估Skill
|
||||
|
||||
详见 [practice/ecosystem-service-skill](./practice/ecosystem-service-skill/)
|
||||
|
||||
### 实践案例03:最小累积阻力(MCR)分析的自动化
|
||||
|
||||
详见 [practice/mcr-automation](./practice/mcr-automation/)
|
||||
|
||||
---
|
||||
|
||||
## 关键要点预览
|
||||
|
||||
1. **空间表征**是空间智能的基础,选择合适的表征方式至关重要
|
||||
2. **空间推理**基于几何和拓扑关系,是空间分析的核心算法
|
||||
3. **多准则决策**平衡多个目标,需要合理的权重设计和敏感性分析
|
||||
4. **空间优化**寻找最优空间配置,是决策支持的关键
|
||||
5. **不确定性量化**让分析结果更可靠,支持稳健决策
|
||||
|
||||
---
|
||||
|
||||
## 延伸资源
|
||||
|
||||
- **"Geographic Information Systems and Science"** (Longley) - GIS基础理论
|
||||
- **"Spatial Analysis"** (O'Sullivan) - 空间分析方法
|
||||
- **"Geocomputation with R"** - 空间计算实践
|
||||
Reference in New Issue
Block a user