a90f7adfa1
将 Markdown 源文件移入 md/,LaTeX 工作目录保留在 latex/, Word 导出移入 word/;删除临时脚本、调试截图和空 stub。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
21 KiB
21 KiB
01.3 概率与不确定性
核心问题
空间分析中的不确定性从何而来? AI系统如何表示和处理不确定性? 如何在不确定性下做出稳健的决策?
概念讲解
不确定性的来源
在空间分析和AI系统中,不确定性无处不在:
空间分析中的不确定性来源
┌─────────────────────────────────────────────────────────────┐
│ │
│ 1. 数据不确定性 │
│ - 测量误差 │
│ - 空间采样不完整 │
│ - 分类错误 │
│ - 时间延迟 │
│ │
│ 2. 参数不确定性 │
│ - 阻力权重不确定 │
│ - 阈值选择主观 │
│ - 模型参数拟合误差 │
│ │
│ 3. 结构不确定性 │
│ - 模型选择 │
│ - 变量关系假设 │
│ - 尺度效应 │
│ │
│ 4. 语义不确定性 │
│ - 概念模糊("生态质量"是什么?) │
│ - 分类边界不清 │
│ - 专家意见分歧 │
│ │
└─────────────────────────────────────────────────────────────┘
不确定性的类型
| 类型 | 说明 | 例子 |
|---|---|---|
| 偶然不确定性 (Aleatoric) | 系统固有的随机性,无法通过更多数据消除 | 降雨量的随机波动 |
| 认知不确定性 (Epistemic) | 知识不足导致的不确定性,可通过更多数据减少 | 未调查区域的物种分布 |
| 模糊性 (Ambiguity) | 概念或分类的不明确 | "高生态价值"的定义 |
| 冲突 (Conflict) | 不同信息源的不一致 | 两个专家给出相反意见 |
AI如何处理不确定性
传统GIS vs 概率AI:
传统GIS: 确定性输出
输入 → [处理] → 单一结果
例如:这个区域是/不是生态源地
概率AI: 概率输出
输入 → [处理] → (结果, 置信度)
例如:这个区域是生态源地的概率是 0.78 ± 0.12
置信度的表示:
# 方式1: 点估计 + 置信区间
estimate = 0.75
confidence_interval = (0.65, 0.85)
# 方式2: 概率分布
from scipy.stats import beta
distribution = beta(a=8, b=3) # 基于共8次成功,3次失败
# 方式3: 分类概率
class_probabilities = {
"high_suitability": 0.65,
"medium_suitability": 0.25,
"low_suitability": 0.10
}
# 方式4: 模糊隶属度
fuzzy_membership = {
"is_source": 0.72,
"is_not_source": 0.28
}
设计原理
不确定性传播
当多个步骤串联时,不确定性会累积:
"""
不确定性传播示例
"""
import numpy as np
from scipy.stats import norm
class UncertainValue:
"""带不确定性的值"""
def __init__(self, mean, std):
self.mean = mean
self.std = std
def __add__(self, other):
"""加法:方差相加"""
return UncertainValue(
self.mean + other.mean,
np.sqrt(self.std**2 + other.std**2)
)
def __mul__(self, scalar):
"""乘以标量:标准差也乘"""
return UncertainValue(
self.mean * scalar,
self.std * abs(scalar)
)
def __repr__(self):
return f"{self.mean:.2f} ± {self.std:.2f}"
# 示例:源地适宜性评估中的不确定性传播
def assess_suitability_with_uncertainty():
"""
每个指标都有测量不确定性,
最终的适宜性评分会累积这些不确定性
"""
# 各项指标(均值 ± 标准差)
vegetation_quality = UncertainValue(0.75, 0.10)
connectivity = UncertainValue(0.60, 0.15)
distance_to_threat = UncertainValue(0.80, 0.08)
# 加权组合(权重也有不确定性)
weights = {
"vegetation": 0.4,
"connectivity": 0.3,
"distance": 0.3
}
# 计算总分(简化传播)
total = (vegetation_quality * weights["vegetation"] +
connectivity * weights["connectivity"] +
distance_to_threat * weights["distance"])
print("各指标不确定性:")
print(f" 植被质量: {vegetation_quality}")
print(f" 连通性: {connectivity}")
print(f" 威胁距离: {distance_to_threat}")
print(f"\n总分: {total}")
print(f" 置信区间95%: [{total.mean - 1.96*total.std:.2f}, "
f"{total.mean + 1.96*total.std:.2f}]")
return total
if __name__ == "__main__":
assess_suitability_with_uncertainty()
敏感性分析
了解哪些参数对结果影响最大:
"""
敏感性分析:识别关键参数
"""
import numpy as np
from typing import Dict, List, Tuple
def sensitivity_analysis(model_fn, param_ranges: Dict[str, Tuple[float, float]],
n_samples=1000) -> Dict[str, float]:
"""
使用蒙特卡洛方法进行敏感性分析
Args:
model_fn: 模型函数,接受参数字典,返回结果
param_ranges: 参数范围 {param_name: (min, max)}
n_samples: 采样次数
Returns:
各参数的敏感性系数
"""
results = {param: [] for param in param_ranges}
model_outputs = []
# 蒙特卡洛采样
for _ in range(n_samples):
# 随机采样参数
sample = {k: np.random.uniform(v[0], v[1])
for k, v in param_ranges.items()}
# 记录参数值
for param, value in sample.items():
results[param].append(value)
# 计算模型输出
output = model_fn(sample)
model_outputs.append(output)
# 计算相关性作为敏感性指标
sensitivities = {}
for param in param_ranges:
correlation = np.corrcoef(results[param], model_outputs)[0, 1]
sensitivities[param] = abs(correlation)
return sensitivities
# 示例:生态阻力面构建的敏感性分析
def resistance_model(params):
"""简化的阻力面模型"""
# 参数:各土地类型的阻力权重
forest_weight = params["forest"]
grass_weight = params["grass"]
urban_weight = params["urban"]
# 简化:计算平均阻力
# 实际应用中会是空间计算
landscape_composition = {
"forest": 0.4,
"grass": 0.3,
"urban": 0.3
}
total_resistance = (
forest_weight * landscape_composition["forest"] +
grass_weight * landscape_composition["grass"] +
urban_weight * landscape_composition["urban"]
)
return total_resistance
def run_sensitivity_example():
"""运行敏感性分析示例"""
print("=== 阻力面参数敏感性分析 ===\n")
# 定义参数范围
param_ranges = {
"forest": (1, 10),
"grass": (10, 50),
"urban": (50, 200)
}
# 运行敏感性分析
sensitivities = sensitivity_analysis(
resistance_model,
param_ranges,
n_samples=5000
)
# 排序并输出
sorted_sens = sorted(sensitivities.items(),
key=lambda x: x[1], reverse=True)
print("参数敏感性排序:")
for param, sensitivity in sorted_sens:
bar = "█" * int(sensitivity * 30)
print(f" {param}: {sensitivity:.3f} {bar}")
print("\n解释:")
print(f" 最敏感的参数是 {sorted_sens[0][0]}")
print(f" 应当优先精确确定该参数的值")
if __name__ == "__main__":
run_sensitivity_example()
鲁棒决策
当不确定性无法消除时,做鲁棒的决策:
"""
鲁棒决策:在不确定性下的稳健决策
"""
from typing import List, Callable
import numpy as np
def robust_decision_scenarios():
"""
鲁棒决策的几种策略
"""
# 策略1: 最大最小 (Maximin) - 最坏情况最优
def maximin(payoff_matrix):
"""
选择在最坏情况下表现最好的选项
payoff_matrix: 选项 × 场景 的收益矩阵
"""
worst_case_outcomes = payoff_matrix.min(axis=1)
best_option = worst_case_outcomes.argmax()
return best_option, worst_case_outcomes
# 策略2: 最大平均 (Maximum Expected Value)
def max_expected(payoff_matrix, probabilities=None):
"""选择期望收益最大的选项"""
if probabilities is None:
probabilities = np.ones(payoff_matrix.shape[1]) / payoff_matrix.shape[1]
expected_values = payoff_matrix @ probabilities
best_option = expected_values.argmax()
return best_option, expected_values
# 策略3: 最小后悔 (Minimax Regret)
def minimax_regret(payoff_matrix):
"""选择最小化最大后悔的选项"""
# 每个场景的最佳收益
best_per_scenario = payoff_matrix.max(axis=0)
# 后悔矩阵:每个选项在每个场景与最佳的差距
regret_matrix = best_per_scenario - payoff_matrix
# 每个选项的最大后悔
max_regret = regret_matrix.max(axis=1)
# 选择最大后悔最小的选项
best_option = max_regret.argmin()
return best_option, max_regret
# 示例:生态廊道选址决策
# 选项:3个候选廊道路线
# 场景:不同的未来土地变化情景
payoff_matrix = np.array([
# 情景1 情景2 情景3 情景4
[80, 60, 40, 70], # 选项A:穿过森林
[50, 90, 70, 50], # 选项B:沿河流
[60, 70, 90, 60], # 选项C:绕行城市边缘
])
print("=== 生态廊道选址:鲁棒决策分析 ===\n")
print("收益矩阵(廊道质量评分):")
print(" 情景1 情景2 情景3 情景4")
for i, row in enumerate(payoff_matrix, ord('A')):
print(f"选项{i}: {row}")
print("\n--- 策略1: 最大最小 (最坏情况最优) ---")
option, worst = maximin(payoff_matrix)
print(f"推荐: 选项{chr(ord('A') + option)}")
print(f"各选项最坏情况: {worst}")
print(" 原理: 选择在最坏情景下表现最好的")
print("\n--- 策略2: 最大期望 (平均收益最大) ---")
option, expected = max_expected(payoff_matrix)
print(f"推荐: 选项{chr(ord('A') + option)}")
print(f"各选项期望收益: {expected}")
print(" 原理: 选择平均表现最好的")
print("\n--- 策略3: 最小最大后悔 ---")
option, regret = minimax_regret(payoff_matrix)
print(f"推荐: 选项{chr(ord('A') + option)}")
print(f"各选项最大后悔: {regret}")
print(" 原理: 选择让'选错'的后悔最小的")
return payoff_matrix
if __name__ == "__main__":
robust_decision_scenarios()
代码示例
概率源地识别
"""
带不确定性的生态源地识别
"""
import numpy as np
from scipy.stats import beta
from typing import Dict, List, Tuple
class ProbabilisticSource:
"""概率源地:带置信度的源地"""
def __init__(self, source_id: int, geometry,
probability: float, confidence: float):
self.id = source_id
self.geometry = geometry
self.probability = probability # 是源地的概率
self.confidence = confidence # 概率估计的置信度
def __repr__(self):
return (f"Source({self.id}, P={self.probability:.2f}±{self.confidence:.2f})")
class ProbabilisticSourceIdentifier:
"""概率源地识别器"""
def __init__(self, threshold=0.5):
self.threshold = threshold
def identify(self, landscape_data) -> List[ProbabilisticSource]:
"""
识别源地,返回概率源地
返回的不是"是/否"的判断,而是"是源地的概率"
"""
sources = []
# 模拟:对每个斑块计算是源地的概率
for i, patch in enumerate(landscape_data):
# 基于多个指标计算概率
probability = self._calculate_source_probability(patch)
# 估计置信度(基于数据质量)
confidence = self._estimate_confidence(patch)
if probability >= self.threshold:
source = ProbabilisticSource(
source_id=i,
geometry=patch['geometry'],
probability=probability,
confidence=confidence
)
sources.append(source)
return sources
def _calculate_source_probability(self, patch) -> float:
"""计算斑块是源地的概率"""
# 使用贝叶斯推理
# P(是源地|数据) ∝ P(数据|是源地) × P(是源地)
# 各指标的似然
area_likelihood = self._area_likelihood(patch['area'])
veg_likelihood = self._vegetation_likelihood(patch['vegetation'])
shape_likelihood = self._shape_likelihood(patch['shape_index'])
# 先验概率
prior = 0.3 # 假设30%的斑块可能是源地
# 后验概率(简化)
probability = (area_likelihood * veg_likelihood *
shape_likelihood * prior)
probability = min(probability, 1.0) # 限制在[0,1]
return probability
def _area_likelihood(self, area: float) -> float:
"""面积似然:大面积更像源地"""
if area > 1000:
return 1.0
elif area > 500:
return 0.7
else:
return 0.3
def _vegetation_likelihood(self, veg_quality: float) -> float:
"""植被质量似然"""
return veg_quality # 假设已归一化到[0,1]
def _shape_likelihood(self, shape_index: float) -> float:
"""形状指数似然:紧凑形状更好"""
return 1.0 - min(abs(shape_index - 1.0), 0.5)
def _estimate_confidence(self, patch) -> float:
"""估计概率的置信度"""
# 基于数据质量、分辨率等因素
data_quality = patch.get('data_quality', 0.8)
resolution_factor = patch.get('resolution', 30) / 30 # 归一化
return data_quality * min(resolution_factor, 1.0)
def uncertainty_propagation_example():
"""不确定性传播示例"""
print("=== 不确定性传播示例 ===\n")
# 创建一些模拟斑块
patches = [
{'id': 1, 'area': 1200, 'vegetation': 0.85, 'shape_index': 1.2,
'geometry': 'POLYGON(...)', 'data_quality': 0.9},
{'id': 2, 'area': 800, 'vegetation': 0.75, 'shape_index': 1.5,
'geometry': 'POLYGON(...)', 'data_quality': 0.7},
{'id': 3, 'area': 400, 'vegetation': 0.65, 'shape_index': 1.8,
'geometry': 'POLYGON(...)', 'data_quality': 0.6},
]
identifier = ProbabilisticSourceIdentifier(threshold=0.4)
sources = identifier.identify(patches)
print("识别到的概率源地:")
for source in sources:
print(f" {source}")
# 计算整体不确定性
if sources:
avg_prob = np.mean([s.probability for s in sources])
avg_conf = np.mean([s.confidence for s in sources])
print(f"\n总体置信度: {avg_conf:.2f}")
print(f"平均源地概率: {avg_prob:.2f}")
# 置信区间
margin_of_error = (1 - avg_conf) * 0.2 # 简化计算
print(f"源地数量估计: {len(sources)} ± {margin_of_error * len(sources):.1f}")
if __name__ == "__main__":
uncertainty_propagation_example()
案例分析
ENAgent中的不确定性处理
在ENAgent项目中,不确定性处理体现在:
1. 源地识别的不确定性
class ENAgentSourceIdentifier:
"""ENAgent的源地识别模块"""
def identify_with_uncertainty(self, landcover, species_params):
"""
识别源地,同时估计不确定性
Returns:
sources: 源地列表
uncertainty_map: 不确定性空间分布
"""
sources = []
uncertainty_map = np.zeros_like(landcover)
# 对每个候选斑块
for patch in self._candidate_patches(landcover):
# 计算适宜性(考虑物种参数)
suitability = self._calculate_suitability(patch, species_params)
# 估计不确定性(来自多个来源)
uncertainty = self._estimate_uncertainty(
patch,
data_quality=landcover.metadata['quality'],
species_uncertainty=species_params['uncertainty']
)
# 记录
if suitability > self.threshold:
sources.append({
'geometry': patch,
'suitability': suitability,
'uncertainty': uncertainty
})
# 更新不确定性地图
self._add_to_uncertainty_map(uncertainty_map, patch, uncertainty)
return sources, uncertainty_map
def _estimate_uncertainty(self, patch, data_quality, species_uncertainty):
"""
估计源地识别的不确定性
来源:
1. 数据质量 (data_quality)
2. 物种参数的不确定性 (species_uncertainty)
3. 分类误差 (classification_error)
4. 边界效应 (edge_effect)
"""
# 组合各种不确定性源
uncertainty = np.sqrt(
(1 - data_quality)**2 +
species_uncertainty**2 +
0.1**2 + # 分类误差
self._edge_uncertainty(patch)**2
)
return min(uncertainty, 1.0)
2. 阻力面的敏感性分析
class ResistanceSurfaceSensitivity:
"""阻力面敏感性分析"""
def analyze(self, base_weights, variation_ranges, n_simulations=1000):
"""
分析阻力面权重对结果的敏感性
Args:
base_weights: 基础权重 {land_type: weight}
variation_ranges: 权重变化范围 {land_type: (min, max)}
n_simulations: 蒙特卡洛模拟次数
Returns:
sensitivity_results: 敏感性分析结果
"""
results = []
for _ in range(n_simulations):
# 随机采样权重
sample_weights = {}
for land_type, (min_w, max_w) in variation_ranges.items():
sample_weights[land_type] = np.random.uniform(min_w, max_w)
# 计算对应的阻力面
resistance = self._compute_resistance(sample_weights)
# 评估结果(例如:平均连通性)
connectivity = self._assess_connectivity(resistance)
results.append({
'weights': sample_weights,
'connectivity': connectivity
})
# 分析敏感性
sensitivity = self._compute_sensitivity(results, base_weights)
return sensitivity
def _compute_sensitivity(self, results, base_weights):
"""计算各土地类型的敏感性"""
# 计算每个权重变化与连通性变化的相关性
sensitivities = {}
for land_type in base_weights:
weight_values = [r['weights'][land_type] for r in results]
connectivity_values = [r['connectivity'] for r in results]
correlation = np.corrcoef(weight_values, connectivity_values)[0, 1]
sensitivities[land_type] = abs(correlation)
return sensitivities
反思与延伸
思考问题
-
不确定性识别:在你的项目中,不确定性来自哪些方面?哪些是可减少的,哪些是固有的?
-
表示选择:你应该用标准差、置信区间,还是概率分布?各有什么优劣?
-
决策权衡:当不确定性很高时,你应该继续分析还是寻求更多数据?
-
沟通问题:如何向非专家解释不确定性?
实践练习
-
不确定性审计:对一个分析流程,识别所有不确定性来源并分类
-
敏感性分析:对你熟悉的空间模型进行敏感性分析
-
鲁棒决策:为你的项目设计一个鲁棒决策框架
延伸阅读
- "Uncertainty Quantification in Predictive Modeling" - 不确定性量化的理论基础
- "Flaw of Averages" (Sam Savage) - 为什么平均值会误导
- 空间数据质量标准 - 空间不确定性的行业实践
关键要点
- 不确定性在空间分析中普遍存在,有多个来源
- 偶然不确定性无法消除,认知不确定性可以通过更多数据减少
- 不确定性会传播,多步骤分析需要考虑累积效应
- 敏感性分析识别关键参数,优先减少高敏感参数的不确定性
- 鲁棒决策在不确定性下做稳健选择,而非追求最优