aigroup-econ-mcp 1.3.3__py3-none-any.whl → 2.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. .gitignore +253 -0
  2. PKG-INFO +732 -0
  3. README.md +687 -0
  4. __init__.py +14 -0
  5. aigroup_econ_mcp-2.0.1.dist-info/METADATA +732 -0
  6. aigroup_econ_mcp-2.0.1.dist-info/RECORD +170 -0
  7. aigroup_econ_mcp-2.0.1.dist-info/entry_points.txt +2 -0
  8. aigroup_econ_mcp-2.0.1.dist-info/licenses/LICENSE +21 -0
  9. cli.py +32 -0
  10. econometrics/README.md +18 -0
  11. econometrics/__init__.py +191 -0
  12. econometrics/advanced_methods/modern_computing_machine_learning/__init__.py +30 -0
  13. econometrics/advanced_methods/modern_computing_machine_learning/causal_forest.py +253 -0
  14. econometrics/advanced_methods/modern_computing_machine_learning/double_ml.py +268 -0
  15. econometrics/advanced_methods/modern_computing_machine_learning/gradient_boosting.py +249 -0
  16. econometrics/advanced_methods/modern_computing_machine_learning/hierarchical_clustering.py +243 -0
  17. econometrics/advanced_methods/modern_computing_machine_learning/kmeans_clustering.py +293 -0
  18. econometrics/advanced_methods/modern_computing_machine_learning/neural_network.py +264 -0
  19. econometrics/advanced_methods/modern_computing_machine_learning/random_forest.py +195 -0
  20. econometrics/advanced_methods/modern_computing_machine_learning/support_vector_machine.py +226 -0
  21. econometrics/advanced_methods/modern_computing_machine_learning/test_all_modules.py +329 -0
  22. econometrics/advanced_methods/modern_computing_machine_learning/test_report.md +107 -0
  23. econometrics/basic_parametric_estimation/__init__.py +31 -0
  24. econometrics/basic_parametric_estimation/gmm/__init__.py +13 -0
  25. econometrics/basic_parametric_estimation/gmm/gmm_model.py +256 -0
  26. econometrics/basic_parametric_estimation/mle/__init__.py +13 -0
  27. econometrics/basic_parametric_estimation/mle/mle_model.py +241 -0
  28. econometrics/basic_parametric_estimation/ols/__init__.py +13 -0
  29. econometrics/basic_parametric_estimation/ols/ols_model.py +141 -0
  30. econometrics/causal_inference/__init__.py +66 -0
  31. econometrics/causal_inference/causal_identification_strategy/__init__.py +104 -0
  32. econometrics/causal_inference/causal_identification_strategy/control_function.py +112 -0
  33. econometrics/causal_inference/causal_identification_strategy/difference_in_differences.py +107 -0
  34. econometrics/causal_inference/causal_identification_strategy/event_study.py +119 -0
  35. econometrics/causal_inference/causal_identification_strategy/first_difference.py +89 -0
  36. econometrics/causal_inference/causal_identification_strategy/fixed_effects.py +103 -0
  37. econometrics/causal_inference/causal_identification_strategy/hausman_test.py +69 -0
  38. econometrics/causal_inference/causal_identification_strategy/instrumental_variables.py +145 -0
  39. econometrics/causal_inference/causal_identification_strategy/mediation_analysis.py +121 -0
  40. econometrics/causal_inference/causal_identification_strategy/moderation_analysis.py +109 -0
  41. econometrics/causal_inference/causal_identification_strategy/propensity_score_matching.py +140 -0
  42. econometrics/causal_inference/causal_identification_strategy/random_effects.py +100 -0
  43. econometrics/causal_inference/causal_identification_strategy/regression_discontinuity.py +98 -0
  44. econometrics/causal_inference/causal_identification_strategy/synthetic_control.py +111 -0
  45. econometrics/causal_inference/causal_identification_strategy/triple_difference.py +86 -0
  46. econometrics/distribution_analysis/__init__.py +28 -0
  47. econometrics/distribution_analysis/oaxaca_blinder.py +184 -0
  48. econometrics/distribution_analysis/time_series_decomposition.py +152 -0
  49. econometrics/distribution_analysis/variance_decomposition.py +179 -0
  50. econometrics/missing_data/__init__.py +18 -0
  51. econometrics/missing_data/imputation_methods.py +219 -0
  52. econometrics/missing_data/missing_data_measurement_error/__init__.py +0 -0
  53. econometrics/model_specification_diagnostics_robust_inference/README.md +173 -0
  54. econometrics/model_specification_diagnostics_robust_inference/__init__.py +78 -0
  55. econometrics/model_specification_diagnostics_robust_inference/diagnostic_tests/__init__.py +20 -0
  56. econometrics/model_specification_diagnostics_robust_inference/diagnostic_tests/diagnostic_tests_model.py +149 -0
  57. econometrics/model_specification_diagnostics_robust_inference/generalized_least_squares/__init__.py +15 -0
  58. econometrics/model_specification_diagnostics_robust_inference/generalized_least_squares/gls_model.py +130 -0
  59. econometrics/model_specification_diagnostics_robust_inference/model_selection/__init__.py +18 -0
  60. econometrics/model_specification_diagnostics_robust_inference/model_selection/model_selection_model.py +286 -0
  61. econometrics/model_specification_diagnostics_robust_inference/regularization/__init__.py +15 -0
  62. econometrics/model_specification_diagnostics_robust_inference/regularization/regularization_model.py +177 -0
  63. econometrics/model_specification_diagnostics_robust_inference/robust_errors/__init__.py +15 -0
  64. econometrics/model_specification_diagnostics_robust_inference/robust_errors/robust_errors_model.py +122 -0
  65. econometrics/model_specification_diagnostics_robust_inference/simultaneous_equations/__init__.py +15 -0
  66. econometrics/model_specification_diagnostics_robust_inference/simultaneous_equations/simultaneous_equations_model.py +246 -0
  67. econometrics/model_specification_diagnostics_robust_inference/weighted_least_squares/__init__.py +15 -0
  68. econometrics/model_specification_diagnostics_robust_inference/weighted_least_squares/wls_model.py +127 -0
  69. econometrics/nonparametric/__init__.py +35 -0
  70. econometrics/nonparametric/gam_model.py +117 -0
  71. econometrics/nonparametric/kernel_regression.py +161 -0
  72. econometrics/nonparametric/nonparametric_semiparametric_methods/__init__.py +0 -0
  73. econometrics/nonparametric/quantile_regression.py +249 -0
  74. econometrics/nonparametric/spline_regression.py +100 -0
  75. econometrics/spatial_econometrics/__init__.py +68 -0
  76. econometrics/spatial_econometrics/geographically_weighted_regression.py +211 -0
  77. econometrics/spatial_econometrics/gwr_simple.py +154 -0
  78. econometrics/spatial_econometrics/spatial_autocorrelation.py +356 -0
  79. econometrics/spatial_econometrics/spatial_durbin_model.py +177 -0
  80. econometrics/spatial_econometrics/spatial_econometrics_new/__init__.py +0 -0
  81. econometrics/spatial_econometrics/spatial_regression.py +315 -0
  82. econometrics/spatial_econometrics/spatial_weights.py +226 -0
  83. econometrics/specific_data_modeling/micro_discrete_limited_data/README.md +164 -0
  84. econometrics/specific_data_modeling/micro_discrete_limited_data/__init__.py +40 -0
  85. econometrics/specific_data_modeling/micro_discrete_limited_data/count_data_models.py +311 -0
  86. econometrics/specific_data_modeling/micro_discrete_limited_data/discrete_choice_models.py +294 -0
  87. econometrics/specific_data_modeling/micro_discrete_limited_data/limited_dependent_variable_models.py +282 -0
  88. econometrics/specific_data_modeling/survival_duration_data/__init__.py +0 -0
  89. econometrics/specific_data_modeling/time_series_panel_data/__init__.py +143 -0
  90. econometrics/specific_data_modeling/time_series_panel_data/arima_model.py +104 -0
  91. econometrics/specific_data_modeling/time_series_panel_data/cointegration_vecm.py +334 -0
  92. econometrics/specific_data_modeling/time_series_panel_data/dynamic_panel_models.py +653 -0
  93. econometrics/specific_data_modeling/time_series_panel_data/exponential_smoothing.py +176 -0
  94. econometrics/specific_data_modeling/time_series_panel_data/garch_model.py +198 -0
  95. econometrics/specific_data_modeling/time_series_panel_data/panel_diagnostics.py +125 -0
  96. econometrics/specific_data_modeling/time_series_panel_data/panel_var.py +60 -0
  97. econometrics/specific_data_modeling/time_series_panel_data/structural_break_tests.py +87 -0
  98. econometrics/specific_data_modeling/time_series_panel_data/time_varying_parameter_models.py +106 -0
  99. econometrics/specific_data_modeling/time_series_panel_data/unit_root_tests.py +204 -0
  100. econometrics/specific_data_modeling/time_series_panel_data/var_svar_model.py +372 -0
  101. econometrics/statistical_inference/__init__.py +21 -0
  102. econometrics/statistical_inference/bootstrap_methods.py +162 -0
  103. econometrics/statistical_inference/permutation_test.py +177 -0
  104. econometrics/statistical_inference/statistical_inference_techniques/__init__.py +0 -0
  105. econometrics/statistics/distribution_decomposition_methods/__init__.py +0 -0
  106. econometrics/survival_analysis/__init__.py +18 -0
  107. econometrics/survival_analysis/survival_models.py +259 -0
  108. econometrics/tests/basic_parametric_estimation_tests/__init__.py +3 -0
  109. econometrics/tests/basic_parametric_estimation_tests/test_gmm.py +128 -0
  110. econometrics/tests/basic_parametric_estimation_tests/test_mle.py +127 -0
  111. econometrics/tests/basic_parametric_estimation_tests/test_ols.py +100 -0
  112. econometrics/tests/causal_inference_tests/__init__.py +3 -0
  113. econometrics/tests/causal_inference_tests/detailed_test.py +441 -0
  114. econometrics/tests/causal_inference_tests/test_all_methods.py +418 -0
  115. econometrics/tests/causal_inference_tests/test_causal_identification_strategy.py +202 -0
  116. econometrics/tests/causal_inference_tests/test_difference_in_differences.py +53 -0
  117. econometrics/tests/causal_inference_tests/test_instrumental_variables.py +44 -0
  118. econometrics/tests/model_specification_diagnostics_tests/__init__.py +3 -0
  119. econometrics/tests/model_specification_diagnostics_tests/test_diagnostic_tests.py +86 -0
  120. econometrics/tests/model_specification_diagnostics_tests/test_robust_errors.py +89 -0
  121. econometrics/tests/specific_data_modeling_tests/__init__.py +3 -0
  122. econometrics/tests/specific_data_modeling_tests/test_arima.py +98 -0
  123. econometrics/tests/specific_data_modeling_tests/test_dynamic_panel.py +198 -0
  124. econometrics/tests/specific_data_modeling_tests/test_exponential_smoothing.py +105 -0
  125. econometrics/tests/specific_data_modeling_tests/test_garch.py +118 -0
  126. econometrics/tests/specific_data_modeling_tests/test_micro_discrete_limited_data.py +189 -0
  127. econometrics/tests/specific_data_modeling_tests/test_unit_root.py +156 -0
  128. econometrics/tests/specific_data_modeling_tests/test_var.py +124 -0
  129. econometrics//321/206/320/254/320/272/321/205/342/225/235/320/220/321/205/320/237/320/241/321/205/320/264/320/267/321/207/342/226/222/342/225/227/321/204/342/225/235/320/250/321/205/320/225/320/230/321/207/342/225/221/320/267/321/205/320/230/320/226/321/206/320/256/320/240.md +544 -0
  130. prompts/__init__.py +0 -0
  131. prompts/analysis_guides.py +43 -0
  132. pyproject.toml +85 -0
  133. resources/MCP_MASTER_GUIDE.md +422 -0
  134. resources/MCP_TOOLS_DATA_FORMAT_GUIDE.md +185 -0
  135. resources/__init__.py +0 -0
  136. server.py +97 -0
  137. tools/README.md +88 -0
  138. tools/__init__.py +119 -0
  139. tools/causal_inference_adapter.py +658 -0
  140. tools/data_loader.py +213 -0
  141. tools/decorators.py +38 -0
  142. tools/distribution_analysis_adapter.py +121 -0
  143. tools/econometrics_adapter.py +286 -0
  144. tools/gwr_simple_adapter.py +54 -0
  145. tools/machine_learning_adapter.py +567 -0
  146. tools/mcp_tool_groups/__init__.py +15 -0
  147. tools/mcp_tool_groups/basic_parametric_tools.py +173 -0
  148. tools/mcp_tool_groups/causal_inference_tools.py +643 -0
  149. tools/mcp_tool_groups/distribution_analysis_tools.py +169 -0
  150. tools/mcp_tool_groups/machine_learning_tools.py +422 -0
  151. tools/mcp_tool_groups/microecon_tools.py +325 -0
  152. tools/mcp_tool_groups/missing_data_tools.py +117 -0
  153. tools/mcp_tool_groups/model_specification_tools.py +402 -0
  154. tools/mcp_tool_groups/nonparametric_tools.py +225 -0
  155. tools/mcp_tool_groups/spatial_econometrics_tools.py +323 -0
  156. tools/mcp_tool_groups/statistical_inference_tools.py +131 -0
  157. tools/mcp_tool_groups/time_series_tools.py +494 -0
  158. tools/mcp_tools_registry.py +124 -0
  159. tools/microecon_adapter.py +412 -0
  160. tools/missing_data_adapter.py +73 -0
  161. tools/model_specification_adapter.py +369 -0
  162. tools/nonparametric_adapter.py +190 -0
  163. tools/output_formatter.py +563 -0
  164. tools/spatial_econometrics_adapter.py +318 -0
  165. tools/statistical_inference_adapter.py +90 -0
  166. tools/survival_analysis_adapter.py +46 -0
  167. tools/time_series_panel_data_adapter.py +858 -0
  168. tools/time_series_panel_data_tools.py +65 -0
  169. aigroup_econ_mcp/__init__.py +0 -19
  170. aigroup_econ_mcp/cli.py +0 -82
  171. aigroup_econ_mcp/config.py +0 -561
  172. aigroup_econ_mcp/server.py +0 -452
  173. aigroup_econ_mcp/tools/__init__.py +0 -19
  174. aigroup_econ_mcp/tools/base.py +0 -470
  175. aigroup_econ_mcp/tools/cache.py +0 -533
  176. aigroup_econ_mcp/tools/data_loader.py +0 -195
  177. aigroup_econ_mcp/tools/file_parser.py +0 -1027
  178. aigroup_econ_mcp/tools/machine_learning.py +0 -60
  179. aigroup_econ_mcp/tools/ml_ensemble.py +0 -210
  180. aigroup_econ_mcp/tools/ml_evaluation.py +0 -272
  181. aigroup_econ_mcp/tools/ml_models.py +0 -54
  182. aigroup_econ_mcp/tools/ml_regularization.py +0 -186
  183. aigroup_econ_mcp/tools/monitoring.py +0 -555
  184. aigroup_econ_mcp/tools/optimized_example.py +0 -229
  185. aigroup_econ_mcp/tools/panel_data.py +0 -619
  186. aigroup_econ_mcp/tools/regression.py +0 -214
  187. aigroup_econ_mcp/tools/statistics.py +0 -154
  188. aigroup_econ_mcp/tools/time_series.py +0 -698
  189. aigroup_econ_mcp/tools/timeout.py +0 -283
  190. aigroup_econ_mcp/tools/tool_descriptions.py +0 -410
  191. aigroup_econ_mcp/tools/tool_handlers.py +0 -1016
  192. aigroup_econ_mcp/tools/tool_registry.py +0 -478
  193. aigroup_econ_mcp/tools/validation.py +0 -482
  194. aigroup_econ_mcp-1.3.3.dist-info/METADATA +0 -525
  195. aigroup_econ_mcp-1.3.3.dist-info/RECORD +0 -30
  196. aigroup_econ_mcp-1.3.3.dist-info/entry_points.txt +0 -2
  197. /aigroup_econ_mcp-1.3.3.dist-info/licenses/LICENSE → /LICENSE +0 -0
  198. {aigroup_econ_mcp-1.3.3.dist-info → aigroup_econ_mcp-2.0.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,356 @@
1
+ """
2
+ 空间自相关检验
3
+ 基于 esda (Exploratory Spatial Data Analysis) 库实现
4
+ """
5
+
6
+ from typing import List, Optional, Tuple
7
+ from pydantic import BaseModel, Field
8
+ import numpy as np
9
+
10
+ try:
11
+ from esda import Moran, Moran_Local, Geary
12
+ from libpysal.weights import W
13
+ ESDA_AVAILABLE = True
14
+ except ImportError:
15
+ ESDA_AVAILABLE = False
16
+ Moran = None
17
+ Moran_Local = None
18
+ Geary = None
19
+ W = None
20
+
21
+
22
+ class MoranIResult(BaseModel):
23
+ """Moran's I 空间自相关检验结果"""
24
+ moran_i: float = Field(..., description="Moran's I 统计量")
25
+ expected_i: float = Field(..., description="期望值")
26
+ variance_i: float = Field(..., description="方差")
27
+ z_score: float = Field(..., description="Z统计量")
28
+ p_value: float = Field(..., description="P值(双侧检验)")
29
+ p_value_one_sided: float = Field(..., description="P值(单侧检验)")
30
+ interpretation: str = Field(..., description="结果解释")
31
+ n_observations: int = Field(..., description="观测数量")
32
+ summary: str = Field(..., description="摘要信息")
33
+
34
+
35
+ class GearysCResult(BaseModel):
36
+ """Geary's C 空间自相关检验结果"""
37
+ geary_c: float = Field(..., description="Geary's C 统计量")
38
+ expected_c: float = Field(..., description="期望值")
39
+ variance_c: float = Field(..., description="方差")
40
+ z_score: float = Field(..., description="Z统计量")
41
+ p_value: float = Field(..., description="P值")
42
+ interpretation: str = Field(..., description="结果解释")
43
+ n_observations: int = Field(..., description="观测数量")
44
+ summary: str = Field(..., description="摘要信息")
45
+
46
+
47
+ class LocalMoranResult(BaseModel):
48
+ """局部Moran's I (LISA) 结果"""
49
+ local_i: List[float] = Field(..., description="局部Moran's I值")
50
+ z_scores: List[float] = Field(..., description="Z统计量")
51
+ p_values: List[float] = Field(..., description="P值")
52
+ quadrants: List[str] = Field(..., description="象限分类 (HH, LL, HL, LH)")
53
+ significant_locations: List[int] = Field(..., description="显著位置索引")
54
+ n_significant: int = Field(..., description="显著位置数量")
55
+ summary: str = Field(..., description="摘要信息")
56
+
57
+
58
+ def morans_i_test(
59
+ values: List[float],
60
+ neighbors: dict,
61
+ weights: Optional[dict] = None,
62
+ permutations: int = 999,
63
+ two_tailed: bool = True
64
+ ) -> MoranIResult:
65
+ """
66
+ Moran's I 全局空间自相关检验
67
+
68
+ Args:
69
+ values: 观测值列表
70
+ neighbors: 邻居字典 {i: [j1, j2, ...]}
71
+ weights: 权重字典 {i: [w1, w2, ...]},如果为None则使用均等权重
72
+ permutations: 置换检验次数
73
+ two_tailed: 是否双侧检验
74
+
75
+ Returns:
76
+ MoranIResult: Moran's I检验结果
77
+
78
+ Raises:
79
+ ImportError: esda库未安装
80
+ ValueError: 输入数据无效
81
+ """
82
+ if not ESDA_AVAILABLE:
83
+ raise ImportError(
84
+ "esda库未安装。请运行: pip install esda\n"
85
+ "或: pip install pysal"
86
+ )
87
+
88
+ # 输入验证
89
+ if not values:
90
+ raise ValueError("values不能为空")
91
+ if not neighbors:
92
+ raise ValueError("neighbors不能为空")
93
+
94
+ n = len(values)
95
+ y = np.array(values, dtype=np.float64)
96
+
97
+ # 构建权重对象
98
+ if weights is None:
99
+ # 使用均等权重
100
+ weights = {i: [1.0] * len(neighbors[i]) for i in neighbors}
101
+
102
+ # 确保邻居字典的键是整数
103
+ neighbors_int = {int(k): [int(n) for n in v] for k, v in neighbors.items()}
104
+ weights_int = {int(k): v for k, v in weights.items()}
105
+
106
+ w = W(neighbors_int, weights_int)
107
+
108
+ # 执行Moran's I检验
109
+ try:
110
+ mi = Moran(y, w, permutations=permutations)
111
+
112
+ # 提取结果
113
+ moran_i = float(mi.I)
114
+ expected_i = float(mi.EI)
115
+ variance_i = float(mi.VI_norm)
116
+ z_score = float(mi.z_norm)
117
+
118
+ # P值
119
+ if two_tailed:
120
+ p_value = float(mi.p_norm)
121
+ p_value_one_sided = float(mi.p_norm) / 2
122
+ else:
123
+ p_value_one_sided = float(mi.p_norm)
124
+ p_value = float(mi.p_norm) * 2
125
+
126
+ # 解释结果
127
+ interpretation = _interpret_moran_i(moran_i, p_value, z_score)
128
+
129
+ # 生成摘要
130
+ summary = f"""Moran's I 空间自相关检验:
131
+ - Moran's I: {moran_i:.4f}
132
+ - 期望值: {expected_i:.4f}
133
+ - Z统计量: {z_score:.4f}
134
+ - P值: {p_value:.4f}
135
+ - 置换次数: {permutations}
136
+ - 结论: {interpretation}
137
+ """
138
+
139
+ return MoranIResult(
140
+ moran_i=moran_i,
141
+ expected_i=expected_i,
142
+ variance_i=variance_i,
143
+ z_score=z_score,
144
+ p_value=p_value,
145
+ p_value_one_sided=p_value_one_sided,
146
+ interpretation=interpretation,
147
+ n_observations=n,
148
+ summary=summary
149
+ )
150
+ except Exception as e:
151
+ raise ValueError(f"Moran's I检验失败: {str(e)}")
152
+
153
+
154
+ def gearys_c_test(
155
+ values: List[float],
156
+ neighbors: dict,
157
+ weights: Optional[dict] = None,
158
+ permutations: int = 999
159
+ ) -> GearysCResult:
160
+ """
161
+ Geary's C 空间自相关检验
162
+
163
+ Args:
164
+ values: 观测值列表
165
+ neighbors: 邻居字典
166
+ weights: 权重字典
167
+ permutations: 置换检验次数
168
+
169
+ Returns:
170
+ GearysCResult: Geary's C检验结果
171
+ """
172
+ if not ESDA_AVAILABLE:
173
+ raise ImportError("esda库未安装")
174
+
175
+ if not values or not neighbors:
176
+ raise ValueError("输入数据不能为空")
177
+
178
+ n = len(values)
179
+ y = np.array(values, dtype=np.float64)
180
+
181
+ # 构建权重对象
182
+ if weights is None:
183
+ weights = {i: [1.0] * len(neighbors[i]) for i in neighbors}
184
+
185
+ # 确保邻居字典的键是整数
186
+ neighbors_int = {int(k): [int(n) for n in v] for k, v in neighbors.items()}
187
+ weights_int = {int(k): v for k, v in weights.items()}
188
+
189
+ w = W(neighbors_int, weights_int)
190
+
191
+ # 执行Geary's C检验
192
+ try:
193
+ gc = Geary(y, w, permutations=permutations)
194
+
195
+ # 提取结果
196
+ geary_c = float(gc.C)
197
+ expected_c = float(gc.EC)
198
+ variance_c = float(gc.VC_norm)
199
+ z_score = float(gc.z_norm)
200
+ p_value = float(gc.p_norm)
201
+
202
+ # 解释结果
203
+ interpretation = _interpret_geary_c(geary_c, p_value, z_score)
204
+
205
+ # 生成摘要
206
+ summary = f"""Geary's C 空间自相关检验:
207
+ - Geary's C: {geary_c:.4f}
208
+ - 期望值: {expected_c:.4f}
209
+ - Z统计量: {z_score:.4f}
210
+ - P值: {p_value:.4f}
211
+ - 结论: {interpretation}
212
+ """
213
+
214
+ return GearysCResult(
215
+ geary_c=geary_c,
216
+ expected_c=expected_c,
217
+ variance_c=variance_c,
218
+ z_score=z_score,
219
+ p_value=p_value,
220
+ interpretation=interpretation,
221
+ n_observations=n,
222
+ summary=summary
223
+ )
224
+ except Exception as e:
225
+ raise ValueError(f"Geary's C检验失败: {str(e)}")
226
+
227
+
228
+ def local_morans_i(
229
+ values: List[float],
230
+ neighbors: dict,
231
+ weights: Optional[dict] = None,
232
+ permutations: int = 999,
233
+ significance_level: float = 0.05
234
+ ) -> LocalMoranResult:
235
+ """
236
+ 局部Moran's I (LISA - Local Indicators of Spatial Association)
237
+
238
+ Args:
239
+ values: 观测值列表
240
+ neighbors: 邻居字典
241
+ weights: 权重字典
242
+ permutations: 置换检验次数
243
+ significance_level: 显著性水平
244
+
245
+ Returns:
246
+ LocalMoranResult: 局部Moran's I结果
247
+ """
248
+ if not ESDA_AVAILABLE:
249
+ raise ImportError("esda库未安装")
250
+
251
+ if not values or not neighbors:
252
+ raise ValueError("输入数据不能为空")
253
+
254
+ y = np.array(values, dtype=np.float64)
255
+
256
+ # 构建权重对象
257
+ if weights is None:
258
+ weights = {i: [1.0] * len(neighbors[i]) for i in neighbors}
259
+
260
+ # 确保邻居字典的键是整数
261
+ neighbors_int = {int(k): [int(n) for n in v] for k, v in neighbors.items()}
262
+ weights_int = {int(k): v for k, v in weights.items()}
263
+
264
+ w = W(neighbors_int, weights_int)
265
+
266
+ # 执行局部Moran's I分析
267
+ lm = Moran_Local(y, w, permutations=permutations)
268
+
269
+ # 提取结果
270
+ local_i = lm.Is.tolist()
271
+ z_scores = lm.z_sim.tolist()
272
+ p_values = lm.p_sim.tolist()
273
+
274
+ # 象限分类
275
+ quadrants = []
276
+ for q in lm.q:
277
+ if q == 1:
278
+ quadrants.append("HH") # High-High
279
+ elif q == 2:
280
+ quadrants.append("LH") # Low-High
281
+ elif q == 3:
282
+ quadrants.append("LL") # Low-Low
283
+ elif q == 4:
284
+ quadrants.append("HL") # High-Low
285
+ else:
286
+ quadrants.append("NS") # Not Significant
287
+
288
+ # 识别显著位置
289
+ significant_locations = [
290
+ i for i, p in enumerate(p_values)
291
+ if p < significance_level
292
+ ]
293
+ n_significant = len(significant_locations)
294
+
295
+ # 生成摘要
296
+ summary = f"""局部Moran's I (LISA) 分析:
297
+ - 观测数量: {len(values)}
298
+ - 显著位置数: {n_significant} ({n_significant/len(values)*100:.1f}%)
299
+ - 显著性水平: {significance_level}
300
+ - HH聚类: {quadrants.count('HH')} 个
301
+ - LL聚类: {quadrants.count('LL')} 个
302
+ - HL离群: {quadrants.count('HL')} 个
303
+ - LH离群: {quadrants.count('LH')} 个
304
+ """
305
+
306
+ return LocalMoranResult(
307
+ local_i=local_i,
308
+ z_scores=z_scores,
309
+ p_values=p_values,
310
+ quadrants=quadrants,
311
+ significant_locations=significant_locations,
312
+ n_significant=n_significant,
313
+ summary=summary
314
+ )
315
+
316
+
317
+ def _interpret_moran_i(moran_i: float, p_value: float, z_score: float) -> str:
318
+ """解释Moran's I结果"""
319
+ if p_value < 0.01:
320
+ sig_level = "高度显著"
321
+ elif p_value < 0.05:
322
+ sig_level = "显著"
323
+ elif p_value < 0.10:
324
+ sig_level = "边际显著"
325
+ else:
326
+ sig_level = "不显著"
327
+
328
+ if moran_i > 0:
329
+ pattern = "正空间自相关(空间聚集)"
330
+ elif moran_i < 0:
331
+ pattern = "负空间自相关(空间离散)"
332
+ else:
333
+ pattern = "无空间自相关(随机分布)"
334
+
335
+ return f"{sig_level}的{pattern}"
336
+
337
+
338
+ def _interpret_geary_c(geary_c: float, p_value: float, z_score: float) -> str:
339
+ """解释Geary's C结果"""
340
+ if p_value < 0.01:
341
+ sig_level = "高度显著"
342
+ elif p_value < 0.05:
343
+ sig_level = "显著"
344
+ elif p_value < 0.10:
345
+ sig_level = "边际显著"
346
+ else:
347
+ sig_level = "不显著"
348
+
349
+ if geary_c < 1:
350
+ pattern = "正空间自相关"
351
+ elif geary_c > 1:
352
+ pattern = "负空间自相关"
353
+ else:
354
+ pattern = "无空间自相关"
355
+
356
+ return f"{sig_level}的{pattern}"
@@ -0,0 +1,177 @@
1
+ """
2
+ 空间杜宾模型 (Spatial Durbin Model - SDM)
3
+ 基于 spreg 库实现
4
+ """
5
+
6
+ from typing import List, Optional, Dict
7
+ from pydantic import BaseModel, Field
8
+ import numpy as np
9
+
10
+ try:
11
+ from spreg import OLS_Regimes, ML_Lag
12
+ from libpysal.weights import W
13
+ SPREG_AVAILABLE = True
14
+ except ImportError:
15
+ SPREG_AVAILABLE = False
16
+ W = None
17
+
18
+
19
+ class SpatialDurbinResult(BaseModel):
20
+ """空间杜宾模型结果"""
21
+ coefficients: List[float] = Field(..., description="回归系数")
22
+ std_errors: List[float] = Field(..., description="标准误")
23
+ z_scores: List[float] = Field(..., description="Z统计量")
24
+ p_values: List[float] = Field(..., description="P值")
25
+ feature_names: List[str] = Field(..., description="特征名称(包括WX)")
26
+ spatial_lag_coef: float = Field(..., description="空间滞后系数ρ")
27
+ spatial_lag_se: float = Field(..., description="空间滞后系数标准误")
28
+ log_likelihood: float = Field(..., description="对数似然值")
29
+ aic: float = Field(..., description="AIC信息准则")
30
+ schwarz: float = Field(..., description="BIC信息准则")
31
+ n_observations: int = Field(..., description="观测数量")
32
+ summary: str = Field(..., description="摘要信息")
33
+
34
+
35
+ def spatial_durbin_model(
36
+ y_data: List[float],
37
+ x_data: List[List[float]],
38
+ neighbors: dict,
39
+ weights: Optional[dict] = None,
40
+ feature_names: Optional[List[str]] = None
41
+ ) -> SpatialDurbinResult:
42
+ """
43
+ 空间杜宾模型 (SDM)
44
+ 模型形式: y = ρWy + Xβ + WXθ + ε
45
+
46
+ Args:
47
+ y_data: 因变量
48
+ x_data: 自变量(二维列表)
49
+ neighbors: 邻居字典
50
+ weights: 权重字典
51
+ feature_names: 特征名称
52
+
53
+ Returns:
54
+ SpatialDurbinResult: 空间杜宾模型结果
55
+
56
+ Raises:
57
+ ImportError: spreg库未安装
58
+ ValueError: 输入数据无效
59
+ """
60
+ if not SPREG_AVAILABLE:
61
+ raise ImportError(
62
+ "spreg库未安装。请运行: pip install spreg\n"
63
+ "或: pip install pysal"
64
+ )
65
+
66
+ # 输入验证
67
+ if not y_data or not x_data:
68
+ raise ValueError("y_data和x_data不能为空")
69
+
70
+ # 数据准备
71
+ y = np.array(y_data).reshape(-1, 1)
72
+ X = np.array(x_data)
73
+
74
+ if X.ndim == 1:
75
+ X = X.reshape(-1, 1)
76
+
77
+ n = len(y)
78
+ k = X.shape[1]
79
+
80
+ # 构建权重对象
81
+ if weights is None:
82
+ weights = {i: [1.0] * len(neighbors[i]) for i in neighbors}
83
+
84
+ # 确保邻居字典的键是整数
85
+ neighbors_int = {int(k): [int(n) for n in v] for k, v in neighbors.items()}
86
+ weights_int = {int(k): v for k, v in weights.items()}
87
+
88
+ w = W(neighbors_int, weights_int)
89
+ w.transform = 'r'
90
+
91
+ # 特征名称
92
+ if feature_names is None:
93
+ feature_names = [f"X{i+1}" for i in range(k)]
94
+
95
+ # 计算WX(空间滞后的自变量)
96
+ try:
97
+ from scipy import sparse
98
+ W_matrix = w.sparse
99
+ WX = W_matrix.dot(X)
100
+ except ImportError:
101
+ # 如果scipy不可用,使用numpy实现
102
+ W_matrix = np.zeros((n, n))
103
+ for i in w.neighbors:
104
+ for j_idx, j in enumerate(w.neighbors[i]):
105
+ W_matrix[i, j] = w.weights[i][j_idx]
106
+ WX = W_matrix.dot(X)
107
+
108
+ # 合并X和WX
109
+ X_full = np.hstack([X, WX])
110
+
111
+ # 特征名称(包括WX)
112
+ wx_names = [f"W_{name}" for name in feature_names]
113
+ all_feature_names = feature_names + wx_names
114
+
115
+ # 使用ML_Lag但包含WX作为额外的解释变量
116
+ # 这实际上是SDM的一种实现方式
117
+ try:
118
+ # 创建包含WX的模型
119
+ model = ML_Lag(y, X_full, w, name_y='y', name_x=all_feature_names)
120
+ except Exception as e:
121
+ raise ValueError(f"空间杜宾模型估计失败: {str(e)}")
122
+
123
+ # 提取结果
124
+ coefficients = model.betas.flatten().tolist()
125
+ std_errors = np.sqrt(np.diag(model.vm)).tolist()
126
+
127
+ # 处理z_stat - 可能是列表或numpy数组
128
+ if hasattr(model.z_stat, 'shape'):
129
+ # numpy数组
130
+ z_scores = model.z_stat[:, 0].tolist()
131
+ p_values = model.z_stat[:, 1].tolist()
132
+ else:
133
+ # 列表
134
+ z_scores = [stat[0] for stat in model.z_stat] if model.z_stat else []
135
+ p_values = [stat[1] for stat in model.z_stat] if model.z_stat else []
136
+
137
+ # 空间滞后系数
138
+ spatial_lag_coef = float(model.rho)
139
+ try:
140
+ spatial_lag_se = float(np.sqrt(model.vm[-1, -1]))
141
+ except:
142
+ spatial_lag_se = 0.0
143
+
144
+ # 模型拟合指标
145
+ log_likelihood = float(model.logll) if hasattr(model, 'logll') else 0.0
146
+ aic = float(model.aic) if hasattr(model, 'aic') else 0.0
147
+ schwarz = float(model.schwarz) if hasattr(model, 'schwarz') else 0.0
148
+
149
+ # 添加常数项到特征名称
150
+ final_feature_names = ['const'] + all_feature_names
151
+
152
+ # 生成摘要
153
+ summary = f"""空间杜宾模型 (SDM):
154
+ - 观测数量: {n}
155
+ - 自变量数: {k}
156
+ - 空间滞后系数 ρ: {spatial_lag_coef:.4f} (SE: {spatial_lag_se:.4f})
157
+ - 对数似然: {log_likelihood:.2f}
158
+ - AIC: {aic:.2f}
159
+ - BIC: {schwarz:.2f}
160
+
161
+ 说明: SDM同时包含Wy和WX,捕捉自变量的空间溢出效应
162
+ """
163
+
164
+ return SpatialDurbinResult(
165
+ coefficients=coefficients,
166
+ std_errors=std_errors,
167
+ z_scores=z_scores,
168
+ p_values=p_values,
169
+ feature_names=final_feature_names,
170
+ spatial_lag_coef=spatial_lag_coef,
171
+ spatial_lag_se=spatial_lag_se,
172
+ log_likelihood=log_likelihood,
173
+ aic=aic,
174
+ schwarz=schwarz,
175
+ n_observations=n,
176
+ summary=summary
177
+ )