# 01.3 概率与不确定性 ## 核心问题 > 空间分析中的不确定性从何而来? > AI系统如何表示和处理不确定性? > 如何在不确定性下做出稳健的决策? --- ## 概念讲解 ### 不确定性的来源 在空间分析和AI系统中,不确定性无处不在: ``` 空间分析中的不确定性来源 ┌─────────────────────────────────────────────────────────────┐ │ │ │ 1. 数据不确定性 │ │ - 测量误差 │ │ - 空间采样不完整 │ │ - 分类错误 │ │ - 时间延迟 │ │ │ │ 2. 参数不确定性 │ │ - 阻力权重不确定 │ │ - 阈值选择主观 │ │ - 模型参数拟合误差 │ │ │ │ 3. 结构不确定性 │ │ - 模型选择 │ │ - 变量关系假设 │ │ - 尺度效应 │ │ │ │ 4. 语义不确定性 │ │ - 概念模糊("生态质量"是什么?) │ │ - 分类边界不清 │ │ - 专家意见分歧 │ │ │ └─────────────────────────────────────────────────────────────┘ ``` ### 不确定性的类型 | 类型 | 说明 | 例子 | |-----|------|------| | **偶然不确定性** (Aleatoric) | 系统固有的随机性,无法通过更多数据消除 | 降雨量的随机波动 | | **认知不确定性** (Epistemic) | 知识不足导致的不确定性,可通过更多数据减少 | 未调查区域的物种分布 | | **模糊性** (Ambiguity) | 概念或分类的不明确 | "高生态价值"的定义 | | **冲突** (Conflict) | 不同信息源的不一致 | 两个专家给出相反意见 | ### AI如何处理不确定性 **传统GIS vs 概率AI**: ``` 传统GIS: 确定性输出 输入 → [处理] → 单一结果 例如:这个区域是/不是生态源地 概率AI: 概率输出 输入 → [处理] → (结果, 置信度) 例如:这个区域是生态源地的概率是 0.78 ± 0.12 ``` **置信度的表示**: ```python # 方式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 } ``` --- ## 设计原理 ### 不确定性传播 当多个步骤串联时,不确定性会累积: ```python """ 不确定性传播示例 """ 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() ``` ### 敏感性分析 了解哪些参数对结果影响最大: ```python """ 敏感性分析:识别关键参数 """ 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() ``` ### 鲁棒决策 当不确定性无法消除时,做鲁棒的决策: ```python """ 鲁棒决策:在不确定性下的稳健决策 """ 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() ``` --- ## 代码示例 ### 概率源地识别 ```python """ 带不确定性的生态源地识别 """ 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. 源地识别的不确定性** ```python 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. 阻力面的敏感性分析** ```python 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 ``` --- ## 反思与延伸 ### 思考问题 1. **不确定性识别**:在你的项目中,不确定性来自哪些方面?哪些是可减少的,哪些是固有的? 2. **表示选择**:你应该用标准差、置信区间,还是概率分布?各有什么优劣? 3. **决策权衡**:当不确定性很高时,你应该继续分析还是寻求更多数据? 4. **沟通问题**:如何向非专家解释不确定性? ### 实践练习 1. **不确定性审计**:对一个分析流程,识别所有不确定性来源并分类 2. **敏感性分析**:对你熟悉的空间模型进行敏感性分析 3. **鲁棒决策**:为你的项目设计一个鲁棒决策框架 ### 延伸阅读 - **"Uncertainty Quantification in Predictive Modeling"** - 不确定性量化的理论基础 - **"Flaw of Averages"** (Sam Savage) - 为什么平均值会误导 - **空间数据质量标准** - 空间不确定性的行业实践 --- ## 关键要点 1. **不确定性在空间分析中普遍存在**,有多个来源 2. **偶然不确定性无法消除**,认知不确定性可以通过更多数据减少 3. **不确定性会传播**,多步骤分析需要考虑累积效应 4. **敏感性分析识别关键参数**,优先减少高敏感参数的不确定性 5. **鲁棒决策在不确定性下做稳健选择**,而非追求最优