Files
2026_DesignAI/dofile/examples/02-spatial-intelligence/uncertainty_analysis.py
T
pengxiao 219232de74 refactor: 重组项目目录结构
以讲义内容为骨架迁移到标准目录格式:
- officefile/ 主内容(12章 + 附录 + CC4SI补充)
- dofile/ 代码示例(11个Python脚本)
- data/ 图片资源
- output/ 生成输出(忽略)
- Archive/ 归档旧目录(忽略)
- .claude/skills/ 保留markdown-to-docx工具链
- .pandoc/ 保留CSL和本地化配置

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 14:00:56 +08:00

1043 lines
32 KiB
Python

"""
不确定性分析示例 (Uncertainty Analysis Example)
==============================================
本示例展示空间智能系统中的不确定性分析方法。
在空间决策中,不确定性来自数据、模型和参数等多个方面。
核心概念:
1. 不确定性来源 - 数据误差、模型简化、参数变异
2. 不确定性传播 - 输入不确定性如何影响输出
3. 蒙特卡洛分析 - 随机采样评估不确定性
4. 敏感性分析 - 识别关键不确定性源
5. 场景分析 - 不同假设下的结果比较
应用场景:
- 风险评估
- 决策稳健性分析
- 模型可信度评估
- 数据质量评估
作者: CC4SI 项目组
"""
import math
import random
from typing import List, Dict, Tuple, Optional, Any, Callable
from dataclasses import dataclass, field
from enum import Enum
from abc import ABC, abstractmethod
import statistics
# ============================================================================
# 不确定性类型
# ============================================================================
class UncertaintyType(Enum):
"""不确定性类型"""
EPISTEMIC = "epistemic" # 认识不确定性 (可通过更多知识减少)
ALEATORY = "aleatory" # 偶然不确定性 (固有随机性)
PARAMETRIC = "parametric" # 参数不确定性
STRUCTURAL = "structural" # 结构不确定性 (模型形式)
DATA = "data" # 数据不确定性
@dataclass
class UncertainValue:
"""
不确定值
表示一个带有不确定性的数值。
"""
value: float
uncertainty: float # 标准差或误差范围
uncertainty_type: UncertaintyType = UncertaintyType.EPISTEMIC
distribution: str = "normal" # 假设的分布类型
@property
def coefficient_of_variation(self) -> float:
"""变异系数"""
if self.value == 0:
return float('inf')
return self.uncertainty / abs(self.value)
def confidence_interval(self, confidence: float = 0.95) -> Tuple[float, float]:
"""
计算置信区间
Args:
confidence: 置信水平
Returns:
(下界, 上界)
"""
if self.distribution == "normal":
# 使用正态分布
z_scores = {0.90: 1.645, 0.95: 1.96, 0.99: 2.576}
z = z_scores.get(confidence, 1.96)
return (
self.value - z * self.uncertainty,
self.value + z * self.uncertainty
)
else:
# 简单区间
return (
self.value - self.uncertainty,
self.value + self.uncertainty
)
def sample(self) -> float:
"""从分布中采样"""
if self.distribution == "normal":
return random.gauss(self.value, self.uncertainty)
elif self.distribution == "uniform":
return random.uniform(
self.value - self.uncertainty,
self.value + self.uncertainty
)
else:
return self.value
def __repr__(self) -> str:
return f"{self.value:.2f} ± {self.uncertainty:.2f}"
# ============================================================================
# 概率分布
# ============================================================================
class ProbabilityDistribution(ABC):
"""概率分布抽象基类"""
def __init__(self, name: str = ""):
self.name = name
@abstractmethod
def sample(self) -> float:
"""采样"""
pass
@abstractmethod
def mean(self) -> float:
"""期望值"""
pass
@abstractmethod
def std(self) -> float:
"""标准差"""
pass
class NormalDistribution(ProbabilityDistribution):
"""正态分布"""
def __init__(self, mu: float, sigma: float, name: str = ""):
super().__init__(name)
self.mu = mu
self.sigma = sigma
def sample(self) -> float:
return random.gauss(self.mu, self.sigma)
def mean(self) -> float:
return self.mu
def std(self) -> float:
return self.sigma
class UniformDistribution(ProbabilityDistribution):
"""均匀分布"""
def __init__(self, a: float, b: float, name: str = ""):
super().__init__(name)
self.a = a
self.b = b
def sample(self) -> float:
return random.uniform(self.a, self.b)
def mean(self) -> float:
return (self.a + self.b) / 2
def std(self) -> float:
return (self.b - self.a) / math.sqrt(12)
class TriangularDistribution(ProbabilityDistribution):
"""三角分布"""
def __init__(self, a: float, b: float, c: float, name: str = ""):
"""
三角分布
Args:
a: 最小值
b: 最大值
c: 众数
"""
super().__init__(name)
self.a = a
self.b = b
self.c = c
def sample(self) -> float:
u = random.random()
fc = (self.c - self.a) / (self.b - self.a)
if u < fc:
return self.a + math.sqrt(u * (self.b - self.a) * (self.c - self.a))
else:
return self.b - math.sqrt((1 - u) * (self.b - self.a) * (self.b - self.c))
def mean(self) -> float:
return (self.a + self.b + self.c) / 3
def std(self) -> float:
numerator = (self.a**2 + self.b**2 + self.c**2 -
self.a * self.b - self.a * self.c - self.b * self.c)
return math.sqrt(numerator / 18)
# ============================================================================
# 不确定性传播
# ============================================================================
class UncertaintyPropagator:
"""
不确定性传播器
分析输入不确定性如何影响输出。
"""
def __init__(self, model: Callable[[Dict[str, float]], float]):
"""
初始化传播器
Args:
model: 输入字典到输出值的函数
"""
self.model = model
def first_order_second_moment(self,
inputs: Dict[str, UncertainValue]) -> UncertainValue:
"""
一阶二矩法 (FOSM)
使用一阶泰勒展开近似传播不确定性。
Args:
inputs: 不确定输入字典
Returns:
不确定输出
"""
# 计算名义值
nominal_inputs = {k: v.value for k, v in inputs.items()}
nominal_output = self.model(nominal_inputs)
# 计算灵敏度 (数值微分)
sensitivities = {}
epsilon = 1e-6
for name, uncertain_val in inputs.items():
perturbed = nominal_inputs.copy()
perturbed[name] += epsilon
output_plus = self.model(perturbed)
sensitivity = (output_plus - nominal_output) / epsilon
sensitivities[name] = sensitivity
# 计算输出方差 (假设输入独立)
output_variance = 0.0
for name, uncertain_val in inputs.items():
sensitivity = sensitivities[name]
output_variance += (sensitivity * uncertain_val.uncertainty) ** 2
output_std = math.sqrt(output_variance)
return UncertainValue(
value=nominal_output,
uncertainty=output_std,
uncertainty_type=UncertaintyType.EPISTEMIC
)
def monte_carlo_propagation(self,
input_distributions: Dict[str, ProbabilityDistribution],
n_samples: int = 10000) -> Dict[str, Any]:
"""
蒙特卡洛传播
Args:
input_distributions: 输入分布字典
n_samples: 采样次数
Returns:
统计结果字典
"""
samples = []
for _ in range(n_samples):
# 采样输入
inputs = {name: dist.sample() for name, dist in input_distributions.items()}
# 计算输出
output = self.model(inputs)
samples.append(output)
# 计算统计量
return {
"mean": statistics.mean(samples),
"std": statistics.stdev(samples) if len(samples) > 1 else 0,
"min": min(samples),
"max": max(samples),
"median": statistics.median(samples),
"percentiles": {
5: self._percentile(samples, 5),
25: self._percentile(samples, 25),
75: self._percentile(samples, 75),
95: self._percentile(samples, 95)
},
"samples": samples
}
def _percentile(self, data: List[float], p: float) -> float:
"""计算百分位数"""
sorted_data = sorted(data)
index = int(p / 100 * len(sorted_data))
return sorted_data[min(index, len(sorted_data) - 1)]
# ============================================================================
# 敏感性分析
# ============================================================================
@dataclass
class SensitivityMeasure:
"""敏感性度量"""
parameter_name: str
sensitivity: float # 敏感性系数
rank: int = 0 # 排名
method: str = "" # 计算方法
class SensitivityAnalyzer:
"""
敏感性分析器
识别对输出影响最大的输入参数。
"""
def __init__(self, model: Callable[[Dict[str, float]], float]):
"""
初始化分析器
Args:
model: 输入字典到输出值的函数
"""
self.model = model
def local_sensitivity(self,
nominal_values: Dict[str, float],
perturbation: float = 0.01) -> List[SensitivityMeasure]:
"""
局部敏感性分析
Args:
nominal_values: 名义输入值
perturbation: 扰动比例
Returns:
敏感性度量列表
"""
nominal_output = self.model(nominal_values)
sensitivities = []
for param_name in nominal_values.keys():
# 正向扰动
perturbed_plus = nominal_values.copy()
perturbed_plus[param_name] *= (1 + perturbation)
output_plus = self.model(perturbed_plus)
# 计算敏感性 (归一化)
delta_output = output_plus - nominal_output
sensitivity = delta_output / (perturbation * nominal_values[param_name])
sensitivities.append({
"parameter": param_name,
"sensitivity": sensitivity,
"delta_output": delta_output
})
# 排序 (绝对值)
sensitivities.sort(key=lambda x: abs(x["sensitivity"]), reverse=True)
measures = []
for i, s in enumerate(sensitivities, 1):
measures.append(SensitivityMeasure(
parameter_name=s["parameter"],
sensitivity=s["sensitivity"],
rank=i,
method="local"
))
return measures
def variance_based_sensitivity(self,
input_distributions: Dict[str, ProbabilityDistribution],
n_samples: int = 1000) -> List[SensitivityMeasure]:
"""
基于方差的敏感性分析 (Sobol指数近似)
Args:
input_distributions: 输入分布
n_samples: 样本数
Returns:
敏感性度量列表
"""
# 使用随机平衡设计近似一阶Sobol指数
samples = []
for _ in range(n_samples):
inputs = {name: dist.sample() for name, dist in input_distributions.items()}
outputs = self.model(inputs)
samples.append((inputs, outputs))
# 计算总方差
output_values = [s[1] for s in samples]
total_variance = statistics.variance(output_values) if len(output_values) > 1 else 0
if total_variance == 0:
return []
sensitivities = []
for param_name in input_distributions.keys():
# 计算条件方差 (简化: 使用回归方法)
param_values = [s[0][param_name] for s in samples]
# 线性回归 R²
mean_x = statistics.mean(param_values)
mean_y = statistics.mean(output_values)
numerator = sum((x - mean_x) * (y - mean_y)
for x, y in zip(param_values, output_values))
denominator_x = sum((x - mean_x)**2 for x in param_values)
denominator_y = sum((y - mean_y)**2 for y in output_values)
if denominator_x == 0 or denominator_y == 0:
first_order = 0
else:
correlation = numerator / math.sqrt(denominator_x * denominator_y)
first_order = correlation ** 2
sensitivities.append({
"parameter": param_name,
"sensitivity": first_order,
"variance_contribution": first_order * total_variance
})
# 排序
sensitivities.sort(key=lambda x: x["sensitivity"], reverse=True)
measures = []
for i, s in enumerate(sensitivities, 1):
measures.append(SensitivityMeasure(
parameter_name=s["parameter"],
sensitivity=s["sensitivity"],
rank=i,
method="sobol"
))
return measures
# ============================================================================
# 场景分析
# ============================================================================
@dataclass
class Scenario:
"""场景"""
name: str
description: str
parameters: Dict[str, float]
probability: float = 1.0
class ScenarioAnalyzer:
"""
场景分析器
评估不同假设情景下的结果。
"""
def __init__(self, model: Callable[[Dict[str, float]], float]):
"""
初始化分析器
Args:
model: 输入字典到输出值的函数
"""
self.model = model
def evaluate_scenarios(self,
scenarios: List[Scenario]) -> List[Dict[str, Any]]:
"""
评估多个场景
Args:
scenarios: 场景列表
Returns:
评估结果列表
"""
results = []
for scenario in scenarios:
output = self.model(scenario.parameters)
results.append({
"scenario": scenario.name,
"description": scenario.description,
"probability": scenario.probability,
"output": output,
"parameters": scenario.parameters.copy()
})
return results
def generate_scenarios(self,
base_parameters: Dict[str, float],
variations: Dict[str, Tuple[float, float]]) -> List[Scenario]:
"""
生成场景 (基准、乐观、悲观)
Args:
base_parameters: 基准参数
variations: 参数变化范围字典
Returns:
场景列表
"""
scenarios = [
Scenario(
name="基准",
description="预期情况",
parameters=base_parameters.copy(),
probability=0.5
)
]
# 乐观场景
optimistic = base_parameters.copy()
for param, (low, high) in variations.items():
if param in base_parameters:
# 选择有利方向的值
if "成本" in param or "cost" in param.lower():
optimistic[param] = low # 成本取低
else:
optimistic[param] = high # 其他取高
scenarios.append(Scenario(
name="乐观",
description="最佳情况",
parameters=optimistic,
probability=0.25
))
# 悲观场景
pessimistic = base_parameters.copy()
for param, (low, high) in variations.items():
if param in base_parameters:
if "成本" in param or "cost" in param.lower():
pessimistic[param] = high # 成本取高
else:
pessimistic[param] = low # 其他取低
scenarios.append(Scenario(
name="悲观",
description="最差情况",
parameters=pessimistic,
probability=0.25
))
return scenarios
# ============================================================================
# 稳健性分析
# ============================================================================
class RobustnessAnalyzer:
"""
稳健性分析器
评估决策在不同条件下的稳健程度。
"""
def __init__(self, model: Callable[[Dict[str, float]], float]):
"""
初始化分析器
Args:
model: 输入字典到输出值的函数
"""
self.model = model
def worst_case_analysis(self,
nominal_values: Dict[str, float],
uncertainties: Dict[str, float],
n_samples: int = 1000) -> Dict[str, Any]:
"""
最坏情况分析
Args:
nominal_values: 名义值
uncertainties: 不确定性范围
n_samples: 采样次数
Returns:
分析结果
"""
samples = []
for _ in range(n_samples):
perturbed = {}
for param, nominal in nominal_values.items():
uncertainty = uncertainties.get(param, 0)
# 均匀采样
perturbed[param] = random.uniform(
nominal - uncertainty,
nominal + uncertainty
)
output = self.model(perturbed)
samples.append(output)
return {
"nominal": self.model(nominal_values),
"best": max(samples),
"worst": min(samples),
"range": max(samples) - min(samples),
"mean": statistics.mean(samples),
"std": statistics.stdev(samples) if len(samples) > 1 else 0,
"percentile_5": self._percentile(samples, 5),
"percentile_95": self._percentile(samples, 95)
}
def regret_analysis(self,
alternatives: List[Dict[str, float]],
scenarios: List[Dict[str, float]],
alternative_names: List[str] = None) -> Dict[str, Any]:
"""
后悔值分析
Args:
alternatives: 备选方案列表
scenarios: 场景列表
alternative_names: 方案名称
Returns:
后悔值分析结果
"""
if alternative_names is None:
alternative_names = [f"方案{i+1}" for i in range(len(alternatives))]
# 计算每个方案在各场景下的结果
results_matrix = []
for alt in alternatives:
row = []
for scenario in scenarios:
# 合并参数
combined = {**alt, **scenario}
output = self.model(combined)
row.append(output)
results_matrix.append(row)
# 找出每个场景下的最优结果
best_per_scenario = []
for j in range(len(scenarios)):
column = [results_matrix[i][j] for i in range(len(alternatives))]
best_per_scenario.append(max(column) if column else 0)
# 计算后悔值矩阵
regret_matrix = []
for i in range(len(alternatives)):
regrets = []
for j in range(len(scenarios)):
regret = best_per_scenario[j] - results_matrix[i][j]
regrets.append(regret)
regret_matrix.append(regrets)
# 计算最大后悔值
max_regrets = [max(regrets) for regrets in regret_matrix]
# 排序
sorted_indices = sorted(range(len(max_regrets)), key=lambda i: max_regrets[i])
return {
"results_matrix": results_matrix,
"regret_matrix": regret_matrix,
"max_regrets": max_regrets,
"minimax_regret_choice": sorted_indices[0] if sorted_indices else None,
"ranking": sorted_indices,
"alternative_names": alternative_names
}
def _percentile(self, data: List[float], p: float) -> float:
"""计算百分位数"""
sorted_data = sorted(data)
index = int(p / 100 * len(sorted_data))
return sorted_data[min(index, len(sorted_data) - 1)]
# ============================================================================
# 空间不确定性应用
# ============================================================================
class SpatialUncertaintyModel:
"""
空间不确定性模型
处理空间数据中的不确定性。
"""
@staticmethod
def uncertain_distance(p1: Tuple[float, float],
p2: Tuple[float, float],
position_error: float = 5.0) -> float:
"""
带不确定性的距离计算
Args:
p1: 点1坐标
p2: 点2坐标
position_error: 位置误差标准差
Returns:
采样距离
"""
# 添加位置误差
x1 = p1[0] + random.gauss(0, position_error)
y1 = p1[1] + random.gauss(0, position_error)
x2 = p2[0] + random.gauss(0, position_error)
y2 = p2[1] + random.gauss(0, position_error)
return math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
@staticmethod
def uncertain_interpolation(target_point: Tuple[float, float],
sample_points: List[Tuple[Tuple[float, float], float]],
measurement_error: float = 0.1,
power: float = 2.0) -> float:
"""
带不确定性的空间插值 (IDW)
Args:
target_point: 目标点
sample_points: 样本点列表 [(坐标, 值), ...]
measurement_error: 测量误差标准差
power: IDW幂次
Returns:
插值结果
"""
tx, ty = target_point
numerator = 0.0
denominator = 0.0
for (sx, sy), value in sample_points:
# 计算距离
distance = math.sqrt((tx - sx)**2 + (ty - sy)**2)
if distance < 1e-10:
# 几乎重合,返回该值加误差
return value + random.gauss(0, measurement_error)
# 添加测量误差
observed_value = value + random.gauss(0, measurement_error)
# 计算权重
weight = 1.0 / (distance ** power)
numerator += weight * observed_value
denominator += weight
if denominator == 0:
return 0.0
return numerator / denominator
# ============================================================================
# 主程序
# ========================================================================
def main():
"""主程序 - 演示不确定性分析的使用"""
print("="*70)
print("不确定性分析示例演示")
print("="*70)
random.seed(42)
# ========================================================================
# 1. 不确定值表示
# ========================================================================
print("\n[部分 1] 不确定值表示")
print("-" * 50)
# 创建不确定值
population = UncertainValue(
value=10000,
uncertainty=500,
uncertainty_type=UncertaintyType.EPISTEMIC,
distribution="normal"
)
print(f"\n人口估计: {population}")
print(f" 变异系数: {population.coefficient_of_variation:.3f}")
print(f" 95% 置信区间: {population.confidence_interval(0.95)}")
# 采样演示
print(f"\n采样示例:")
samples = [population.sample() for _ in range(5)]
print(f" {samples}")
# ========================================================================
# 2. 不确定性传播
# ========================================================================
print("\n\n[部分 2] 不确定性传播")
print("-" * 50)
# 定义模型: 地块价值 = 面积 * 单价 - 开发成本
def land_value_model(inputs):
area = inputs["area"]
unit_price = inputs["unit_price"]
development_cost = inputs["development_cost"]
return area * unit_price - development_cost
propagator = UncertaintyPropagator(land_value_model)
# 定义不确定输入
uncertain_inputs = {
"area": UncertainValue(1000, 50), # 面积: 1000 ± 50 平方米
"unit_price": UncertainValue(5000, 300), # 单价: 5000 ± 300 元/平方米
"development_cost": UncertainValue(100000, 10000) # 开发成本
}
print("\n输入不确定性:")
for name, val in uncertain_inputs.items():
print(f" {name}: {val}")
# 一阶二矩法
fosm_result = propagator.first_order_second_moment(uncertain_inputs)
print(f"\n一阶二矩法 (FOSM) 结果:")
print(f" 地块价值: {fosm_result}")
print(f" 95% 置信区间: {fosm_result.confidence_interval(0.95)}")
# 蒙特卡洛传播
input_dists = {
"area": NormalDistribution(1000, 50),
"unit_price": NormalDistribution(5000, 300),
"development_cost": NormalDistribution(100000, 10000)
}
mc_result = propagator.monte_carlo_propagation(input_dists, n_samples=10000)
print(f"\n蒙特卡洛传播结果:")
print(f" 均值: {mc_result['mean']:.0f}")
print(f" 标准差: {mc_result['std']:.0f}")
print(f" 范围: [{mc_result['min']:.0f}, {mc_result['max']:.0f}]")
print(f" 90% 置信区间: [{mc_result['percentiles'][5]:.0f}, "
f"{mc_result['percentiles'][95]:.0f}]")
# ========================================================================
# 3. 敏感性分析
# ========================================================================
print("\n\n[部分 3] 敏感性分析")
print("-" * 50)
# 局部敏感性
analyzer = SensitivityAnalyzer(land_value_model)
nominal_values = {
"area": 1000,
"unit_price": 5000,
"development_cost": 100000
}
local_sens = analyzer.local_sensitivity(nominal_values, perturbation=0.01)
print("\n局部敏感性分析:")
print(f"{'排名':<6} {'参数':<15} {'敏感性系数':<15} {'影响':<15}")
print("-" * 55)
for s in local_sens:
impact = "" if abs(s.sensitivity) > 100 else "" if abs(s.sensitivity) > 10 else ""
print(f"{s.rank:<6} {s.parameter_name:<15} {s.sensitivity:<15.2f} {impact:<15}")
# 方差基敏感性
var_sens = analyzer.variance_based_sensitivity(input_dists, n_samples=1000)
print("\n基于方差的敏感性 (Sobol指数近似):")
print(f"{'排名':<6} {'参数':<15} {'一阶效应':<15} {'贡献':<15}")
print("-" * 55)
for s in var_sens:
contrib = f"{s.sensitivity * 100:.1f}%"
print(f"{s.rank:<6} {s.parameter_name:<15} {s.sensitivity:<15.4f} {contrib:<15}")
# ========================================================================
# 4. 场景分析
# ========================================================================
print("\n\n[部分 4] 场景分析 - 房地产项目评估")
print("-" * 50)
# 定义项目评估模型
def project_evaluation(inputs):
revenue = inputs["area"] * inputs["selling_price"]
cost = inputs["land_cost"] + inputs["construction_cost"] * inputs["area"]
return revenue - cost
scenario_analyzer = ScenarioAnalyzer(project_evaluation)
base_params = {
"area": 10000,
"selling_price": 15000,
"land_cost": 50000000,
"construction_cost": 8000
}
variations = {
"area": (8000, 12000),
"selling_price": (12000, 18000),
"land_cost": (40000000, 60000000),
"construction_cost": (7000, 9000)
}
scenarios = scenario_analyzer.generate_scenarios(base_params, variations)
print("\n生成的场景:")
for s in scenarios:
print(f" {s.name}: {s.description} (概率: {s.probability})")
# 评估场景
results = scenario_analyzer.evaluate_scenarios(scenarios)
print("\n场景评估结果:")
print(f"{'场景':<10} {'利润(万元)':<15} {'概率':<10}")
print("-" * 40)
for r in results:
profit_wan = r["output"] / 10000
print(f"{r['scenario']:<10} {profit_wan:<15.1f} {r['probability']:<10.1%}")
# 期望值
expected_value = sum(r["output"] * r["probability"] for r in results)
print(f"\n期望利润: {expected_value / 10000:.1f} 万元")
# ========================================================================
# 5. 稳健性分析
# ========================================================================
print("\n\n[部分 5] 稳健性分析")
print("-" * 50)
robustness = RobustnessAnalyzer(project_evaluation)
# 最坏情况分析
uncertainties = {
"area": 1000,
"selling_price": 2000,
"land_cost": 5000000,
"construction_cost": 500
}
worst_case = robustness.worst_case_analysis(base_params, uncertainties, n_samples=1000)
print("\n最坏情况分析:")
print(f" 名义利润: {worst_case['nominal'] / 10000:.1f} 万元")
print(f" 最好情况: {worst_case['best'] / 10000:.1f} 万元")
print(f" 最差情况: {worst_case['worst'] / 10000:.1f} 万元")
print(f" 变化范围: {worst_case['range'] / 10000:.1f} 万元")
print(f" 90% 置信区间: [{worst_case['percentile_5'] / 10000:.1f}, "
f"{worst_case['percentile_95'] / 10000:.1f}] 万元")
# 后悔值分析
alternatives = [
{"area": 8000, "selling_price": 15000, "land_cost": 40000000, "construction_cost": 8000},
{"area": 10000, "selling_price": 15000, "land_cost": 50000000, "construction_cost": 8000},
{"area": 12000, "selling_price": 15000, "land_cost": 60000000, "construction_cost": 8000},
]
scenarios_list = [
{"selling_price": 13000}, # 价格下跌
{"selling_price": 15000}, # 价格平稳
{"selling_price": 17000}, # 价格上涨
]
regret_result = robustness.regret_analysis(
alternatives, scenarios_list,
alternative_names=["小规模", "中规模", "大规模"]
)
print("\n后悔值分析:")
print(f"{'方案':<10} {'最大后悔值(万元)':<20}")
print("-" * 35)
for i, name in enumerate(regret_result["alternative_names"]):
max_regret_wan = regret_result["max_regrets"][i] / 10000
print(f"{name:<10} {max_regret_wan:<20.1f}")
minimax_choice = regret_result["minimax_regret_choice"]
if minimax_choice is not None:
best_name = regret_result["alternative_names"][minimax_choice]
print(f"\n最小最大后悔值推荐: {best_name}")
# ========================================================================
# 6. 空间不确定性
# ========================================================================
print("\n\n[部分 6] 空间不确定性应用")
print("-" * 50)
# GPS定位不确定下的距离测量
point_a = (100, 200)
point_b = (150, 250)
print("\n带位置误差的距离测量:")
print(f" 点A: {point_a}")
print(f" 点B: {point_b}")
print(f" 理论距离: {math.sqrt((150-100)**2 + (250-200)**2):.2f}")
# 多次测量
measurements = [SpatialUncertaintyModel.uncertain_distance(
point_a, point_b, position_error=5
) for _ in range(10)]
print(f" 实际测量 (10次): {[f'{m:.1f}' for m in measurements]}")
print(f" 平均: {statistics.mean(measurements):.2f} ± {statistics.stdev(measurements):.2f}")
# 不确定插值
print("\n带测量误差的空间插值:")
samples = [
((0, 0), 10),
((100, 0), 20),
((0, 100), 15),
((100, 100), 25)
]
target = (50, 50)
interpolated_values = [
SpatialUncertaintyModel.uncertain_interpolation(
target, samples, measurement_error=1
) for _ in range(10)
]
print(f" 目标点: {target}")
print(f" 插值结果 (10次): {[f'{v:.1f}' for v in interpolated_values]}")
print(f" 平均: {statistics.mean(interpolated_values):.2f} ± "
f"{statistics.stdev(interpolated_values):.2f}")
print("\n" + "="*70)
print("演示完成!")
print("="*70)
if __name__ == "__main__":
main()