aigroup-econ-mcp 1.4.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 (97) hide show
  1. PKG-INFO +344 -322
  2. README.md +335 -320
  3. __init__.py +1 -1
  4. aigroup_econ_mcp-2.0.1.dist-info/METADATA +732 -0
  5. aigroup_econ_mcp-2.0.1.dist-info/RECORD +170 -0
  6. cli.py +4 -0
  7. econometrics/advanced_methods/modern_computing_machine_learning/__init__.py +30 -0
  8. econometrics/advanced_methods/modern_computing_machine_learning/causal_forest.py +253 -0
  9. econometrics/advanced_methods/modern_computing_machine_learning/double_ml.py +268 -0
  10. econometrics/advanced_methods/modern_computing_machine_learning/gradient_boosting.py +249 -0
  11. econometrics/advanced_methods/modern_computing_machine_learning/hierarchical_clustering.py +243 -0
  12. econometrics/advanced_methods/modern_computing_machine_learning/kmeans_clustering.py +293 -0
  13. econometrics/advanced_methods/modern_computing_machine_learning/neural_network.py +264 -0
  14. econometrics/advanced_methods/modern_computing_machine_learning/random_forest.py +195 -0
  15. econometrics/advanced_methods/modern_computing_machine_learning/support_vector_machine.py +226 -0
  16. econometrics/advanced_methods/modern_computing_machine_learning/test_all_modules.py +329 -0
  17. econometrics/advanced_methods/modern_computing_machine_learning/test_report.md +107 -0
  18. econometrics/causal_inference/__init__.py +66 -0
  19. econometrics/causal_inference/causal_identification_strategy/__init__.py +104 -0
  20. econometrics/causal_inference/causal_identification_strategy/control_function.py +112 -0
  21. econometrics/causal_inference/causal_identification_strategy/difference_in_differences.py +107 -0
  22. econometrics/causal_inference/causal_identification_strategy/event_study.py +119 -0
  23. econometrics/causal_inference/causal_identification_strategy/first_difference.py +89 -0
  24. econometrics/causal_inference/causal_identification_strategy/fixed_effects.py +103 -0
  25. econometrics/causal_inference/causal_identification_strategy/hausman_test.py +69 -0
  26. econometrics/causal_inference/causal_identification_strategy/instrumental_variables.py +145 -0
  27. econometrics/causal_inference/causal_identification_strategy/mediation_analysis.py +121 -0
  28. econometrics/causal_inference/causal_identification_strategy/moderation_analysis.py +109 -0
  29. econometrics/causal_inference/causal_identification_strategy/propensity_score_matching.py +140 -0
  30. econometrics/causal_inference/causal_identification_strategy/random_effects.py +100 -0
  31. econometrics/causal_inference/causal_identification_strategy/regression_discontinuity.py +98 -0
  32. econometrics/causal_inference/causal_identification_strategy/synthetic_control.py +111 -0
  33. econometrics/causal_inference/causal_identification_strategy/triple_difference.py +86 -0
  34. econometrics/distribution_analysis/__init__.py +28 -0
  35. econometrics/distribution_analysis/oaxaca_blinder.py +184 -0
  36. econometrics/distribution_analysis/time_series_decomposition.py +152 -0
  37. econometrics/distribution_analysis/variance_decomposition.py +179 -0
  38. econometrics/missing_data/__init__.py +18 -0
  39. econometrics/missing_data/imputation_methods.py +219 -0
  40. econometrics/nonparametric/__init__.py +35 -0
  41. econometrics/nonparametric/gam_model.py +117 -0
  42. econometrics/nonparametric/kernel_regression.py +161 -0
  43. econometrics/nonparametric/quantile_regression.py +249 -0
  44. econometrics/nonparametric/spline_regression.py +100 -0
  45. econometrics/spatial_econometrics/__init__.py +68 -0
  46. econometrics/spatial_econometrics/geographically_weighted_regression.py +211 -0
  47. econometrics/spatial_econometrics/gwr_simple.py +154 -0
  48. econometrics/spatial_econometrics/spatial_autocorrelation.py +356 -0
  49. econometrics/spatial_econometrics/spatial_durbin_model.py +177 -0
  50. econometrics/spatial_econometrics/spatial_regression.py +315 -0
  51. econometrics/spatial_econometrics/spatial_weights.py +226 -0
  52. econometrics/specific_data_modeling/micro_discrete_limited_data/README.md +164 -0
  53. econometrics/specific_data_modeling/micro_discrete_limited_data/__init__.py +40 -0
  54. econometrics/specific_data_modeling/micro_discrete_limited_data/count_data_models.py +311 -0
  55. econometrics/specific_data_modeling/micro_discrete_limited_data/discrete_choice_models.py +294 -0
  56. econometrics/specific_data_modeling/micro_discrete_limited_data/limited_dependent_variable_models.py +282 -0
  57. econometrics/statistical_inference/__init__.py +21 -0
  58. econometrics/statistical_inference/bootstrap_methods.py +162 -0
  59. econometrics/statistical_inference/permutation_test.py +177 -0
  60. econometrics/survival_analysis/__init__.py +18 -0
  61. econometrics/survival_analysis/survival_models.py +259 -0
  62. econometrics/tests/causal_inference_tests/__init__.py +3 -0
  63. econometrics/tests/causal_inference_tests/detailed_test.py +441 -0
  64. econometrics/tests/causal_inference_tests/test_all_methods.py +418 -0
  65. econometrics/tests/causal_inference_tests/test_causal_identification_strategy.py +202 -0
  66. econometrics/tests/causal_inference_tests/test_difference_in_differences.py +53 -0
  67. econometrics/tests/causal_inference_tests/test_instrumental_variables.py +44 -0
  68. econometrics/tests/specific_data_modeling_tests/test_micro_discrete_limited_data.py +189 -0
  69. 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
  70. pyproject.toml +9 -2
  71. server.py +15 -1
  72. tools/__init__.py +75 -1
  73. tools/causal_inference_adapter.py +658 -0
  74. tools/distribution_analysis_adapter.py +121 -0
  75. tools/gwr_simple_adapter.py +54 -0
  76. tools/machine_learning_adapter.py +567 -0
  77. tools/mcp_tool_groups/__init__.py +15 -1
  78. tools/mcp_tool_groups/causal_inference_tools.py +643 -0
  79. tools/mcp_tool_groups/distribution_analysis_tools.py +169 -0
  80. tools/mcp_tool_groups/machine_learning_tools.py +422 -0
  81. tools/mcp_tool_groups/microecon_tools.py +325 -0
  82. tools/mcp_tool_groups/missing_data_tools.py +117 -0
  83. tools/mcp_tool_groups/nonparametric_tools.py +225 -0
  84. tools/mcp_tool_groups/spatial_econometrics_tools.py +323 -0
  85. tools/mcp_tool_groups/statistical_inference_tools.py +131 -0
  86. tools/mcp_tools_registry.py +13 -3
  87. tools/microecon_adapter.py +412 -0
  88. tools/missing_data_adapter.py +73 -0
  89. tools/nonparametric_adapter.py +190 -0
  90. tools/spatial_econometrics_adapter.py +318 -0
  91. tools/statistical_inference_adapter.py +90 -0
  92. tools/survival_analysis_adapter.py +46 -0
  93. aigroup_econ_mcp-1.4.3.dist-info/METADATA +0 -710
  94. aigroup_econ_mcp-1.4.3.dist-info/RECORD +0 -92
  95. {aigroup_econ_mcp-1.4.3.dist-info → aigroup_econ_mcp-2.0.1.dist-info}/WHEEL +0 -0
  96. {aigroup_econ_mcp-1.4.3.dist-info → aigroup_econ_mcp-2.0.1.dist-info}/entry_points.txt +0 -0
  97. {aigroup_econ_mcp-1.4.3.dist-info → aigroup_econ_mcp-2.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,412 @@
1
+ """
2
+ Microeconometrics Adapter for Econometrics MCP Tools
3
+ Provides unified interfaces for discrete choice, count data, and limited dependent variable models
4
+ """
5
+
6
+ import numpy as np
7
+ import pandas as pd
8
+ from typing import Union, Optional, Dict, Any, List
9
+ import json
10
+ import logging
11
+
12
+ # Import microeconometrics modules
13
+ from econometrics.specific_data_modeling.micro_discrete_limited_data import (
14
+ LogitModel,
15
+ ProbitModel,
16
+ MultinomialLogit,
17
+ OrderedLogit,
18
+ ConditionalLogit,
19
+ PoissonModel,
20
+ NegativeBinomialModel,
21
+ ZeroInflatedPoissonModel,
22
+ ZeroInflatedNegativeBinomialModel,
23
+ TobitModel,
24
+ HeckmanModel
25
+ )
26
+
27
+ from tools.data_loader import DataLoader
28
+
29
+ # Set up logging
30
+ logger = logging.getLogger(__name__)
31
+
32
+
33
+ def logit_adapter(
34
+ X_data: Optional[Union[List[float], List[List[float]]]] = None,
35
+ y_data: Optional[List[int]] = None,
36
+ file_path: Optional[str] = None,
37
+ feature_names: Optional[List[str]] = None,
38
+ output_format: str = 'json',
39
+ save_path: Optional[str] = None
40
+ ) -> str:
41
+ """Logistic regression adapter"""
42
+ try:
43
+ if file_path:
44
+ data = DataLoader.load_from_file(file_path)
45
+ X_data = data.get('x_data', data.get('X', data.get('features')))
46
+ y_data = data.get('y_data', data.get('y', data.get('target')))
47
+ if feature_names is None:
48
+ feature_names = data.get('feature_names')
49
+
50
+ if X_data is None or y_data is None:
51
+ raise ValueError("X_data and y_data must be provided")
52
+
53
+ X = np.array(X_data)
54
+ y = np.array(y_data)
55
+
56
+ if X.ndim == 1:
57
+ X = X.reshape(-1, 1)
58
+
59
+ model = LogitModel()
60
+ model.fit(X, y)
61
+
62
+ results = model.results_
63
+ formatted_results = {
64
+ 'model_type': 'logit',
65
+ 'coefficients': results.params.tolist(),
66
+ 'std_errors': results.bse.tolist(),
67
+ 'z_values': results.tvalues.tolist(),
68
+ 'p_values': results.pvalues.tolist(),
69
+ 'pseudo_r_squared': float(results.prsquared),
70
+ 'log_likelihood': float(results.llf),
71
+ 'aic': float(results.aic),
72
+ 'bic': float(results.bic),
73
+ 'n_obs': int(results.nobs),
74
+ 'feature_names': feature_names or [f'X{i+1}' for i in range(X.shape[1])]
75
+ }
76
+
77
+ return json.dumps(formatted_results, indent=2, ensure_ascii=False)
78
+
79
+ except Exception as e:
80
+ logger.error(f"Logit failed: {str(e)}")
81
+ return json.dumps({'error': str(e)}, indent=2, ensure_ascii=False)
82
+
83
+
84
+ def probit_adapter(
85
+ X_data: Optional[Union[List[float], List[List[float]]]] = None,
86
+ y_data: Optional[List[int]] = None,
87
+ file_path: Optional[str] = None,
88
+ feature_names: Optional[List[str]] = None,
89
+ output_format: str = 'json',
90
+ save_path: Optional[str] = None
91
+ ) -> str:
92
+ """Probit regression adapter"""
93
+ try:
94
+ if file_path:
95
+ data = DataLoader.load_from_file(file_path)
96
+ X_data = data.get('x_data', data.get('X', data.get('features')))
97
+ y_data = data.get('y_data', data.get('y', data.get('target')))
98
+ if feature_names is None:
99
+ feature_names = data.get('feature_names')
100
+
101
+ if X_data is None or y_data is None:
102
+ raise ValueError("X_data and y_data must be provided")
103
+
104
+ X = np.array(X_data)
105
+ y = np.array(y_data)
106
+
107
+ if X.ndim == 1:
108
+ X = X.reshape(-1, 1)
109
+
110
+ model = ProbitModel()
111
+ model.fit(X, y)
112
+
113
+ results = model.results_
114
+ formatted_results = {
115
+ 'model_type': 'probit',
116
+ 'coefficients': results.params.tolist(),
117
+ 'std_errors': results.bse.tolist(),
118
+ 'z_values': results.tvalues.tolist(),
119
+ 'p_values': results.pvalues.tolist(),
120
+ 'pseudo_r_squared': float(results.prsquared),
121
+ 'log_likelihood': float(results.llf),
122
+ 'aic': float(results.aic),
123
+ 'bic': float(results.bic),
124
+ 'n_obs': int(results.nobs),
125
+ 'feature_names': feature_names or [f'X{i+1}' for i in range(X.shape[1])]
126
+ }
127
+
128
+ return json.dumps(formatted_results, indent=2, ensure_ascii=False)
129
+
130
+ except Exception as e:
131
+ logger.error(f"Probit failed: {str(e)}")
132
+ return json.dumps({'error': str(e)}, indent=2, ensure_ascii=False)
133
+
134
+
135
+ def multinomial_logit_adapter(
136
+ X_data: Optional[Union[List[float], List[List[float]]]] = None,
137
+ y_data: Optional[List[int]] = None,
138
+ file_path: Optional[str] = None,
139
+ feature_names: Optional[List[str]] = None,
140
+ output_format: str = 'json',
141
+ save_path: Optional[str] = None
142
+ ) -> str:
143
+ """Multinomial Logit adapter"""
144
+ try:
145
+ if file_path:
146
+ data = DataLoader.load_from_file(file_path)
147
+ X_data = data.get('x_data', data.get('X', data.get('features')))
148
+ y_data = data.get('y_data', data.get('y', data.get('target')))
149
+ if feature_names is None:
150
+ feature_names = data.get('feature_names')
151
+
152
+ if X_data is None or y_data is None:
153
+ raise ValueError("X_data and y_data must be provided")
154
+
155
+ X = np.array(X_data)
156
+ y = np.array(y_data)
157
+
158
+ if X.ndim == 1:
159
+ X = X.reshape(-1, 1)
160
+
161
+ model = MultinomialLogit()
162
+ model.fit(X, y)
163
+
164
+ results = model.results_
165
+ formatted_results = {
166
+ 'model_type': 'multinomial_logit',
167
+ 'coefficients': results.params.tolist(),
168
+ 'std_errors': results.bse.tolist(),
169
+ 'z_values': results.tvalues.tolist(),
170
+ 'p_values': results.pvalues.tolist(),
171
+ 'pseudo_r_squared': float(results.prsquared),
172
+ 'log_likelihood': float(results.llf),
173
+ 'aic': float(results.aic),
174
+ 'bic': float(results.bic),
175
+ 'n_obs': int(results.nobs),
176
+ 'classes': model.classes_.tolist(),
177
+ 'feature_names': feature_names or [f'X{i+1}' for i in range(X.shape[1])]
178
+ }
179
+
180
+ return json.dumps(formatted_results, indent=2, ensure_ascii=False)
181
+
182
+ except Exception as e:
183
+ logger.error(f"Multinomial Logit failed: {str(e)}")
184
+ return json.dumps({'error': str(e)}, indent=2, ensure_ascii=False)
185
+
186
+
187
+ def poisson_adapter(
188
+ X_data: Optional[Union[List[float], List[List[float]]]] = None,
189
+ y_data: Optional[List[int]] = None,
190
+ file_path: Optional[str] = None,
191
+ feature_names: Optional[List[str]] = None,
192
+ output_format: str = 'json',
193
+ save_path: Optional[str] = None
194
+ ) -> str:
195
+ """Poisson regression adapter"""
196
+ try:
197
+ if file_path:
198
+ data = DataLoader.load_from_file(file_path)
199
+ X_data = data.get('x_data', data.get('X', data.get('features')))
200
+ y_data = data.get('y_data', data.get('y', data.get('target')))
201
+ if feature_names is None:
202
+ feature_names = data.get('feature_names')
203
+
204
+ if X_data is None or y_data is None:
205
+ raise ValueError("X_data and y_data must be provided")
206
+
207
+ X = np.array(X_data)
208
+ y = np.array(y_data).astype(int)
209
+
210
+ if X.ndim == 1:
211
+ X = X.reshape(-1, 1)
212
+
213
+ model = PoissonModel()
214
+ model.fit(X, y)
215
+
216
+ results = model.results_
217
+ formatted_results = {
218
+ 'model_type': 'poisson',
219
+ 'coefficients': results.params.tolist(),
220
+ 'std_errors': results.bse.tolist(),
221
+ 'z_values': results.tvalues.tolist(),
222
+ 'p_values': results.pvalues.tolist(),
223
+ 'pseudo_r_squared': float(results.prsquared),
224
+ 'log_likelihood': float(results.llf),
225
+ 'aic': float(results.aic),
226
+ 'bic': float(results.bic),
227
+ 'n_obs': int(results.nobs),
228
+ 'feature_names': feature_names or [f'X{i+1}' for i in range(X.shape[1])]
229
+ }
230
+
231
+ return json.dumps(formatted_results, indent=2, ensure_ascii=False)
232
+
233
+ except Exception as e:
234
+ logger.error(f"Poisson failed: {str(e)}")
235
+ return json.dumps({'error': str(e)}, indent=2, ensure_ascii=False)
236
+
237
+
238
+ def negative_binomial_adapter(
239
+ X_data: Optional[Union[List[float], List[List[float]]]] = None,
240
+ y_data: Optional[List[int]] = None,
241
+ file_path: Optional[str] = None,
242
+ feature_names: Optional[List[str]] = None,
243
+ distr: str = 'nb2',
244
+ output_format: str = 'json',
245
+ save_path: Optional[str] = None
246
+ ) -> str:
247
+ """Negative Binomial regression adapter"""
248
+ try:
249
+ if file_path:
250
+ data = DataLoader.load_from_file(file_path)
251
+ X_data = data.get('x_data', data.get('X', data.get('features')))
252
+ y_data = data.get('y_data', data.get('y', data.get('target')))
253
+ if feature_names is None:
254
+ feature_names = data.get('feature_names')
255
+
256
+ if X_data is None or y_data is None:
257
+ raise ValueError("X_data and y_data must be provided")
258
+
259
+ X = np.array(X_data)
260
+ y = np.array(y_data).astype(int)
261
+
262
+ if X.ndim == 1:
263
+ X = X.reshape(-1, 1)
264
+
265
+ model = NegativeBinomialModel(distr=distr)
266
+ model.fit(X, y)
267
+
268
+ results = model.results_
269
+ formatted_results = {
270
+ 'model_type': 'negative_binomial',
271
+ 'distribution': distr,
272
+ 'coefficients': results.params.tolist(),
273
+ 'std_errors': results.bse.tolist(),
274
+ 'z_values': results.tvalues.tolist(),
275
+ 'p_values': results.pvalues.tolist(),
276
+ 'pseudo_r_squared': float(results.prsquared),
277
+ 'log_likelihood': float(results.llf),
278
+ 'aic': float(results.aic),
279
+ 'bic': float(results.bic),
280
+ 'n_obs': int(results.nobs),
281
+ 'feature_names': feature_names or [f'X{i+1}' for i in range(X.shape[1])]
282
+ }
283
+
284
+ return json.dumps(formatted_results, indent=2, ensure_ascii=False)
285
+
286
+ except Exception as e:
287
+ logger.error(f"Negative Binomial failed: {str(e)}")
288
+ return json.dumps({'error': str(e)}, indent=2, ensure_ascii=False)
289
+
290
+
291
+ def tobit_adapter(
292
+ X_data: Optional[Union[List[float], List[List[float]]]] = None,
293
+ y_data: Optional[List[float]] = None,
294
+ file_path: Optional[str] = None,
295
+ feature_names: Optional[List[str]] = None,
296
+ lower_bound: float = 0.0,
297
+ upper_bound: Optional[float] = None,
298
+ output_format: str = 'json',
299
+ save_path: Optional[str] = None
300
+ ) -> str:
301
+ """Tobit model adapter"""
302
+ try:
303
+ if file_path:
304
+ data = DataLoader.load_from_file(file_path)
305
+ X_data = data.get('x_data', data.get('X', data.get('features')))
306
+ y_data = data.get('y_data', data.get('y', data.get('target')))
307
+ if feature_names is None:
308
+ feature_names = data.get('feature_names')
309
+
310
+ if X_data is None or y_data is None:
311
+ raise ValueError("X_data and y_data must be provided")
312
+
313
+ X = np.array(X_data)
314
+ y = np.array(y_data)
315
+
316
+ if X.ndim == 1:
317
+ X = X.reshape(-1, 1)
318
+
319
+ model = TobitModel(lower_bound=lower_bound, upper_bound=upper_bound)
320
+ model.fit(X, y)
321
+
322
+ results = model.results_
323
+ formatted_results = {
324
+ 'model_type': 'tobit',
325
+ 'lower_bound': lower_bound,
326
+ 'upper_bound': upper_bound,
327
+ 'coefficients': results.params.tolist(),
328
+ 'std_errors': results.bse.tolist(),
329
+ 'z_values': results.tvalues.tolist(),
330
+ 'p_values': results.pvalues.tolist(),
331
+ 'log_likelihood': float(results.llf),
332
+ 'aic': float(results.aic),
333
+ 'bic': float(results.bic),
334
+ 'n_obs': int(results.nobs),
335
+ 'feature_names': feature_names or [f'X{i+1}' for i in range(X.shape[1])]
336
+ }
337
+
338
+ return json.dumps(formatted_results, indent=2, ensure_ascii=False)
339
+
340
+ except Exception as e:
341
+ logger.error(f"Tobit failed: {str(e)}")
342
+ return json.dumps({'error': str(e)}, indent=2, ensure_ascii=False)
343
+
344
+
345
+ def heckman_adapter(
346
+ X_select_data: Optional[Union[List[float], List[List[float]]]] = None,
347
+ Z_data: Optional[Union[List[float], List[List[float]]]] = None,
348
+ y_data: Optional[List[float]] = None,
349
+ s_data: Optional[List[int]] = None,
350
+ file_path: Optional[str] = None,
351
+ selection_feature_names: Optional[List[str]] = None,
352
+ outcome_feature_names: Optional[List[str]] = None,
353
+ output_format: str = 'json',
354
+ save_path: Optional[str] = None
355
+ ) -> str:
356
+ """Heckman selection model adapter"""
357
+ try:
358
+ if file_path:
359
+ data = DataLoader.load_from_file(file_path)
360
+ X_select_data = data.get('X_select', data.get('selection_features'))
361
+ Z_data = data.get('Z', data.get('outcome_features'))
362
+ y_data = data.get('y', data.get('outcome'))
363
+ s_data = data.get('s', data.get('selection'))
364
+ if selection_feature_names is None:
365
+ selection_feature_names = data.get('selection_feature_names')
366
+ if outcome_feature_names is None:
367
+ outcome_feature_names = data.get('outcome_feature_names')
368
+
369
+ if X_select_data is None or Z_data is None or y_data is None or s_data is None:
370
+ raise ValueError("All data must be provided")
371
+
372
+ X_select = np.array(X_select_data)
373
+ Z = np.array(Z_data)
374
+ y = np.array(y_data)
375
+ s = np.array(s_data).astype(int)
376
+
377
+ if X_select.ndim == 1:
378
+ X_select = X_select.reshape(-1, 1)
379
+ if Z.ndim == 1:
380
+ Z = Z.reshape(-1, 1)
381
+
382
+ model = HeckmanModel()
383
+ model.fit(X_select, Z, y, s)
384
+
385
+ selection_names = selection_feature_names or [f'SelectX{i+1}' for i in range(X_select.shape[1])]
386
+ outcome_names = outcome_feature_names or [f'OutcomeZ{i+1}' for i in range(Z.shape[1])]
387
+
388
+ formatted_results = {
389
+ 'model_type': 'heckman',
390
+ 'selection_results': {
391
+ 'coefficients': model.selection_results_.params.tolist(),
392
+ 'std_errors': model.selection_results_.bse.tolist(),
393
+ 'z_values': model.selection_results_.tvalues.tolist(),
394
+ 'p_values': model.selection_results_.pvalues.tolist(),
395
+ 'feature_names': selection_names
396
+ },
397
+ 'outcome_results': {
398
+ 'coefficients': model.outcome_results_.params.tolist(),
399
+ 'std_errors': model.outcome_results_.bse.tolist(),
400
+ 't_values': model.outcome_results_.tvalues.tolist(),
401
+ 'p_values': model.outcome_results_.pvalues.tolist(),
402
+ 'feature_names': outcome_names
403
+ },
404
+ 'n_obs': len(y),
405
+ 'n_selected': int(np.sum(s))
406
+ }
407
+
408
+ return json.dumps(formatted_results, indent=2, ensure_ascii=False)
409
+
410
+ except Exception as e:
411
+ logger.error(f"Heckman failed: {str(e)}")
412
+ return json.dumps({'error': str(e)}, indent=2, ensure_ascii=False)
@@ -0,0 +1,73 @@
1
+ """
2
+ 缺失数据处理适配器
3
+ """
4
+
5
+ from typing import List, Optional
6
+ import json
7
+
8
+ from econometrics.missing_data import (
9
+ simple_imputation,
10
+ multiple_imputation,
11
+ SimpleImputationResult,
12
+ MultipleImputationResult
13
+ )
14
+
15
+ from .output_formatter import OutputFormatter
16
+
17
+
18
+ def simple_imputation_adapter(
19
+ data: List[List[float]],
20
+ strategy: str = "mean",
21
+ fill_value: Optional[float] = None,
22
+ output_format: str = "json",
23
+ save_path: Optional[str] = None
24
+ ) -> str:
25
+ """简单插补适配器"""
26
+
27
+ result: SimpleImputationResult = simple_imputation(
28
+ data=data,
29
+ strategy=strategy,
30
+ fill_value=fill_value
31
+ )
32
+
33
+ if output_format == "json":
34
+ json_result = json.dumps(result.dict(), ensure_ascii=False, indent=2)
35
+ if save_path:
36
+ OutputFormatter.save_to_file(json_result, save_path)
37
+ return f"分析完成!结果已保存到: {save_path}\n\n{json_result}"
38
+ return json_result
39
+ else:
40
+ formatted = f"""# 简单插补结果\n\n{result.summary}"""
41
+ if save_path:
42
+ OutputFormatter.save_to_file(formatted, save_path)
43
+ return formatted
44
+
45
+
46
+ def multiple_imputation_adapter(
47
+ data: List[List[float]],
48
+ n_imputations: int = 5,
49
+ max_iter: int = 10,
50
+ random_state: Optional[int] = None,
51
+ output_format: str = "json",
52
+ save_path: Optional[str] = None
53
+ ) -> str:
54
+ """多重插补适配器"""
55
+
56
+ result: MultipleImputationResult = multiple_imputation(
57
+ data=data,
58
+ n_imputations=n_imputations,
59
+ max_iter=max_iter,
60
+ random_state=random_state
61
+ )
62
+
63
+ if output_format == "json":
64
+ json_result = json.dumps(result.dict(), ensure_ascii=False, indent=2)
65
+ if save_path:
66
+ OutputFormatter.save_to_file(json_result, save_path)
67
+ return f"分析完成!结果已保存到: {save_path}\n\n{json_result}"
68
+ return json_result
69
+ else:
70
+ formatted = f"""# 多重插补结果\n\n{result.summary}"""
71
+ if save_path:
72
+ OutputFormatter.save_to_file(formatted, save_path)
73
+ return formatted
@@ -0,0 +1,190 @@
1
+ """
2
+ 非参数与半参数方法适配器
3
+ 将核心算法适配为MCP工具
4
+ """
5
+
6
+ from typing import List, Optional
7
+ import json
8
+
9
+ from econometrics.nonparametric import (
10
+ kernel_regression,
11
+ quantile_regression,
12
+ spline_regression,
13
+ gam_model,
14
+ KernelRegressionResult,
15
+ QuantileRegressionResult,
16
+ SplineRegressionResult,
17
+ GAMResult
18
+ )
19
+
20
+ from .data_loader import DataLoader
21
+ from .output_formatter import OutputFormatter
22
+
23
+
24
+ def kernel_regression_adapter(
25
+ y_data: Optional[List[float]] = None,
26
+ x_data: Optional[List[List[float]]] = None,
27
+ file_path: Optional[str] = None,
28
+ kernel_type: str = "gaussian",
29
+ bandwidth: Optional[List[float]] = None,
30
+ bandwidth_method: str = "cv_ls",
31
+ variable_type: Optional[str] = None,
32
+ output_format: str = "json",
33
+ save_path: Optional[str] = None
34
+ ) -> str:
35
+ """核回归适配器"""
36
+
37
+ # 数据准备
38
+ if file_path:
39
+ data = DataLoader.load_from_file(file_path)
40
+ y_data = data["y_data"]
41
+ x_data = data["x_data"]
42
+ elif y_data is None or x_data is None:
43
+ raise ValueError("必须提供文件路径(file_path)或直接数据(y_data和x_data)")
44
+
45
+ # 调用核心算法
46
+ result: KernelRegressionResult = kernel_regression(
47
+ y_data=y_data,
48
+ x_data=x_data,
49
+ kernel_type=kernel_type,
50
+ bandwidth=bandwidth,
51
+ bandwidth_method=bandwidth_method,
52
+ variable_type=variable_type
53
+ )
54
+
55
+ # 格式化输出
56
+ if output_format == "json":
57
+ json_result = json.dumps(result.dict(), ensure_ascii=False, indent=2)
58
+ if save_path:
59
+ OutputFormatter.save_to_file(json_result, save_path)
60
+ return f"分析完成!结果已保存到: {save_path}\n\n{json_result}"
61
+ return json_result
62
+ else:
63
+ formatted = f"""# 核回归分析结果
64
+
65
+ {result.summary}
66
+
67
+ ## 模型信息
68
+ - 核函数: {result.kernel_type}
69
+ - 带宽: {', '.join([f'{b:.4f}' for b in result.bandwidth])}
70
+ - R²: {result.r_squared:.4f}
71
+ """
72
+ if result.aic:
73
+ formatted += f"- AIC: {result.aic:.2f}\n"
74
+
75
+ if save_path:
76
+ OutputFormatter.save_to_file(formatted, save_path)
77
+ return f"分析完成!\n\n{formatted}\n\n已保存到: {save_path}"
78
+ return formatted
79
+
80
+
81
+ def quantile_regression_adapter(
82
+ y_data: Optional[List[float]] = None,
83
+ x_data: Optional[List[List[float]]] = None,
84
+ file_path: Optional[str] = None,
85
+ quantile: float = 0.5,
86
+ feature_names: Optional[List[str]] = None,
87
+ confidence_level: float = 0.95,
88
+ output_format: str = "json",
89
+ save_path: Optional[str] = None
90
+ ) -> str:
91
+ """分位数回归适配器"""
92
+
93
+ # 数据准备
94
+ if file_path:
95
+ data = DataLoader.load_from_file(file_path)
96
+ y_data = data["y_data"]
97
+ x_data = data["x_data"]
98
+ feature_names = data.get("feature_names") or feature_names
99
+ elif y_data is None or x_data is None:
100
+ raise ValueError("必须提供文件路径(file_path)或直接数据(y_data和x_data)")
101
+
102
+ # 调用核心算法
103
+ result: QuantileRegressionResult = quantile_regression(
104
+ y_data=y_data,
105
+ x_data=x_data,
106
+ quantile=quantile,
107
+ feature_names=feature_names,
108
+ confidence_level=confidence_level
109
+ )
110
+
111
+ # 格式化输出
112
+ if output_format == "json":
113
+ json_result = json.dumps(result.dict(), ensure_ascii=False, indent=2)
114
+ if save_path:
115
+ OutputFormatter.save_to_file(json_result, save_path)
116
+ return f"分析完成!结果已保存到: {save_path}\n\n{json_result}"
117
+ return json_result
118
+ else:
119
+ formatted = f"""# 分位数回归分析结果
120
+
121
+ {result.summary}
122
+ """
123
+ if save_path:
124
+ OutputFormatter.save_to_file(formatted, save_path)
125
+ return f"分析完成!\n\n{formatted}\n\n已保存到: {save_path}"
126
+ return formatted
127
+
128
+
129
+ def spline_regression_adapter(
130
+ y_data: List[float],
131
+ x_data: List[float],
132
+ n_knots: int = 5,
133
+ degree: int = 3,
134
+ knots: str = "uniform",
135
+ output_format: str = "json",
136
+ save_path: Optional[str] = None
137
+ ) -> str:
138
+ """样条回归适配器"""
139
+
140
+ result: SplineRegressionResult = spline_regression(
141
+ y_data=y_data,
142
+ x_data=x_data,
143
+ n_knots=n_knots,
144
+ degree=degree,
145
+ knots=knots
146
+ )
147
+
148
+ if output_format == "json":
149
+ json_result = json.dumps(result.dict(), ensure_ascii=False, indent=2)
150
+ if save_path:
151
+ OutputFormatter.save_to_file(json_result, save_path)
152
+ return f"分析完成!结果已保存到: {save_path}\n\n{json_result}"
153
+ return json_result
154
+ else:
155
+ formatted = f"""# 样条回归结果\n\n{result.summary}"""
156
+ if save_path:
157
+ OutputFormatter.save_to_file(formatted, save_path)
158
+ return formatted
159
+
160
+
161
+ def gam_adapter(
162
+ y_data: List[float],
163
+ x_data: List[List[float]],
164
+ problem_type: str = "regression",
165
+ n_splines: int = 10,
166
+ lam: float = 0.6,
167
+ output_format: str = "json",
168
+ save_path: Optional[str] = None
169
+ ) -> str:
170
+ """GAM模型适配器"""
171
+
172
+ result: GAMResult = gam_model(
173
+ y_data=y_data,
174
+ x_data=x_data,
175
+ problem_type=problem_type,
176
+ n_splines=n_splines,
177
+ lam=lam
178
+ )
179
+
180
+ if output_format == "json":
181
+ json_result = json.dumps(result.dict(), ensure_ascii=False, indent=2)
182
+ if save_path:
183
+ OutputFormatter.save_to_file(json_result, save_path)
184
+ return f"分析完成!结果已保存到: {save_path}\n\n{json_result}"
185
+ return json_result
186
+ else:
187
+ formatted = f"""# GAM模型结果\n\n{result.summary}"""
188
+ if save_path:
189
+ OutputFormatter.save_to_file(formatted, save_path)
190
+ return formatted