aigroup-econ-mcp 0.3.8__py3-none-any.whl → 0.4.0__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.
- aigroup_econ_mcp/__init__.py +18 -18
- aigroup_econ_mcp/server.py +284 -3291
- aigroup_econ_mcp/server_v1_backup.py +1250 -0
- aigroup_econ_mcp/server_v1_old.py +1250 -0
- aigroup_econ_mcp/server_with_file_support.py +259 -0
- aigroup_econ_mcp/tools/__init__.py +3 -2
- aigroup_econ_mcp/tools/data_loader.py +171 -0
- aigroup_econ_mcp/tools/decorators.py +178 -0
- aigroup_econ_mcp/tools/file_input_handler.py +268 -0
- aigroup_econ_mcp/tools/file_parser.py +560 -0
- aigroup_econ_mcp/tools/machine_learning.py +14 -14
- aigroup_econ_mcp/tools/panel_data.py +10 -6
- aigroup_econ_mcp/tools/time_series.py +54 -127
- aigroup_econ_mcp/tools/tool_handlers.py +378 -0
- aigroup_econ_mcp/tools/tool_registry.py +170 -0
- {aigroup_econ_mcp-0.3.8.dist-info → aigroup_econ_mcp-0.4.0.dist-info}/METADATA +287 -22
- aigroup_econ_mcp-0.4.0.dist-info/RECORD +30 -0
- aigroup_econ_mcp-0.3.8.dist-info/RECORD +0 -21
- {aigroup_econ_mcp-0.3.8.dist-info → aigroup_econ_mcp-0.4.0.dist-info}/WHEEL +0 -0
- {aigroup_econ_mcp-0.3.8.dist-info → aigroup_econ_mcp-0.4.0.dist-info}/entry_points.txt +0 -0
- {aigroup_econ_mcp-0.3.8.dist-info → aigroup_econ_mcp-0.4.0.dist-info}/licenses/LICENSE +0 -0
aigroup_econ_mcp/server.py
CHANGED
|
@@ -1,119 +1,44 @@
|
|
|
1
|
-
|
|
2
1
|
"""
|
|
3
|
-
AIGroup 计量经济学 MCP 服务器
|
|
4
|
-
|
|
2
|
+
AIGroup 计量经济学 MCP 服务器 - 优化版
|
|
3
|
+
使用组件化架构,代码量减少80%,同时自动支持文件输入
|
|
5
4
|
"""
|
|
6
5
|
|
|
7
|
-
from typing import
|
|
6
|
+
from typing import Dict, Any, Optional, List, Annotated
|
|
8
7
|
from collections.abc import AsyncIterator
|
|
9
8
|
from contextlib import asynccontextmanager
|
|
10
9
|
from dataclasses import dataclass
|
|
11
|
-
import importlib.metadata
|
|
12
|
-
import json
|
|
13
|
-
import os
|
|
14
|
-
from pathlib import Path
|
|
15
10
|
|
|
16
|
-
import pandas as pd
|
|
17
|
-
import numpy as np
|
|
18
|
-
import statsmodels.api as sm
|
|
19
|
-
from statsmodels.tsa import stattools
|
|
20
|
-
from scipy import stats
|
|
21
11
|
from pydantic import BaseModel, Field
|
|
22
|
-
|
|
23
12
|
from mcp.server.fastmcp import FastMCP, Context
|
|
24
13
|
from mcp.server.session import ServerSession
|
|
25
14
|
from mcp.types import CallToolResult, TextContent
|
|
26
15
|
|
|
27
|
-
#
|
|
28
|
-
from .tools.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
# 返回默认配置
|
|
51
|
-
default_config = {
|
|
52
|
-
"performance": {
|
|
53
|
-
"cache": {"enabled": True, "ttl": 3600, "max_size": 1000},
|
|
54
|
-
"monitoring": {"enabled": True, "memory_check_interval": 1.0},
|
|
55
|
-
"timeouts": {
|
|
56
|
-
"simple_models": 30,
|
|
57
|
-
"complex_models": 120,
|
|
58
|
-
"machine_learning": 300,
|
|
59
|
-
"time_series": 180
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
"models": {
|
|
63
|
-
"descriptive_statistics": {"timeout": 30},
|
|
64
|
-
"ols_regression": {"timeout": 60},
|
|
65
|
-
"time_series_analysis": {"timeout": 120},
|
|
66
|
-
"panel_data_analysis": {"timeout": 180},
|
|
67
|
-
"var_model": {"timeout": 300},
|
|
68
|
-
"garch_model": {"timeout": 240},
|
|
69
|
-
"random_forest": {"timeout": 300},
|
|
70
|
-
"gradient_boosting": {"timeout": 300}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
print("⚠️ 使用默认性能配置")
|
|
74
|
-
return default_config
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# 数据模型定义 - 使用Pydantic实现结构化输出
|
|
78
|
-
class DescriptiveStatsResult(BaseModel):
|
|
79
|
-
"""描述性统计结果"""
|
|
80
|
-
count: int = Field(description="样本数量")
|
|
81
|
-
mean: float = Field(description="均值")
|
|
82
|
-
std: float = Field(description="标准差")
|
|
83
|
-
min: float = Field(description="最小值")
|
|
84
|
-
max: float = Field(description="最大值")
|
|
85
|
-
median: float = Field(description="中位数")
|
|
86
|
-
skewness: float = Field(description="偏度")
|
|
87
|
-
kurtosis: float = Field(description="峰度")
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
class OLSRegressionResult(BaseModel):
|
|
91
|
-
"""OLS回归分析结果"""
|
|
92
|
-
rsquared: float = Field(description="R²")
|
|
93
|
-
rsquared_adj: float = Field(description="调整R²")
|
|
94
|
-
f_statistic: float = Field(description="F统计量")
|
|
95
|
-
f_pvalue: float = Field(description="F检验p值")
|
|
96
|
-
aic: float = Field(description="AIC信息准则")
|
|
97
|
-
bic: float = Field(description="BIC信息准则")
|
|
98
|
-
coefficients: Dict[str, Dict[str, float]] = Field(description="回归系数详情")
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
class HypothesisTestResult(BaseModel):
|
|
102
|
-
"""假设检验结果"""
|
|
103
|
-
test_type: str = Field(description="检验类型")
|
|
104
|
-
statistic: float = Field(description="检验统计量")
|
|
105
|
-
p_value: float = Field(description="p值")
|
|
106
|
-
significant: bool = Field(description="是否显著(5%水平)")
|
|
107
|
-
confidence_interval: Optional[List[float]] = Field(default=None, description="置信区间")
|
|
108
|
-
|
|
16
|
+
# 导入工具处理器
|
|
17
|
+
from .tools.tool_handlers import (
|
|
18
|
+
handle_descriptive_statistics,
|
|
19
|
+
handle_ols_regression,
|
|
20
|
+
handle_hypothesis_testing,
|
|
21
|
+
handle_time_series_analysis,
|
|
22
|
+
handle_correlation_analysis,
|
|
23
|
+
handle_panel_fixed_effects,
|
|
24
|
+
handle_panel_random_effects,
|
|
25
|
+
handle_panel_hausman_test,
|
|
26
|
+
handle_panel_unit_root_test,
|
|
27
|
+
handle_var_model,
|
|
28
|
+
handle_vecm_model,
|
|
29
|
+
handle_garch_model,
|
|
30
|
+
handle_state_space_model,
|
|
31
|
+
handle_variance_decomposition,
|
|
32
|
+
handle_random_forest,
|
|
33
|
+
handle_gradient_boosting,
|
|
34
|
+
handle_lasso_regression,
|
|
35
|
+
handle_ridge_regression,
|
|
36
|
+
handle_cross_validation,
|
|
37
|
+
handle_feature_importance
|
|
38
|
+
)
|
|
109
39
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
adf_statistic: float = Field(description="ADF检验统计量")
|
|
113
|
-
adf_pvalue: float = Field(description="ADF检验p值")
|
|
114
|
-
stationary: bool = Field(description="是否平稳")
|
|
115
|
-
acf: List[float] = Field(description="自相关函数")
|
|
116
|
-
pacf: List[float] = Field(description="偏自相关函数")
|
|
40
|
+
# 导入装饰器
|
|
41
|
+
from .tools.decorators import econometric_tool
|
|
117
42
|
|
|
118
43
|
|
|
119
44
|
# 应用上下文
|
|
@@ -121,3339 +46,407 @@ class TimeSeriesStatsResult(BaseModel):
|
|
|
121
46
|
class AppContext:
|
|
122
47
|
"""应用上下文,包含共享资源"""
|
|
123
48
|
config: Dict[str, Any]
|
|
124
|
-
version: str =
|
|
125
|
-
performance_config: Dict[str, Any] = None
|
|
126
|
-
timeout_manager: Any = None
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
# 服务器图标(已移除,因为MCP库不再支持Icon类)
|
|
49
|
+
version: str = "0.2.0"
|
|
130
50
|
|
|
131
51
|
|
|
132
52
|
@asynccontextmanager
|
|
133
53
|
async def lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
|
|
134
54
|
"""服务器生命周期管理"""
|
|
135
|
-
# 启动时初始化资源
|
|
136
55
|
config = {
|
|
137
56
|
"max_sample_size": 10000,
|
|
138
57
|
"default_significance_level": 0.05,
|
|
139
58
|
"supported_tests": ["t_test", "f_test", "chi_square", "adf"],
|
|
140
59
|
"data_types": ["cross_section", "time_series", "panel"]
|
|
141
60
|
}
|
|
142
|
-
|
|
143
|
-
# 加载性能配置
|
|
144
|
-
performance_config = load_performance_config()
|
|
145
|
-
|
|
146
|
-
# 初始化超时管理器
|
|
147
|
-
timeout_manager = TimeoutManager()
|
|
148
|
-
timeout_manager.set_timeout_config(performance_config.get("timeouts", {}))
|
|
149
|
-
|
|
150
61
|
try:
|
|
151
|
-
yield AppContext(
|
|
152
|
-
config=config,
|
|
153
|
-
version=importlib.metadata.version("aigroup-econ-mcp"),
|
|
154
|
-
performance_config=performance_config,
|
|
155
|
-
timeout_manager=timeout_manager
|
|
156
|
-
)
|
|
62
|
+
yield AppContext(config=config, version="0.2.0")
|
|
157
63
|
finally:
|
|
158
|
-
# 清理资源
|
|
159
64
|
pass
|
|
160
65
|
|
|
161
66
|
|
|
162
67
|
# 创建MCP服务器实例
|
|
163
68
|
mcp = FastMCP(
|
|
164
69
|
name="aigroup-econ-mcp",
|
|
165
|
-
instructions="Econometrics MCP Server - Provides data analysis
|
|
70
|
+
instructions="Econometrics MCP Server - Provides data analysis with automatic file input support",
|
|
166
71
|
lifespan=lifespan
|
|
167
72
|
)
|
|
168
73
|
|
|
169
74
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
datasets = {
|
|
174
|
-
"economic_growth": """
|
|
175
|
-
GDP Growth,Inflation Rate,Unemployment Rate,Investment Rate
|
|
176
|
-
3.2,2.1,4.5,15.2
|
|
177
|
-
2.8,2.3,4.2,14.8
|
|
178
|
-
3.5,1.9,4.0,16.1
|
|
179
|
-
2.9,2.4,4.3,15.5
|
|
180
|
-
""",
|
|
181
|
-
"stock_returns": """
|
|
182
|
-
Stock A,Stock B,Stock C
|
|
183
|
-
0.02,-0.01,0.015
|
|
184
|
-
-0.015,0.025,-0.008
|
|
185
|
-
0.018,-0.005,0.012
|
|
186
|
-
""",
|
|
187
|
-
"time_series": """
|
|
188
|
-
Date,Sales,Advertising Expense
|
|
189
|
-
2023-01,12000,800
|
|
190
|
-
2023-02,13500,900
|
|
191
|
-
2023-03,11800,750
|
|
192
|
-
2023-04,14200,1000
|
|
193
|
-
"""
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if dataset_name not in datasets:
|
|
197
|
-
return f"Available datasets: {', '.join(datasets.keys())}"
|
|
198
|
-
|
|
199
|
-
return datasets[dataset_name]
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
@mcp.prompt(title="Economic Data Analysis")
|
|
203
|
-
def economic_analysis_prompt(data_description: str, analysis_type: str = "descriptive") -> str:
|
|
204
|
-
"""Economic data analysis prompt template"""
|
|
205
|
-
prompts = {
|
|
206
|
-
"descriptive": "Please perform descriptive statistical analysis on the following economic data:",
|
|
207
|
-
"regression": "Please perform regression analysis on the following economic data to identify key factors:",
|
|
208
|
-
"hypothesis": "Please perform hypothesis testing on the following economic data to verify research assumptions:",
|
|
209
|
-
"time_series": "Please analyze the following time series data to check stationarity and correlation:"
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
return f"{prompts.get(analysis_type, prompts['descriptive'])}\n\nData description: {data_description}"
|
|
213
|
-
|
|
75
|
+
# ============================================================================
|
|
76
|
+
# 基础统计工具 (5个) - 自动支持文件输入
|
|
77
|
+
# ============================================================================
|
|
214
78
|
|
|
215
79
|
@mcp.tool()
|
|
80
|
+
@econometric_tool('multi_var_dict')
|
|
216
81
|
async def descriptive_statistics(
|
|
217
82
|
ctx: Context[ServerSession, AppContext],
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
示例格式:
|
|
224
|
-
{
|
|
225
|
-
"GDP增长率": [3.2, 2.8, 3.5, 2.9],
|
|
226
|
-
"通货膨胀率": [2.1, 2.3, 1.9, 2.4],
|
|
227
|
-
"失业率": [4.5, 4.2, 4.0, 4.3]
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
要求:
|
|
231
|
-
- 至少包含一个变量
|
|
232
|
-
- 每个变量的数据点数量应相同
|
|
233
|
-
- 数值必须为浮点数或整数
|
|
234
|
-
- 建议样本量 >= 30 以获得可靠的统计推断"""
|
|
235
|
-
)
|
|
236
|
-
]
|
|
83
|
+
file_path: Annotated[Optional[str], Field(default=None, description="CSV/JSON文件路径")] = None,
|
|
84
|
+
file_content: Annotated[Optional[str], Field(default=None, description="CSV/JSON文件内容")] = None,
|
|
85
|
+
file_format: Annotated[str, Field(default="auto", description="文件格式(csv/json/auto)")] = "auto",
|
|
86
|
+
data: Annotated[Optional[Dict[str, List[float]]], Field(default=None, description="数据字典(直接数据输入)")] = None
|
|
237
87
|
) -> CallToolResult:
|
|
238
|
-
"""计算描述性统计量
|
|
239
|
-
|
|
240
|
-
📊 功能说明:
|
|
241
|
-
对输入数据进行全面的描述性统计分析,包括集中趋势、离散程度、分布形状等指标。
|
|
242
|
-
|
|
243
|
-
📈 输出指标:
|
|
244
|
-
- 样本数量 (count)
|
|
245
|
-
- 均值 (mean):数据的平均水平
|
|
246
|
-
- 标准差 (std):数据的离散程度
|
|
247
|
-
- 最小值/最大值 (min/max):数据的取值范围
|
|
248
|
-
- 中位数 (median):数据的中间值,对异常值不敏感
|
|
249
|
-
- 偏度 (skewness):分布的对称性,0表示对称,>0右偏,<0左偏
|
|
250
|
-
- 峰度 (kurtosis):分布的尖峭程度,0表示正态分布
|
|
251
|
-
- 相关系数矩阵:变量间的线性相关关系
|
|
252
|
-
|
|
253
|
-
💡 使用场景:
|
|
254
|
-
- 初步了解数据的分布特征
|
|
255
|
-
- 检查数据质量和异常值
|
|
256
|
-
- 为后续建模提供基础信息
|
|
257
|
-
- 比较不同变量的统计特征
|
|
258
|
-
|
|
259
|
-
⚠️ 注意事项:
|
|
260
|
-
- 偏度绝对值 > 1 表示数据明显偏斜,可能需要转换
|
|
261
|
-
- 峰度绝对值 > 3 表示尖峭或扁平分布
|
|
262
|
-
- 相关系数 > 0.8 表示强相关,可能存在多重共线性
|
|
263
|
-
|
|
264
|
-
Args:
|
|
265
|
-
data: 数据字典,键为变量名,值为数值列表
|
|
266
|
-
ctx: MCP上下文对象
|
|
267
88
|
"""
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
try:
|
|
271
|
-
# 获取超时管理器
|
|
272
|
-
timeout_manager = ctx.session.context.timeout_manager
|
|
273
|
-
model_timeout = ctx.session.context.performance_config.get("models", {}).get("descriptive_statistics", {}).get("timeout", 30)
|
|
274
|
-
|
|
275
|
-
# 使用超时控制执行计算
|
|
276
|
-
result = await timeout_manager.execute_with_timeout(
|
|
277
|
-
model_name="descriptive_statistics",
|
|
278
|
-
timeout_seconds=model_timeout,
|
|
279
|
-
func=_compute_descriptive_stats,
|
|
280
|
-
data=data
|
|
281
|
-
)
|
|
282
|
-
|
|
283
|
-
await ctx.info(f"描述性统计计算完成,样本大小: {result['count']}")
|
|
284
|
-
|
|
285
|
-
return CallToolResult(
|
|
286
|
-
content=[
|
|
287
|
-
TextContent(
|
|
288
|
-
type="text",
|
|
289
|
-
text=f"描述性统计结果:\n"
|
|
290
|
-
f"均值: {result['mean']:.4f}\n"
|
|
291
|
-
f"标准差: {result['std']:.4f}\n"
|
|
292
|
-
f"最小值: {result['min']:.4f}\n"
|
|
293
|
-
f"最大值: {result['max']:.4f}\n"
|
|
294
|
-
f"中位数: {result['median']:.4f}\n"
|
|
295
|
-
f"偏度: {result['skewness']:.4f}\n"
|
|
296
|
-
f"峰度: {result['kurtosis']:.4f}\n\n"
|
|
297
|
-
f"相关系数矩阵:\n{result['correlation_matrix']}"
|
|
298
|
-
)
|
|
299
|
-
],
|
|
300
|
-
structuredContent=result
|
|
301
|
-
)
|
|
302
|
-
|
|
303
|
-
except TimeoutError:
|
|
304
|
-
await ctx.error("描述性统计计算超时,请减少数据量或调整配置")
|
|
305
|
-
return CallToolResult(
|
|
306
|
-
content=[TextContent(type="text", text="错误: 计算超时,请减少数据量或调整配置")],
|
|
307
|
-
isError=True
|
|
308
|
-
)
|
|
309
|
-
except Exception as e:
|
|
310
|
-
await ctx.error(f"计算描述性统计时出错: {str(e)}")
|
|
311
|
-
return CallToolResult(
|
|
312
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
313
|
-
isError=True
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
def _compute_descriptive_stats(data: Dict[str, List[float]]) -> Dict[str, Any]:
|
|
318
|
-
"""计算描述性统计(同步函数,用于超时控制)"""
|
|
319
|
-
# 数据验证
|
|
320
|
-
if not data:
|
|
321
|
-
raise ValueError("数据不能为空")
|
|
322
|
-
|
|
323
|
-
df = pd.DataFrame(data)
|
|
324
|
-
|
|
325
|
-
# 检查数据一致性
|
|
326
|
-
if len(df.columns) == 0:
|
|
327
|
-
raise ValueError("至少需要一个变量")
|
|
89
|
+
计算描述性统计量
|
|
328
90
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
"max": float(df.max().max()), # 所有变量的最大值
|
|
336
|
-
"median": float(df.median().mean()), # 所有变量的中位数均值
|
|
337
|
-
"skewness": float(df.skew().mean()), # 所有变量的偏度均值
|
|
338
|
-
"kurtosis": float(df.kurtosis().mean()) # 所有变量的峰度均值
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
# 计算相关系数矩阵
|
|
342
|
-
correlation_matrix = df.corr().round(4)
|
|
343
|
-
result["correlation_matrix"] = correlation_matrix.to_string()
|
|
344
|
-
|
|
345
|
-
return result
|
|
91
|
+
支持三种输入方式(按优先级):
|
|
92
|
+
1. file_path: 文件路径 (如 "data.csv")
|
|
93
|
+
2. file_content: 文件内容字符串
|
|
94
|
+
3. data: 直接传入数据字典
|
|
95
|
+
"""
|
|
96
|
+
return await handle_descriptive_statistics(ctx, data=data)
|
|
346
97
|
|
|
347
98
|
|
|
348
99
|
@mcp.tool()
|
|
100
|
+
@econometric_tool('regression')
|
|
349
101
|
async def ols_regression(
|
|
350
102
|
ctx: Context[ServerSession, AppContext],
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
要求:
|
|
359
|
-
- 必须为数值列表
|
|
360
|
-
- 长度必须与自变量观测数量一致
|
|
361
|
-
- 不能包含缺失值(NaN)
|
|
362
|
-
- 建议样本量 >= 30"""
|
|
363
|
-
)
|
|
364
|
-
],
|
|
365
|
-
x_data: Annotated[
|
|
366
|
-
List[List[float]],
|
|
367
|
-
Field(
|
|
368
|
-
description="""自变量数据(解释变量/预测变量),二维列表格式
|
|
369
|
-
|
|
370
|
-
示例格式(3个观测,2个自变量):
|
|
371
|
-
[
|
|
372
|
-
[800, 5.2], # 第1个观测的自变量值
|
|
373
|
-
[900, 5.8], # 第2个观测的自变量值
|
|
374
|
-
[750, 4.9] # 第3个观测的自变量值
|
|
375
|
-
]
|
|
376
|
-
|
|
377
|
-
要求:
|
|
378
|
-
- 外层列表:每个元素代表一个观测
|
|
379
|
-
- 内层列表:该观测的所有自变量值
|
|
380
|
-
- 所有观测的自变量数量必须相同
|
|
381
|
-
- 观测数量必须与y_data长度一致
|
|
382
|
-
- 自变量数量建议 < 观测数量/10(避免过拟合)"""
|
|
383
|
-
)
|
|
384
|
-
],
|
|
385
|
-
feature_names: Annotated[
|
|
386
|
-
Optional[List[str]],
|
|
387
|
-
Field(
|
|
388
|
-
default=None,
|
|
389
|
-
description="""自变量名称列表(可选)
|
|
390
|
-
|
|
391
|
-
示例:["广告支出", "价格指数"]
|
|
392
|
-
|
|
393
|
-
说明:
|
|
394
|
-
- 如果不提供,将自动命名为 x1, x2, x3...
|
|
395
|
-
- 名称数量必须与自变量数量一致
|
|
396
|
-
- 建议使用有意义的名称以便解释结果"""
|
|
397
|
-
)
|
|
398
|
-
] = None
|
|
103
|
+
file_path: Annotated[Optional[str], Field(default=None, description="CSV/JSON文件路径")] = None,
|
|
104
|
+
file_content: Annotated[Optional[str], Field(default=None, description="CSV/JSON文件内容")] = None,
|
|
105
|
+
file_format: Annotated[str, Field(default="auto", description="文件格式")] = "auto",
|
|
106
|
+
y_data: Annotated[Optional[List[float]], Field(default=None, description="因变量(直接输入)")] = None,
|
|
107
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None, description="自变量(直接输入)")] = None,
|
|
108
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None, description="特征名称")] = None
|
|
399
109
|
) -> CallToolResult:
|
|
400
|
-
"""执行普通最小二乘法(OLS)回归分析
|
|
401
|
-
|
|
402
|
-
📊 功能说明:
|
|
403
|
-
使用最小二乘法估计线性回归模型,分析因变量与自变量之间的线性关系。
|
|
404
|
-
模型形式:Y = β₀ + β₁X₁ + β₂X₂ + ... + βₖXₖ + ε
|
|
405
|
-
|
|
406
|
-
📈 输出指标:
|
|
407
|
-
- R²:决定系数,取值0-1,衡量模型拟合优度
|
|
408
|
-
- 调整R²:考虑自变量数量的修正R²
|
|
409
|
-
- F统计量及p值:检验模型整体显著性
|
|
410
|
-
- AIC/BIC:信息准则,用于模型比较,越小越好
|
|
411
|
-
- 回归系数:每个自变量的估计值、标准误、t统计量、p值、置信区间
|
|
412
|
-
|
|
413
|
-
💡 使用场景:
|
|
414
|
-
- 因果关系分析(如广告支出对销售额的影响)
|
|
415
|
-
- 预测建模(如根据经济指标预测GDP)
|
|
416
|
-
- 控制变量分析(如研究教育回报率时控制工作经验)
|
|
417
|
-
- 假设检验(如检验某变量是否对结果有显著影响)
|
|
418
|
-
|
|
419
|
-
⚠️ 注意事项:
|
|
420
|
-
- R² > 0.7 表示拟合良好,但需警惕过拟合
|
|
421
|
-
- p值 < 0.05 表示该系数在5%水平显著
|
|
422
|
-
- 需检查残差的正态性、同方差性和独立性假设
|
|
423
|
-
- 自变量间高度相关(相关系数>0.8)可能导致多重共线性问题
|
|
424
|
-
- 样本量过小可能导致不可靠的估计结果
|
|
425
|
-
|
|
426
|
-
Args:
|
|
427
|
-
y_data: 因变量数据
|
|
428
|
-
x_data: 自变量数据,每行一个观测
|
|
429
|
-
feature_names: 自变量名称(可选)
|
|
430
|
-
ctx: MCP上下文对象
|
|
431
110
|
"""
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
try:
|
|
435
|
-
# 获取超时管理器
|
|
436
|
-
timeout_manager = ctx.session.context.timeout_manager
|
|
437
|
-
model_timeout = ctx.session.context.performance_config.get("models", {}).get("ols_regression", {}).get("timeout", 60)
|
|
438
|
-
|
|
439
|
-
# 使用超时控制执行计算
|
|
440
|
-
result = await timeout_manager.execute_with_timeout(
|
|
441
|
-
model_name="ols_regression",
|
|
442
|
-
timeout_seconds=model_timeout,
|
|
443
|
-
func=_compute_ols_regression,
|
|
444
|
-
y_data=y_data,
|
|
445
|
-
x_data=x_data,
|
|
446
|
-
feature_names=feature_names
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
await ctx.info("OLS回归分析完成")
|
|
450
|
-
|
|
451
|
-
return CallToolResult(
|
|
452
|
-
content=[
|
|
453
|
-
TextContent(
|
|
454
|
-
type="text",
|
|
455
|
-
text=f"OLS回归分析结果:\n"
|
|
456
|
-
f"R² = {result['rsquared']:.4f}\n"
|
|
457
|
-
f"调整R² = {result['rsquared_adj']:.4f}\n"
|
|
458
|
-
f"F统计量 = {result['f_statistic']:.4f} (p = {result['f_pvalue']:.4f})\n"
|
|
459
|
-
f"AIC = {result['aic']:.2f}, BIC = {result['bic']:.2f}\n\n"
|
|
460
|
-
f"回归系数:\n{result['summary_table']}"
|
|
461
|
-
)
|
|
462
|
-
],
|
|
463
|
-
structuredContent=result
|
|
464
|
-
)
|
|
465
|
-
|
|
466
|
-
except TimeoutError:
|
|
467
|
-
await ctx.error("OLS回归分析超时,请减少数据量或调整配置")
|
|
468
|
-
return CallToolResult(
|
|
469
|
-
content=[TextContent(type="text", text="错误: 计算超时,请减少数据量或调整配置")],
|
|
470
|
-
isError=True
|
|
471
|
-
)
|
|
472
|
-
except Exception as e:
|
|
473
|
-
await ctx.error(f"OLS回归分析出错: {str(e)}")
|
|
474
|
-
return CallToolResult(
|
|
475
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
476
|
-
isError=True
|
|
477
|
-
)
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
def _compute_ols_regression(y_data: List[float], x_data: List[List[float]], feature_names: Optional[List[str]] = None) -> Dict[str, Any]:
|
|
481
|
-
"""计算OLS回归(同步函数,用于超时控制)"""
|
|
482
|
-
# 数据验证
|
|
483
|
-
if not y_data:
|
|
484
|
-
raise ValueError("因变量数据不能为空")
|
|
485
|
-
if not x_data:
|
|
486
|
-
raise ValueError("自变量数据不能为空")
|
|
487
|
-
if len(y_data) != len(x_data):
|
|
488
|
-
raise ValueError(f"因变量和自变量的观测数量不一致: y_data={len(y_data)}, x_data={len(x_data)}")
|
|
489
|
-
|
|
490
|
-
# 准备数据
|
|
491
|
-
X = np.array(x_data)
|
|
492
|
-
y = np.array(y_data)
|
|
493
|
-
|
|
494
|
-
# 添加常数项
|
|
495
|
-
X_with_const = sm.add_constant(X)
|
|
496
|
-
|
|
497
|
-
# 拟合模型
|
|
498
|
-
model = sm.OLS(y, X_with_const).fit()
|
|
499
|
-
|
|
500
|
-
# 构建系数字典
|
|
501
|
-
conf_int = model.conf_int()
|
|
502
|
-
coefficients = {}
|
|
503
|
-
|
|
504
|
-
# 处理feature_names
|
|
505
|
-
if feature_names is None:
|
|
506
|
-
feature_names = [f"x{i+1}" for i in range(X.shape[1])]
|
|
507
|
-
elif len(feature_names) != X.shape[1]:
|
|
508
|
-
feature_names = [f"x{i+1}" for i in range(X.shape[1])]
|
|
509
|
-
|
|
510
|
-
for i, coef in enumerate(model.params):
|
|
511
|
-
if i == 0:
|
|
512
|
-
var_name = "const"
|
|
513
|
-
else:
|
|
514
|
-
var_name = feature_names[i-1]
|
|
515
|
-
|
|
516
|
-
coefficients[var_name] = {
|
|
517
|
-
"coef": float(coef),
|
|
518
|
-
"std_err": float(model.bse[i]),
|
|
519
|
-
"t_value": float(model.tvalues[i]),
|
|
520
|
-
"p_value": float(model.pvalues[i]),
|
|
521
|
-
"ci_lower": float(conf_int[i][0]),
|
|
522
|
-
"ci_upper": float(conf_int[i][1])
|
|
523
|
-
}
|
|
111
|
+
OLS回归分析
|
|
524
112
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
"f_statistic": float(model.fvalue),
|
|
530
|
-
"f_pvalue": float(model.f_pvalue),
|
|
531
|
-
"aic": float(model.aic),
|
|
532
|
-
"bic": float(model.bic),
|
|
533
|
-
"coefficients": coefficients,
|
|
534
|
-
"summary_table": str(model.summary().tables[1])
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
return result
|
|
113
|
+
支持文件输入或直接数据输入。文件格式示例:
|
|
114
|
+
CSV: 最后一列为因变量,其余列为自变量
|
|
115
|
+
"""
|
|
116
|
+
return await handle_ols_regression(ctx, y_data=y_data, x_data=x_data, feature_names=feature_names)
|
|
538
117
|
|
|
539
118
|
|
|
540
119
|
@mcp.tool()
|
|
120
|
+
@econometric_tool('single_var')
|
|
541
121
|
async def hypothesis_testing(
|
|
542
122
|
ctx: Context[ServerSession, AppContext],
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
要求:
|
|
551
|
-
- 必须为数值列表
|
|
552
|
-
- 不能包含缺失值
|
|
553
|
-
- 建议样本量 >= 30(大样本)
|
|
554
|
-
- t检验要求数据近似正态分布"""
|
|
555
|
-
)
|
|
556
|
-
],
|
|
557
|
-
data2: Annotated[
|
|
558
|
-
Optional[List[float]],
|
|
559
|
-
Field(
|
|
560
|
-
default=None,
|
|
561
|
-
description="""第二组数据(可选,用于双样本检验)
|
|
562
|
-
|
|
563
|
-
示例:[2.5, 2.9, 2.3, 2.6, 2.8]
|
|
564
|
-
|
|
565
|
-
说明:
|
|
566
|
-
- 仅在双样本t检验时需要提供
|
|
567
|
-
- 单样本t检验时保持为None
|
|
568
|
-
- 两组数据可以
|
|
569
|
-
有不同的样本量
|
|
570
|
-
- ADF检验不需要第二组数据"""
|
|
571
|
-
)
|
|
572
|
-
] = None,
|
|
573
|
-
test_type: Annotated[
|
|
574
|
-
str,
|
|
575
|
-
Field(
|
|
576
|
-
default="t_test",
|
|
577
|
-
description="""假设检验类型
|
|
578
|
-
|
|
579
|
-
可选值:
|
|
580
|
-
- "t_test": t检验(默认)
|
|
581
|
-
* 单样本t检验:检验样本均值是否等于0(data2=None)
|
|
582
|
-
* 双样本t检验:检验两组样本均值是否相等(提供data2)
|
|
583
|
-
|
|
584
|
-
- "adf": 增强迪基-富勒检验(Augmented Dickey-Fuller Test)
|
|
585
|
-
* 用于检验时间序列的平稳性
|
|
586
|
-
* 原假设:存在单位根(非平稳)
|
|
587
|
-
* p<0.05 拒绝原假设,序列平稳
|
|
588
|
-
|
|
589
|
-
使用建议:
|
|
590
|
-
- 比较均值差异 → 使用 t_test
|
|
591
|
-
- 检验时间序列平稳性 → 使用 adf"""
|
|
592
|
-
)
|
|
593
|
-
] = "t_test"
|
|
123
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
124
|
+
file_content: Annotated[Optional[str], Field(default=None, description="文件内容")] = None,
|
|
125
|
+
file_format: Annotated[str, Field(default="auto", description="文件格式")] = "auto",
|
|
126
|
+
data: Annotated[Optional[List[float]], Field(default=None, description="第一组数据")] = None,
|
|
127
|
+
data2: Annotated[Optional[List[float]], Field(default=None, description="第二组数据")] = None,
|
|
128
|
+
test_type: Annotated[str, Field(default="t_test", description="检验类型(t_test/adf)")] = "t_test"
|
|
594
129
|
) -> CallToolResult:
|
|
595
|
-
"""
|
|
596
|
-
|
|
597
|
-
📊 功能说明:
|
|
598
|
-
对数据进行统计假设检验,判断样本是否支持某个统计假设。
|
|
599
|
-
|
|
600
|
-
📈 检验类型详解:
|
|
601
|
-
|
|
602
|
-
1️⃣ t检验 (t_test):
|
|
603
|
-
- 单样本:H₀: μ = 0 vs H₁: μ ≠ 0
|
|
604
|
-
- 双样本:H₀: μ₁ = μ₂ vs H₁: μ₁ ≠ μ₂
|
|
605
|
-
- 适用于小样本(n<30)且数据近似正态分布
|
|
606
|
-
|
|
607
|
-
2️⃣ ADF检验 (adf):
|
|
608
|
-
- H₀: 序列存在单位根(非平稳)
|
|
609
|
-
- H₁: 序列不存在单位根(平稳)
|
|
610
|
-
- 用于时间序列分析前的平稳性检验
|
|
611
|
-
|
|
612
|
-
📊 输出指标:
|
|
613
|
-
- 检验统计量:用于判断是否拒绝原假设
|
|
614
|
-
- p值:显著性水平,<0.05表示在5%水平显著
|
|
615
|
-
- 是否显著:基于5%显著性水平的判断
|
|
616
|
-
- 置信区间:参数的可能取值范围(仅t检验)
|
|
617
|
-
|
|
618
|
-
💡 使用场景:
|
|
619
|
-
- 检验新药是否有效(单样本t检验)
|
|
620
|
-
- 比较两种教学方法的效果差异(双样本t检验)
|
|
621
|
-
- 检验股价序列是否平稳(ADF检验)
|
|
622
|
-
- 验证经济理论假说(如购买力平价理论)
|
|
623
|
-
|
|
624
|
-
⚠️ 注意事项:
|
|
625
|
-
- p值 < 0.05:拒绝原假设(结果显著)
|
|
626
|
-
- p值 >= 0.05:不能拒绝原假设(结果不显著)
|
|
627
|
-
- t检验要求数据近似正态分布
|
|
628
|
-
- 小样本(<30)时t检验结果可能不可靠
|
|
629
|
-
- ADF检验中p<0.05表示序列平稳(拒绝非平稳假设)
|
|
630
|
-
|
|
631
|
-
Args:
|
|
632
|
-
data1: 第一组数据
|
|
633
|
-
data2: 第二组数据(可选,用于双样本检验)
|
|
634
|
-
test_type: 检验类型(t_test或adf)
|
|
635
|
-
ctx: MCP上下文对象
|
|
636
|
-
"""
|
|
637
|
-
await ctx.info(f"开始假设检验: {test_type}")
|
|
638
|
-
|
|
639
|
-
try:
|
|
640
|
-
if test_type == "t_test":
|
|
641
|
-
if data2 is None:
|
|
642
|
-
# 单样本t检验
|
|
643
|
-
result = stats.ttest_1samp(data1, 0)
|
|
644
|
-
ci = stats.t.interval(0.95, len(data1)-1, loc=np.mean(data1), scale=stats.sem(data1))
|
|
645
|
-
else:
|
|
646
|
-
# 双样本t检验
|
|
647
|
-
result = stats.ttest_ind(data1, data2)
|
|
648
|
-
ci = None # 双样本t检验不计算置信区间
|
|
649
|
-
|
|
650
|
-
test_result = HypothesisTestResult(
|
|
651
|
-
test_type=test_type,
|
|
652
|
-
statistic=result.statistic,
|
|
653
|
-
p_value=result.pvalue,
|
|
654
|
-
significant=result.pvalue < 0.05,
|
|
655
|
-
confidence_interval=list(ci) if ci else None
|
|
656
|
-
)
|
|
657
|
-
|
|
658
|
-
elif test_type == "adf":
|
|
659
|
-
# ADF单位根检验
|
|
660
|
-
result = stattools.adfuller(data1)
|
|
661
|
-
test_result = HypothesisTestResult(
|
|
662
|
-
test_type="adf",
|
|
663
|
-
statistic=result[0],
|
|
664
|
-
p_value=result[1],
|
|
665
|
-
significant=result[1] < 0.05,
|
|
666
|
-
confidence_interval=None
|
|
667
|
-
)
|
|
668
|
-
else:
|
|
669
|
-
raise ValueError(f"不支持的检验类型: {test_type}")
|
|
670
|
-
|
|
671
|
-
await ctx.info(f"假设检验完成: {test_type}")
|
|
672
|
-
|
|
673
|
-
return CallToolResult(
|
|
674
|
-
content=[
|
|
675
|
-
TextContent(
|
|
676
|
-
type="text",
|
|
677
|
-
text=f"{test_type.upper()}检验结果:\n"
|
|
678
|
-
f"检验统计量 = {test_result.statistic:.4f}\n"
|
|
679
|
-
f"p值 = {test_result.p_value:.4f}\n"
|
|
680
|
-
f"{'显著' if test_result.significant else '不显著'} (5%水平)\n"
|
|
681
|
-
f"{f'95%置信区间: [{test_result.confidence_interval[0]:.4f}, {test_result.confidence_interval[1]:.4f}]' if test_result.confidence_interval else ''}"
|
|
682
|
-
)
|
|
683
|
-
],
|
|
684
|
-
structuredContent=test_result.model_dump()
|
|
685
|
-
)
|
|
686
|
-
|
|
687
|
-
except Exception as e:
|
|
688
|
-
await ctx.error(f"假设检验出错: {str(e)}")
|
|
689
|
-
return CallToolResult(
|
|
690
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
691
|
-
isError=True
|
|
692
|
-
)
|
|
130
|
+
"""假设检验 - 支持文件或直接数据输入"""
|
|
131
|
+
return await handle_hypothesis_testing(ctx, data1=data, data2=data2, test_type=test_type)
|
|
693
132
|
|
|
694
133
|
|
|
695
134
|
@mcp.tool()
|
|
135
|
+
@econometric_tool('single_var')
|
|
696
136
|
async def time_series_analysis(
|
|
697
137
|
ctx: Context[ServerSession, AppContext],
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
示例格式:
|
|
704
|
-
[12000, 13500, 11800, 14200, 15100, 14800, 16200, 15900]
|
|
705
|
-
# 表示连续8期的观测值,如月度销售额
|
|
706
|
-
|
|
707
|
-
要求:
|
|
708
|
-
- 必须按时间顺序排列(从早到晚)
|
|
709
|
-
- 建议至少30个观测点以获得可靠结果
|
|
710
|
-
- 数据应等间隔采样(如日度、月度、季度)
|
|
711
|
-
- 不能包含缺失值
|
|
712
|
-
- 数据量越大,ACF/PACF分析越准确
|
|
713
|
-
|
|
714
|
-
应用示例:
|
|
715
|
-
- 股票价格序列
|
|
716
|
-
- GDP季度数据
|
|
717
|
-
- 月度销售额
|
|
718
|
-
- 日均气温数据"""
|
|
719
|
-
)
|
|
720
|
-
]
|
|
138
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
139
|
+
file_content: Annotated[Optional[str], Field(default=None, description="文件内容")] = None,
|
|
140
|
+
file_format: Annotated[str, Field(default="auto", description="文件格式")] = "auto",
|
|
141
|
+
data: Annotated[Optional[List[float]], Field(default=None, description="时间序列数据")] = None
|
|
721
142
|
) -> CallToolResult:
|
|
722
|
-
"""
|
|
723
|
-
|
|
724
|
-
📊 功能说明:
|
|
725
|
-
对时间序列数据进行全面的统计分析,包括平稳性检验和自相关分析。
|
|
726
|
-
|
|
727
|
-
📈 分析内容:
|
|
728
|
-
|
|
729
|
-
1️⃣ ADF单位根检验(Augmented Dickey-Fuller Test):
|
|
730
|
-
- 检验序列是否平稳
|
|
731
|
-
- H₀: 存在单位根(序列非平稳)
|
|
732
|
-
- p < 0.05:拒绝原假设,序列平稳
|
|
733
|
-
- 平稳性是时间序列建模的基础
|
|
734
|
-
|
|
735
|
-
2️⃣ 自相关函数(ACF):
|
|
736
|
-
- 衡量序列与其滞后值之间的相关性
|
|
737
|
-
- 用于识别MA模型的阶数
|
|
738
|
-
- 指数衰减→AR过程;q阶截尾→MA(q)过程
|
|
739
|
-
|
|
740
|
-
3️⃣ 偏自相关函数(PACF):
|
|
741
|
-
- 剔除中间滞后项影响后的相关性
|
|
742
|
-
- 用于识别AR模型的阶数
|
|
743
|
-
- p阶截尾→AR(p)过程
|
|
744
|
-
|
|
745
|
-
📊 输出指标:
|
|
746
|
-
- ADF统计量:越负越可能平稳
|
|
747
|
-
- ADF p值:<0.05表示序列平稳
|
|
748
|
-
- 平稳性判断:基于5%显著性水平
|
|
749
|
-
- ACF值:前20阶(或更少)的自相关系数
|
|
750
|
-
- PACF值:前20阶(或更少)的偏自相关系数
|
|
751
|
-
|
|
752
|
-
💡 使用场景:
|
|
753
|
-
- ARIMA建模前的平稳性检验
|
|
754
|
-
- 识别合适的时间序列模型(AR、MA、ARMA)
|
|
755
|
-
- 检测季节性和趋势
|
|
756
|
-
- 评估序列的记忆性和持续性
|
|
757
|
-
|
|
758
|
-
⚠️ 注意事项:
|
|
759
|
-
- 非平稳序列需要差分或变换后才能建模
|
|
760
|
-
- ACF和PACF应结合使用以识别模型类型
|
|
761
|
-
- 数据点太少(<30)可能导致不可靠的结果
|
|
762
|
-
- 强烈的季节性可能影响ACF/PACF的解读
|
|
763
|
-
- 建议同时观察ACF/PACF图形以获得更好的直观理解
|
|
764
|
-
|
|
765
|
-
📖 结果解读:
|
|
766
|
-
- ADF p值 < 0.05 + ACF快速衰减 → 平稳序列,可直接建模
|
|
767
|
-
- ADF p值 >= 0.05 → 非平稳序列,需要差分处理
|
|
768
|
-
- PACF在p阶截尾 → 考虑AR(p)模型
|
|
769
|
-
- ACF在q阶截尾 → 考虑MA(q)模型
|
|
770
|
-
- ACF和PACF都衰减 → 考虑ARMA模型
|
|
771
|
-
|
|
772
|
-
Args:
|
|
773
|
-
data: 时间序列数据(按时间顺序)
|
|
774
|
-
ctx: MCP上下文对象
|
|
775
|
-
"""
|
|
776
|
-
await ctx.info(f"开始时间序列分析,数据点数量: {len(data)}")
|
|
777
|
-
|
|
778
|
-
try:
|
|
779
|
-
# 数据验证
|
|
780
|
-
if not data:
|
|
781
|
-
raise ValueError("时间序列数据不能为空")
|
|
782
|
-
if len(data) < 5:
|
|
783
|
-
raise ValueError("时间序列数据至少需要5个观测点")
|
|
784
|
-
|
|
785
|
-
# ADF单位根检验
|
|
786
|
-
adf_result = stattools.adfuller(data)
|
|
787
|
-
|
|
788
|
-
# 自相关和偏自相关函数
|
|
789
|
-
# 修复:安全计算nlags,避免PACF计算失败
|
|
790
|
-
max_nlags = min(20, len(data) - 1, len(data) // 2)
|
|
791
|
-
if max_nlags < 1:
|
|
792
|
-
max_nlags = 1 # 确保至少计算1阶
|
|
793
|
-
|
|
794
|
-
# 修复:使用try-except处理ACF/PACF计算可能失败的情况
|
|
795
|
-
try:
|
|
796
|
-
acf_values = stattools.acf(data, nlags=max_nlags)
|
|
797
|
-
pacf_values = stattools.pacf(data, nlags=max_nlags)
|
|
798
|
-
except Exception as acf_error:
|
|
799
|
-
await ctx.warning(f"ACF/PACF计算遇到问题: {str(acf_error)},使用简化计算")
|
|
800
|
-
# 使用更简单的计算方法
|
|
801
|
-
acf_values = np.zeros(max_nlags + 1)
|
|
802
|
-
pacf_values = np.zeros(max_nlags + 1)
|
|
803
|
-
acf_values[0] = 1.0 # 0阶自相关总是1
|
|
804
|
-
pacf_values[0] = 1.0 # 0阶偏自相关总是1
|
|
805
|
-
|
|
806
|
-
# 转换numpy类型为Python原生类型
|
|
807
|
-
result = TimeSeriesStatsResult(
|
|
808
|
-
adf_statistic=float(adf_result[0]),
|
|
809
|
-
adf_pvalue=float(adf_result[1]),
|
|
810
|
-
stationary=bool(adf_result[1] < 0.05),
|
|
811
|
-
acf=[float(x) for x in acf_values.tolist()],
|
|
812
|
-
pacf=[float(x) for x in pacf_values.tolist()]
|
|
813
|
-
)
|
|
814
|
-
|
|
815
|
-
await ctx.info("时间序列分析完成")
|
|
816
|
-
|
|
817
|
-
return CallToolResult(
|
|
818
|
-
content=[
|
|
819
|
-
TextContent(
|
|
820
|
-
type="text",
|
|
821
|
-
text=f"时间序列分析结果:\n"
|
|
822
|
-
f"ADF检验统计量 = {result.adf_statistic:.4f}\n"
|
|
823
|
-
f"ADF检验p值 = {result.adf_pvalue:.4f}\n"
|
|
824
|
-
f"{'平稳' if result.stationary else '非平稳'}序列\n"
|
|
825
|
-
f"ACF前5阶: {result.acf[:5]}\n"
|
|
826
|
-
f"PACF前5阶: {result.pacf[:5]}"
|
|
827
|
-
)
|
|
828
|
-
],
|
|
829
|
-
structuredContent=result.model_dump()
|
|
830
|
-
)
|
|
831
|
-
|
|
832
|
-
except Exception as e:
|
|
833
|
-
await ctx.error(f"时间序列分析出错: {str(e)}")
|
|
834
|
-
return CallToolResult(
|
|
835
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
836
|
-
isError=True
|
|
837
|
-
)
|
|
143
|
+
"""时间序列分析 - 支持文件或直接数据输入"""
|
|
144
|
+
return await handle_time_series_analysis(ctx, data=data)
|
|
838
145
|
|
|
839
146
|
|
|
840
147
|
@mcp.tool()
|
|
148
|
+
@econometric_tool('multi_var_dict')
|
|
841
149
|
async def correlation_analysis(
|
|
842
150
|
ctx: Context[ServerSession, AppContext],
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
示例格式:
|
|
849
|
-
{
|
|
850
|
-
"销售额": [12000, 13500, 11800, 14200],
|
|
851
|
-
"广告支出": [800, 900, 750, 1000],
|
|
852
|
-
"价格": [99, 95, 102, 98],
|
|
853
|
-
"竞争对手数量": [3, 3, 4, 3]
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
要求:
|
|
857
|
-
- 至少包含2个变量
|
|
858
|
-
- 所有变量的数据点数量必须相同
|
|
859
|
-
- 建议样本量 >= 30
|
|
860
|
-
- 数值不能包含缺失值
|
|
861
|
-
|
|
862
|
-
应用:
|
|
863
|
-
- 探索变量间的关联关系
|
|
864
|
-
- 识别潜在的多重共线性
|
|
865
|
-
- 为回归分析筛选变量"""
|
|
866
|
-
)
|
|
867
|
-
],
|
|
868
|
-
method: Annotated[
|
|
869
|
-
str,
|
|
870
|
-
Field(
|
|
871
|
-
default="pearson",
|
|
872
|
-
description="""相关系数计算方法
|
|
873
|
-
|
|
874
|
-
可选值:
|
|
875
|
-
- "pearson": 皮尔逊相关系数(默认)
|
|
876
|
-
* 衡量线性相关关系
|
|
877
|
-
* 取值范围:-1到1
|
|
878
|
-
* 要求:数据近似正态分布
|
|
879
|
-
* 对异常值敏感
|
|
880
|
-
|
|
881
|
-
- "spearman": 斯皮尔曼秩相关系数
|
|
882
|
-
* 衡量单调相关关系(不要求线性)
|
|
883
|
-
* 基于数据的秩次
|
|
884
|
-
* 对异常值不敏感
|
|
885
|
-
* 适用于非正态分布
|
|
886
|
-
|
|
887
|
-
- "kendall": 肯德尔τ相关系数
|
|
888
|
-
* 衡量一致性程度
|
|
889
|
-
* 更稳健但计算较慢
|
|
890
|
-
* 适用于小样本和有序数据
|
|
891
|
-
|
|
892
|
-
选择建议:
|
|
893
|
-
- 数据正态分布 + 关注线性关系 → pearson
|
|
894
|
-
- 数据有异常值或非正态 → spearman
|
|
895
|
-
- 有序分类数据 → kendall"""
|
|
896
|
-
)
|
|
897
|
-
] = "pearson"
|
|
151
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
152
|
+
file_content: Annotated[Optional[str], Field(default=None, description="文件内容")] = None,
|
|
153
|
+
file_format: Annotated[str, Field(default="auto", description="文件格式")] = "auto",
|
|
154
|
+
data: Annotated[Optional[Dict[str, List[float]]], Field(default=None, description="多变量数据")] = None,
|
|
155
|
+
method: Annotated[str, Field(default="pearson", description="相关系数类型")] = "pearson"
|
|
898
156
|
) -> CallToolResult:
|
|
899
|
-
"""
|
|
900
|
-
|
|
901
|
-
📊 功能说明:
|
|
902
|
-
计算多个变量之间的相关系数矩阵,揭示变量间的关联关系强度和方向。
|
|
903
|
-
|
|
904
|
-
📈 相关系数解读:
|
|
905
|
-
- 相关系数范围:-1 到 +1
|
|
906
|
-
- |r| = 0.0-0.3:弱相关或无相关
|
|
907
|
-
- |r| = 0.3-0.7:中等程度相关
|
|
908
|
-
- |r| = 0.7-1.0:强相关
|
|
909
|
-
- r > 0:正相关(同向变化)
|
|
910
|
-
- r < 0:负相关(反向变化)
|
|
911
|
-
- r = 0:无线性相关
|
|
912
|
-
|
|
913
|
-
💡 使用场景:
|
|
914
|
-
- 探索性数据分析(EDA)
|
|
915
|
-
- 回归分析前的变量筛选
|
|
916
|
-
- 识别多重共线性问题
|
|
917
|
-
- 构建投资组合(寻找低相关资产)
|
|
918
|
-
- 因子分析和主成分分析的前置步骤
|
|
919
|
-
|
|
920
|
-
⚠️ 注意事项:
|
|
921
|
-
- 相关≠因果:高相关不代表因果关系
|
|
922
|
-
- 皮尔逊相关仅衡量线性关系,可能错过非线性关系
|
|
923
|
-
- 异常值会显著影响皮尔逊相关系数
|
|
924
|
-
- 回归分析中,自变量间相关系数>0.8可能导致多重共线性
|
|
925
|
-
- 小样本(<30)的相关系数可能不稳定
|
|
926
|
-
|
|
927
|
-
📖 实际应用示例:
|
|
928
|
-
- 营销分析:广告支出与销售额的相关性
|
|
929
|
-
- 金融分析:不同股票收益率之间的相关性
|
|
930
|
-
- 经济研究:GDP增长与失业率的关系
|
|
931
|
-
- 多重共线性检测:回归模型中自变量间的相关性
|
|
932
|
-
|
|
933
|
-
Args:
|
|
934
|
-
data: 变量数据字典
|
|
935
|
-
method: 相关系数类型(pearson/spearman/kendall)
|
|
936
|
-
ctx: MCP上下文对象
|
|
937
|
-
"""
|
|
938
|
-
await ctx.info(f"开始相关性分析: {method}")
|
|
939
|
-
|
|
940
|
-
try:
|
|
941
|
-
# 数据验证
|
|
942
|
-
if not data:
|
|
943
|
-
raise ValueError("数据不能为空")
|
|
944
|
-
if len(data) < 2:
|
|
945
|
-
raise ValueError("至少需要2个变量进行相关性分析")
|
|
946
|
-
|
|
947
|
-
df = pd.DataFrame(data)
|
|
948
|
-
correlation_matrix = df.corr(method=method)
|
|
949
|
-
|
|
950
|
-
await ctx.info("相关性分析完成")
|
|
951
|
-
|
|
952
|
-
# 修复:返回正确的CallToolResult类型
|
|
953
|
-
return CallToolResult(
|
|
954
|
-
content=[
|
|
955
|
-
TextContent(
|
|
956
|
-
type="text",
|
|
957
|
-
text=f"{method.title()}相关系数矩阵:\n{correlation_matrix.round(4).to_string()}"
|
|
958
|
-
)
|
|
959
|
-
]
|
|
960
|
-
)
|
|
961
|
-
|
|
962
|
-
except Exception as e:
|
|
963
|
-
await ctx.error(f"相关性分析出错: {str(e)}")
|
|
964
|
-
return CallToolResult(
|
|
965
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
966
|
-
isError=True
|
|
967
|
-
)
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
def create_mcp_server() -> FastMCP:
|
|
971
|
-
"""创建并返回MCP服务器实例"""
|
|
972
|
-
return mcp
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
# 面板数据分析工具
|
|
976
|
-
# 高级时间序列分析工具
|
|
977
|
-
from .tools.time_series import (
|
|
978
|
-
VARModelResult,
|
|
979
|
-
VECMModelResult,
|
|
980
|
-
GARCHModelResult,
|
|
981
|
-
StateSpaceModelResult,
|
|
982
|
-
var_model,
|
|
983
|
-
vecm_model,
|
|
984
|
-
garch_model,
|
|
985
|
-
state_space_model,
|
|
986
|
-
forecast_var,
|
|
987
|
-
impulse_response_analysis,
|
|
988
|
-
variance_decomposition
|
|
989
|
-
)
|
|
157
|
+
"""相关性分析 - 支持文件或直接数据输入"""
|
|
158
|
+
return await handle_correlation_analysis(ctx, data=data, method=method)
|
|
990
159
|
|
|
991
160
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
max_lags: int = Field(default=5, description="最大滞后阶数")
|
|
996
|
-
ic: str = Field(default="aic", description="信息准则")
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
class VECMModelArguments(BaseModel):
|
|
1000
|
-
"""VECM模型参数"""
|
|
1001
|
-
data: Dict[str, List[float]] = Field(description="多变量时间序列数据")
|
|
1002
|
-
coint_rank: int = Field(default=1, description="协整秩")
|
|
1003
|
-
deterministic: str = Field(default="co", description="确定性项")
|
|
1004
|
-
max_lags: int = Field(default=5, description="最大滞后阶数")
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
class GARCHModelArguments(BaseModel):
|
|
1008
|
-
"""GARCH模型参数"""
|
|
1009
|
-
data: List[float] = Field(description="时间序列数据")
|
|
1010
|
-
order: Tuple[int, int] = Field(default=(1, 1), description="GARCH阶数")
|
|
1011
|
-
dist: str = Field(default="normal", description="误差分布")
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
class StateSpaceModelArguments(BaseModel):
|
|
1015
|
-
"""状态空间模型参数"""
|
|
1016
|
-
data: List[float] = Field(description="时间序列数据")
|
|
1017
|
-
state_dim: int = Field(default=1, description="状态维度")
|
|
1018
|
-
observation_dim: int = Field(default=1, description="观测维度")
|
|
1019
|
-
trend: bool = Field(default=True, description="是否包含趋势项")
|
|
1020
|
-
seasonal: bool = Field(default=False, description="是否包含季节项")
|
|
1021
|
-
period: int = Field(default=12, description="季节周期")
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
class VARForecastArguments(BaseModel):
|
|
1025
|
-
"""VAR预测参数"""
|
|
1026
|
-
data: Dict[str, List[float]] = Field(description="多变量时间序列数据")
|
|
1027
|
-
steps: int = Field(default=10, description="预测步数")
|
|
1028
|
-
max_lags: int = Field(default=5, description="最大滞后阶数")
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
class ImpulseResponseArguments(BaseModel):
|
|
1032
|
-
"""脉冲响应分析参数"""
|
|
1033
|
-
data: Dict[str, List[float]] = Field(description="多变量时间序列数据")
|
|
1034
|
-
periods: int = Field(default=10, description="响应期数")
|
|
1035
|
-
max_lags: int = Field(default=5, description="最大滞后阶数")
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
class VarianceDecompositionArguments(BaseModel):
|
|
1039
|
-
"""方差分解参数"""
|
|
1040
|
-
data: Dict[str, List[float]] = Field(description="多变量时间序列数据")
|
|
1041
|
-
periods: int = Field(default=10, description="分解期数")
|
|
1042
|
-
max_lags: int = Field(default=5, description="最大滞后阶数")
|
|
1043
|
-
from .tools.panel_data import (
|
|
1044
|
-
FixedEffectsResult,
|
|
1045
|
-
RandomEffectsResult,
|
|
1046
|
-
HausmanTestResult,
|
|
1047
|
-
PanelUnitRootResult,
|
|
1048
|
-
fixed_effects_model,
|
|
1049
|
-
random_effects_model,
|
|
1050
|
-
hausman_test,
|
|
1051
|
-
panel_unit_root_test,
|
|
1052
|
-
compare_panel_models
|
|
1053
|
-
)
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
class FixedEffectsArguments(BaseModel):
|
|
1057
|
-
"""固定效应模型参数"""
|
|
1058
|
-
y_data: List[float] = Field(description="因变量数据")
|
|
1059
|
-
x_data: List[List[float]] = Field(description="自变量数据")
|
|
1060
|
-
entity_ids: List[str] = Field(description="个体标识符")
|
|
1061
|
-
time_periods: List[str] = Field(description="时间标识符")
|
|
1062
|
-
feature_names: Optional[List[str]] = Field(default=None, description="自变量名称")
|
|
1063
|
-
entity_effects: bool = Field(default=True, description="是否包含个体效应")
|
|
1064
|
-
time_effects: bool = Field(default=False, description="是否包含时间效应")
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
class RandomEffectsArguments(BaseModel):
|
|
1068
|
-
"""随机效应模型参数"""
|
|
1069
|
-
y_data: List[float] = Field(description="因变量数据")
|
|
1070
|
-
x_data: List[List[float]] = Field(description="自变量数据")
|
|
1071
|
-
entity_ids: List[str] = Field(description="个体标识符")
|
|
1072
|
-
time_periods: List[str] = Field(description="时间标识符")
|
|
1073
|
-
feature_names: Optional[List[str]] = Field(default=None, description="自变量名称")
|
|
1074
|
-
entity_effects: bool = Field(default=True, description="是否包含个体效应")
|
|
1075
|
-
time_effects: bool = Field(default=False, description="是否包含时间效应")
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
class HausmanTestArguments(BaseModel):
|
|
1079
|
-
"""Hausman检验参数"""
|
|
1080
|
-
y_data: List[float] = Field(description="因变量数据")
|
|
1081
|
-
x_data: List[List[float]] = Field(description="自变量数据")
|
|
1082
|
-
entity_ids: List[str] = Field(description="个体标识符")
|
|
1083
|
-
time_periods: List[str] = Field(description="时间标识符")
|
|
1084
|
-
feature_names: Optional[List[str]] = Field(default=None, description="自变量名称")
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
class PanelUnitRootArguments(BaseModel):
|
|
1088
|
-
"""面板单位根检验参数"""
|
|
1089
|
-
data: List[float] = Field(description="面板数据序列")
|
|
1090
|
-
entity_ids: List[str] = Field(description="个体标识符")
|
|
1091
|
-
time_periods: List[str] = Field(description="时间标识符")
|
|
1092
|
-
test_type: str = Field(default="levinlin", description="检验类型")
|
|
1093
|
-
|
|
161
|
+
# ============================================================================
|
|
162
|
+
# 面板数据工具 (4个) - 自动支持文件输入
|
|
163
|
+
# ============================================================================
|
|
1094
164
|
|
|
1095
165
|
@mcp.tool()
|
|
166
|
+
@econometric_tool('panel')
|
|
1096
167
|
async def panel_fixed_effects(
|
|
1097
168
|
ctx: Context[ServerSession, AppContext],
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
],
|
|
1112
|
-
x_data: Annotated[
|
|
1113
|
-
List[List[float]],
|
|
1114
|
-
Field(
|
|
1115
|
-
description="""自变量数据(解释变量),二维列表格式
|
|
1116
|
-
|
|
1117
|
-
示例格式(5个观测,2个自变量):
|
|
1118
|
-
[
|
|
1119
|
-
[5, 100], # 第1个观测的自变量值
|
|
1120
|
-
[6, 98], # 第2个观测的自变量值
|
|
1121
|
-
[7.5, 95], # 第3个观测的自变量值
|
|
1122
|
-
[6.5, 97], # 第4个观测的自变量值
|
|
1123
|
-
[9, 92] # 第5个观测的自变量值
|
|
1124
|
-
]
|
|
1125
|
-
|
|
1126
|
-
要求:
|
|
1127
|
-
- 外层列表:每个元素代表一个观测
|
|
1128
|
-
- 内层列表:该观测的所有自变量值
|
|
1129
|
-
- 所有观测的自变量数量必须相同
|
|
1130
|
-
- 观测数量必须与y_data长度一致"""
|
|
1131
|
-
)
|
|
1132
|
-
],
|
|
1133
|
-
entity_ids: Annotated[
|
|
1134
|
-
List[str],
|
|
1135
|
-
Field(
|
|
1136
|
-
description="""个体标识符列表
|
|
1137
|
-
|
|
1138
|
-
示例:["公司A", "公司A", "公司A", "公司B", "公司B", "公司B"]
|
|
1139
|
-
|
|
1140
|
-
要求:
|
|
1141
|
-
- 长度必须与观测数量一致
|
|
1142
|
-
- 建议使用有意义的标识符
|
|
1143
|
-
- 每个个体应有多个时间观测"""
|
|
1144
|
-
)
|
|
1145
|
-
],
|
|
1146
|
-
time_periods: Annotated[
|
|
1147
|
-
List[str],
|
|
1148
|
-
Field(
|
|
1149
|
-
description="""时间标识符列表
|
|
1150
|
-
|
|
1151
|
-
示例:["2020Q1", "2020Q2", "2020Q3", "2020Q1", "2020Q2", "2020Q3"]
|
|
1152
|
-
|
|
1153
|
-
要求:
|
|
1154
|
-
- 长度必须与观测数量一致
|
|
1155
|
-
- 建议使用标准时间格式
|
|
1156
|
-
- 每个时间点可以有多个个体观测"""
|
|
1157
|
-
)
|
|
1158
|
-
],
|
|
1159
|
-
feature_names: Annotated[
|
|
1160
|
-
Optional[List[str]],
|
|
1161
|
-
Field(
|
|
1162
|
-
default=None,
|
|
1163
|
-
description="""自变量名称列表(可选)
|
|
1164
|
-
|
|
1165
|
-
示例:["广告支出", "价格"]
|
|
1166
|
-
|
|
1167
|
-
说明:
|
|
1168
|
-
- 如果不提供,将自动命名为 x1, x2, x3...
|
|
1169
|
-
- 名称数量必须与自变量数量一致
|
|
1170
|
-
- 建议使用有意义的名称以便解释结果"""
|
|
1171
|
-
)
|
|
1172
|
-
] = None,
|
|
1173
|
-
entity_effects: Annotated[
|
|
1174
|
-
bool,
|
|
1175
|
-
Field(
|
|
1176
|
-
default=True,
|
|
1177
|
-
description="""是否包含个体效应
|
|
1178
|
-
|
|
1179
|
-
说明:
|
|
1180
|
-
- True:包含个体固定效应(默认)
|
|
1181
|
-
- False:不包含个体固定效应
|
|
1182
|
-
- 通常建议包含个体效应以控制个体间差异"""
|
|
1183
|
-
)
|
|
1184
|
-
] = True,
|
|
1185
|
-
time_effects: Annotated[
|
|
1186
|
-
bool,
|
|
1187
|
-
Field(
|
|
1188
|
-
default=False,
|
|
1189
|
-
description="""是否包含时间效应
|
|
1190
|
-
|
|
1191
|
-
说明:
|
|
1192
|
-
- True:包含时间固定效应
|
|
1193
|
-
- False:不包含时间固定效应(默认)
|
|
1194
|
-
- 如果存在时间趋势,建议包含时间效应"""
|
|
1195
|
-
)
|
|
1196
|
-
] = False
|
|
169
|
+
file_path: Annotated[Optional[str], Field(
|
|
170
|
+
default=None,
|
|
171
|
+
description="CSV文件路径。CSV格式要求:必须包含实体ID列(列名含entity_id/id/entity/firm/company/country/region之一)和时间列(列名含time_period/time/date/year/month/period/quarter之一)"
|
|
172
|
+
)] = None,
|
|
173
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
174
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
175
|
+
y_data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
176
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None)] = None,
|
|
177
|
+
entity_ids: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
178
|
+
time_periods: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
179
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
180
|
+
entity_effects: Annotated[bool, Field(default=True)] = True,
|
|
181
|
+
time_effects: Annotated[bool, Field(default=False)] = False
|
|
1197
182
|
) -> CallToolResult:
|
|
1198
|
-
"""
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
固定效应模型假设个体间存在不可观测的固定差异,通过组内变换消除这些固定效应。
|
|
1202
|
-
适用于个体特征不随时间变化的情况。
|
|
1203
|
-
|
|
1204
|
-
📈 模型形式:
|
|
1205
|
-
y_it = α_i + βX_it + ε_it
|
|
1206
|
-
|
|
1207
|
-
💡 使用场景:
|
|
1208
|
-
- 研究个体内部随时间变化的影响
|
|
1209
|
-
- 控制个体固定特征的影响
|
|
1210
|
-
- 面板数据中个体间存在系统性差异
|
|
1211
|
-
|
|
1212
|
-
⚠️ 注意事项:
|
|
1213
|
-
- 无法估计不随时间变化的变量的系数
|
|
1214
|
-
- 需要较大的时间维度以获得可靠估计
|
|
1215
|
-
- 对个体异质性敏感
|
|
1216
|
-
|
|
1217
|
-
Args:
|
|
1218
|
-
y_data: 因变量数据
|
|
1219
|
-
x_data: 自变量数据
|
|
1220
|
-
entity_ids: 个体标识符
|
|
1221
|
-
time_periods: 时间标识符
|
|
1222
|
-
feature_names: 自变量名称
|
|
1223
|
-
entity_effects: 是否包含个体效应
|
|
1224
|
-
time_effects: 是否包含时间效应
|
|
1225
|
-
ctx: MCP上下文对象
|
|
1226
|
-
"""
|
|
1227
|
-
await ctx.info(f"开始固定效应模型分析,样本大小: {len(y_data)},个体数量: {len(set(entity_ids))}")
|
|
1228
|
-
|
|
1229
|
-
try:
|
|
1230
|
-
# 数据验证
|
|
1231
|
-
if not y_data:
|
|
1232
|
-
raise ValueError("因变量数据不能为空")
|
|
1233
|
-
if not x_data:
|
|
1234
|
-
raise ValueError("自变量数据不能为空")
|
|
1235
|
-
if len(y_data) != len(x_data):
|
|
1236
|
-
raise ValueError(f"因变量和自变量的观测数量不一致: y_data={len(y_data)}, x_data={len(x_data)}")
|
|
1237
|
-
if len(y_data) != len(entity_ids):
|
|
1238
|
-
raise ValueError(f"因变量和个体标识符数量不一致: y_data={len(y_data)}, entity_ids={len(entity_ids)}")
|
|
1239
|
-
if len(y_data) != len(time_periods):
|
|
1240
|
-
raise ValueError(f"因变量和时间标识符数量不一致: y_data={len(y_data)}, time_periods={len(time_periods)}")
|
|
1241
|
-
|
|
1242
|
-
# 执行固定效应模型分析
|
|
1243
|
-
result = fixed_effects_model(
|
|
1244
|
-
y_data, x_data, entity_ids, time_periods, feature_names,
|
|
1245
|
-
entity_effects, time_effects
|
|
1246
|
-
)
|
|
1247
|
-
|
|
1248
|
-
await ctx.info("固定效应模型分析完成")
|
|
1249
|
-
|
|
1250
|
-
return CallToolResult(
|
|
1251
|
-
content=[
|
|
1252
|
-
TextContent(
|
|
1253
|
-
type="text",
|
|
1254
|
-
text=f"固定效应模型分析结果:\n"
|
|
1255
|
-
f"R² = {result.rsquared:.4f}\n"
|
|
1256
|
-
f"调整R² = {result.rsquared_adj:.4f}\n"
|
|
1257
|
-
f"F统计量 = {result.f_statistic:.4f} (p = {result.f_pvalue:.4f})\n"
|
|
1258
|
-
f"AIC = {result.aic:.2f}, BIC = {result.bic:.2f}\n"
|
|
1259
|
-
f"组内R² = {result.within_rsquared:.4f}\n"
|
|
1260
|
-
f"观测数量 = {result.n_obs}\n"
|
|
1261
|
-
f"个体效应: {'是' if result.entity_effects else '否'}, "
|
|
1262
|
-
f"时间效应: {'是' if result.time_effects else '否'}"
|
|
1263
|
-
)
|
|
1264
|
-
],
|
|
1265
|
-
structuredContent=result.model_dump()
|
|
1266
|
-
)
|
|
1267
|
-
|
|
1268
|
-
except Exception as e:
|
|
1269
|
-
await ctx.error(f"固定效应模型分析出错: {str(e)}")
|
|
1270
|
-
return CallToolResult(
|
|
1271
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
1272
|
-
isError=True
|
|
1273
|
-
)
|
|
183
|
+
"""固定效应模型 - 支持文件输入"""
|
|
184
|
+
return await handle_panel_fixed_effects(ctx, y_data, x_data, entity_ids, time_periods,
|
|
185
|
+
feature_names, entity_effects, time_effects)
|
|
1274
186
|
|
|
1275
187
|
|
|
1276
188
|
@mcp.tool()
|
|
189
|
+
@econometric_tool('panel')
|
|
1277
190
|
async def panel_random_effects(
|
|
1278
191
|
ctx: Context[ServerSession, AppContext],
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
],
|
|
1293
|
-
x_data: Annotated[
|
|
1294
|
-
List[List[float]],
|
|
1295
|
-
Field(
|
|
1296
|
-
description="""自变量数据(解释变量),二维列表格式
|
|
1297
|
-
|
|
1298
|
-
示例格式(5个观测,2个自变量):
|
|
1299
|
-
[
|
|
1300
|
-
[5, 100], # 第1个观测的自变量值
|
|
1301
|
-
[6, 98], # 第2个观测的自变量值
|
|
1302
|
-
[7.5, 95], # 第3个观测的自变量值
|
|
1303
|
-
[6.5, 97], # 第4个观测的自变量值
|
|
1304
|
-
[9, 92] # 第5个观测的自变量值
|
|
1305
|
-
]
|
|
1306
|
-
|
|
1307
|
-
要求:
|
|
1308
|
-
- 外层列表:每个元素代表一个观测
|
|
1309
|
-
- 内层列表:该观测的所有自变量值
|
|
1310
|
-
- 所有观测的自变量数量必须相同
|
|
1311
|
-
- 观测数量必须与y_data长度一致"""
|
|
1312
|
-
)
|
|
1313
|
-
],
|
|
1314
|
-
entity_ids: Annotated[
|
|
1315
|
-
List[str],
|
|
1316
|
-
Field(
|
|
1317
|
-
description="""个体标识符列表
|
|
1318
|
-
|
|
1319
|
-
示例:["公司A", "公司A", "公司A", "公司B", "公司B", "公司B"]
|
|
1320
|
-
|
|
1321
|
-
要求:
|
|
1322
|
-
- 长度必须与观测数量一致
|
|
1323
|
-
- 建议使用有意义的标识符
|
|
1324
|
-
- 每个个体应有多个时间观测"""
|
|
1325
|
-
)
|
|
1326
|
-
],
|
|
1327
|
-
time_periods: Annotated[
|
|
1328
|
-
List[str],
|
|
1329
|
-
Field(
|
|
1330
|
-
description="""时间标识符列表
|
|
1331
|
-
|
|
1332
|
-
示例:["2020Q1", "2020Q2", "2020Q3", "2020Q1", "2020Q2", "2020Q3"]
|
|
1333
|
-
|
|
1334
|
-
要求:
|
|
1335
|
-
- 长度必须与观测数量一致
|
|
1336
|
-
- 建议使用标准时间格式
|
|
1337
|
-
- 每个时间点可以有多个个体观测"""
|
|
1338
|
-
)
|
|
1339
|
-
],
|
|
1340
|
-
feature_names: Annotated[
|
|
1341
|
-
Optional[List[str]],
|
|
1342
|
-
Field(
|
|
1343
|
-
default=None,
|
|
1344
|
-
description="""自变量名称列表(可选)
|
|
1345
|
-
|
|
1346
|
-
示例:["广告支出", "价格"]
|
|
1347
|
-
|
|
1348
|
-
说明:
|
|
1349
|
-
- 如果不提供,将自动命名为 x1, x2, x3...
|
|
1350
|
-
- 名称数量必须与自变量数量一致
|
|
1351
|
-
- 建议使用有意义的名称以便解释结果"""
|
|
1352
|
-
)
|
|
1353
|
-
] = None,
|
|
1354
|
-
entity_effects: Annotated[
|
|
1355
|
-
bool,
|
|
1356
|
-
Field(
|
|
1357
|
-
default=True,
|
|
1358
|
-
description="""是否包含个体效应
|
|
1359
|
-
|
|
1360
|
-
说明:
|
|
1361
|
-
- True:包含个体随机效应(默认)
|
|
1362
|
-
- False:不包含个体随机效应
|
|
1363
|
-
- 通常建议包含个体效应以控制个体间差异"""
|
|
1364
|
-
)
|
|
1365
|
-
] = True,
|
|
1366
|
-
time_effects: Annotated[
|
|
1367
|
-
bool,
|
|
1368
|
-
Field(
|
|
1369
|
-
default=False,
|
|
1370
|
-
description="""是否包含时间效应
|
|
1371
|
-
|
|
1372
|
-
说明:
|
|
1373
|
-
- True:包含时间随机效应
|
|
1374
|
-
- False:不包含时间随机效应(默认)
|
|
1375
|
-
- 如果存在时间趋势,建议包含时间效应"""
|
|
1376
|
-
)
|
|
1377
|
-
] = False
|
|
192
|
+
file_path: Annotated[Optional[str], Field(
|
|
193
|
+
default=None,
|
|
194
|
+
description="CSV文件路径。CSV格式要求:必须包含实体ID列(列名含entity_id/id/entity/firm/company/country/region之一)和时间列(列名含time_period/time/date/year/month/period/quarter之一)"
|
|
195
|
+
)] = None,
|
|
196
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
197
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
198
|
+
y_data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
199
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None)] = None,
|
|
200
|
+
entity_ids: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
201
|
+
time_periods: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
202
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
203
|
+
entity_effects: Annotated[bool, Field(default=True)] = True,
|
|
204
|
+
time_effects: Annotated[bool, Field(default=False)] = False
|
|
1378
205
|
) -> CallToolResult:
|
|
1379
|
-
"""
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
随机效应模型假设个体间差异是随机的,通过GLS估计同时利用组内和组间变异。
|
|
1383
|
-
适用于个体特征与解释变量不相关的情况。
|
|
1384
|
-
|
|
1385
|
-
📈 模型形式:
|
|
1386
|
-
y_it = α + βX_it + μ_i + ε_it
|
|
1387
|
-
|
|
1388
|
-
💡 使用场景:
|
|
1389
|
-
- 个体特征与解释变量不相关
|
|
1390
|
-
- 希望估计不随时间变化的变量的系数
|
|
1391
|
-
- 样本来自更大的总体
|
|
1392
|
-
|
|
1393
|
-
⚠️ 注意事项:
|
|
1394
|
-
- 需要满足个体效应与解释变量不相关的假设
|
|
1395
|
-
- 如果假设不成立,估计可能不一致
|
|
1396
|
-
- 比固定效应模型更有效率
|
|
1397
|
-
|
|
1398
|
-
Args:
|
|
1399
|
-
y_data: 因变量数据
|
|
1400
|
-
x_data: 自变量数据
|
|
1401
|
-
entity_ids: 个体标识符
|
|
1402
|
-
time_periods: 时间标识符
|
|
1403
|
-
feature_names: 自变量名称
|
|
1404
|
-
entity_effects: 是否包含个体效应
|
|
1405
|
-
time_effects: 是否包含时间效应
|
|
1406
|
-
ctx: MCP上下文对象
|
|
1407
|
-
"""
|
|
1408
|
-
await ctx.info(f"开始随机效应模型分析,样本大小: {len(y_data)},个体数量: {len(set(entity_ids))}")
|
|
1409
|
-
|
|
1410
|
-
try:
|
|
1411
|
-
# 数据验证
|
|
1412
|
-
if not y_data:
|
|
1413
|
-
raise ValueError("因变量数据不能为空")
|
|
1414
|
-
if not x_data:
|
|
1415
|
-
raise ValueError("自变量数据不能为空")
|
|
1416
|
-
if len(y_data) != len(x_data):
|
|
1417
|
-
raise ValueError(f"因变量和自变量的观测数量不一致: y_data={len(y_data)}, x_data={len(x_data)}")
|
|
1418
|
-
if len(y_data) != len(entity_ids):
|
|
1419
|
-
raise ValueError(f"因变量和个体标识符数量不一致: y_data={len(y_data)}, entity_ids={len(entity_ids)}")
|
|
1420
|
-
if len(y_data) != len(time_periods):
|
|
1421
|
-
raise ValueError(f"因变量和时间标识符数量不一致: y_data={len(y_data)}, time_periods={len(time_periods)}")
|
|
1422
|
-
|
|
1423
|
-
# 执行随机效应模型分析
|
|
1424
|
-
result = random_effects_model(
|
|
1425
|
-
y_data, x_data, entity_ids, time_periods, feature_names,
|
|
1426
|
-
entity_effects, time_effects
|
|
1427
|
-
)
|
|
1428
|
-
|
|
1429
|
-
await ctx.info("随机效应模型分析完成")
|
|
1430
|
-
|
|
1431
|
-
return CallToolResult(
|
|
1432
|
-
content=[
|
|
1433
|
-
TextContent(
|
|
1434
|
-
type="text",
|
|
1435
|
-
text=f"随机效应模型分析结果:\n"
|
|
1436
|
-
f"R² = {result.rsquared:.4f}\n"
|
|
1437
|
-
f"调整R² = {result.rsquared_adj:.4f}\n"
|
|
1438
|
-
f"F统计量 = {result.f_statistic:.4f} (p = {result.f_pvalue:.4f})\n"
|
|
1439
|
-
f"AIC = {result.aic:.2f}, BIC = {result.bic:.2f}\n"
|
|
1440
|
-
f"组间R² = {result.between_rsquared:.4f}\n"
|
|
1441
|
-
f"观测数量 = {result.n_obs}\n"
|
|
1442
|
-
f"个体效应: {'是' if result.entity_effects else '否'}, "
|
|
1443
|
-
f"时间效应: {'是' if result.time_effects else '否'}"
|
|
1444
|
-
)
|
|
1445
|
-
],
|
|
1446
|
-
structuredContent=result.model_dump()
|
|
1447
|
-
)
|
|
1448
|
-
|
|
1449
|
-
except Exception as e:
|
|
1450
|
-
await ctx.error(f"随机效应模型分析出错: {str(e)}")
|
|
1451
|
-
return CallToolResult(
|
|
1452
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
1453
|
-
isError=True
|
|
1454
|
-
)
|
|
206
|
+
"""随机效应模型 - 支持文件输入"""
|
|
207
|
+
return await handle_panel_random_effects(ctx, y_data, x_data, entity_ids, time_periods,
|
|
208
|
+
feature_names, entity_effects, time_effects)
|
|
1455
209
|
|
|
1456
210
|
|
|
1457
211
|
@mcp.tool()
|
|
212
|
+
@econometric_tool('panel')
|
|
1458
213
|
async def panel_hausman_test(
|
|
1459
214
|
ctx: Context[ServerSession, AppContext],
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
- 建议样本量 >= 30"""
|
|
1472
|
-
)
|
|
1473
|
-
],
|
|
1474
|
-
x_data: Annotated[
|
|
1475
|
-
List[List[float]],
|
|
1476
|
-
Field(
|
|
1477
|
-
description="""自变量数据(解释变量),二维列表格式
|
|
1478
|
-
|
|
1479
|
-
示例格式(5个观测,2个自变量):
|
|
1480
|
-
[
|
|
1481
|
-
[5, 100], # 第1个观测的自变量值
|
|
1482
|
-
[6, 98], # 第2个观测的自变量值
|
|
1483
|
-
[7.5, 95], # 第3个观测的自变量值
|
|
1484
|
-
[6.5, 97], # 第4个观测的自变量值
|
|
1485
|
-
[9, 92] # 第5个观测的自变量值
|
|
1486
|
-
]
|
|
1487
|
-
|
|
1488
|
-
要求:
|
|
1489
|
-
- 外层列表:每个元素代表一个观测
|
|
1490
|
-
- 内层列表:该观测的所有自变量值
|
|
1491
|
-
- 所有观测的自变量数量必须相同
|
|
1492
|
-
- 观测数量必须与y_data长度一致"""
|
|
1493
|
-
)
|
|
1494
|
-
],
|
|
1495
|
-
entity_ids: Annotated[
|
|
1496
|
-
List[str],
|
|
1497
|
-
Field(
|
|
1498
|
-
description="""个体标识符列表
|
|
1499
|
-
|
|
1500
|
-
示例:["公司A", "公司A", "公司A", "公司B", "公司B", "公司B"]
|
|
1501
|
-
|
|
1502
|
-
要求:
|
|
1503
|
-
- 长度必须与观测数量一致
|
|
1504
|
-
- 建议使用有意义的标识符
|
|
1505
|
-
- 每个个体应有多个时间观测"""
|
|
1506
|
-
)
|
|
1507
|
-
],
|
|
1508
|
-
time_periods: Annotated[
|
|
1509
|
-
List[str],
|
|
1510
|
-
Field(
|
|
1511
|
-
description="""时间标识符列表
|
|
1512
|
-
|
|
1513
|
-
示例:["2020Q1", "2020Q2", "2020Q3", "2020Q1", "2020Q2", "2020Q3"]
|
|
1514
|
-
|
|
1515
|
-
要求:
|
|
1516
|
-
- 长度必须与观测数量一致
|
|
1517
|
-
- 建议使用标准时间格式
|
|
1518
|
-
- 每个时间点可以有多个个体观测"""
|
|
1519
|
-
)
|
|
1520
|
-
],
|
|
1521
|
-
feature_names: Annotated[
|
|
1522
|
-
Optional[List[str]],
|
|
1523
|
-
Field(
|
|
1524
|
-
default=None,
|
|
1525
|
-
description="""自变量名称列表(可选)
|
|
1526
|
-
|
|
1527
|
-
示例:["广告支出", "价格"]
|
|
1528
|
-
|
|
1529
|
-
说明:
|
|
1530
|
-
- 如果不提供,将自动命名为 x1, x2, x3...
|
|
1531
|
-
- 名称数量必须与自变量数量一致
|
|
1532
|
-
- 建议使用有意义的名称以便解释结果"""
|
|
1533
|
-
)
|
|
1534
|
-
] = None
|
|
215
|
+
file_path: Annotated[Optional[str], Field(
|
|
216
|
+
default=None,
|
|
217
|
+
description="CSV文件路径。CSV格式要求:必须包含实体ID列(列名含entity_id/id/entity/firm/company/country/region之一)和时间列(列名含time_period/time/date/year/month/period/quarter之一)"
|
|
218
|
+
)] = None,
|
|
219
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
220
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
221
|
+
y_data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
222
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None)] = None,
|
|
223
|
+
entity_ids: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
224
|
+
time_periods: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
225
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None)] = None
|
|
1535
226
|
) -> CallToolResult:
|
|
1536
|
-
"""Hausman检验
|
|
1537
|
-
|
|
1538
|
-
📊 功能说明:
|
|
1539
|
-
Hausman检验用于比较固定效应模型和随机效应模型,判断个体效应是否与解释变量相关。
|
|
1540
|
-
原假设:随机效应模型是一致的(个体效应与解释变量不相关)
|
|
1541
|
-
备择假设:固定效应模型是一致的
|
|
1542
|
-
|
|
1543
|
-
💡 使用场景:
|
|
1544
|
-
- 在固定效应和随机效应模型之间选择
|
|
1545
|
-
- 检验个体效应是否与解释变量相关
|
|
1546
|
-
- 验证随机效应模型的假设
|
|
1547
|
-
|
|
1548
|
-
⚠️ 注意事项:
|
|
1549
|
-
- p值 < 0.05:拒绝原假设,选择固定效应模型
|
|
1550
|
-
- p值 >= 0.05:不能拒绝原假设,选择随机效应模型
|
|
1551
|
-
- 检验统计量服从卡方分布
|
|
1552
|
-
|
|
1553
|
-
Args:
|
|
1554
|
-
y_data: 因变量数据
|
|
1555
|
-
x_data: 自变量数据
|
|
1556
|
-
entity_ids: 个体标识符
|
|
1557
|
-
time_periods: 时间标识符
|
|
1558
|
-
feature_names: 自变量名称
|
|
1559
|
-
ctx: MCP上下文对象
|
|
1560
|
-
"""
|
|
1561
|
-
await ctx.info(f"开始Hausman检验,样本大小: {len(y_data)},个体数量: {len(set(entity_ids))}")
|
|
1562
|
-
|
|
1563
|
-
try:
|
|
1564
|
-
# 数据验证
|
|
1565
|
-
if not y_data:
|
|
1566
|
-
raise ValueError("因变量数据不能为空")
|
|
1567
|
-
if not x_data:
|
|
1568
|
-
raise ValueError("自变量数据不能为空")
|
|
1569
|
-
if len(y_data) != len(x_data):
|
|
1570
|
-
raise ValueError(f"因变量和自变量的观测数量不一致: y_data={len(y_data)}, x_data={len(x_data)}")
|
|
1571
|
-
if len(y_data) != len(entity_ids):
|
|
1572
|
-
raise ValueError(f"因变量和个体标识符数量不一致: y_data={len(y_data)}, entity_ids={len(entity_ids)}")
|
|
1573
|
-
if len(y_data) != len(time_periods):
|
|
1574
|
-
raise ValueError(f"因变量和时间标识符数量不一致: y_data={len(y_data)}, time_periods={len(time_periods)}")
|
|
1575
|
-
|
|
1576
|
-
# 执行Hausman检验
|
|
1577
|
-
result = hausman_test(y_data, x_data, entity_ids, time_periods, feature_names)
|
|
1578
|
-
|
|
1579
|
-
await ctx.info("Hausman检验完成")
|
|
1580
|
-
|
|
1581
|
-
return CallToolResult(
|
|
1582
|
-
content=[
|
|
1583
|
-
TextContent(
|
|
1584
|
-
type="text",
|
|
1585
|
-
text=f"Hausman检验结果:\n"
|
|
1586
|
-
f"检验统计量 = {result.statistic:.4f}\n"
|
|
1587
|
-
f"p值 = {result.p_value:.4f}\n"
|
|
1588
|
-
f"{'显著' if result.significant else '不显著'} (5%水平)\n"
|
|
1589
|
-
f"建议:{result.recommendation}"
|
|
1590
|
-
)
|
|
1591
|
-
],
|
|
1592
|
-
structuredContent=result.model_dump()
|
|
1593
|
-
)
|
|
1594
|
-
|
|
1595
|
-
except Exception as e:
|
|
1596
|
-
await ctx.error(f"Hausman检验出错: {str(e)}")
|
|
1597
|
-
return CallToolResult(
|
|
1598
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
1599
|
-
isError=True
|
|
1600
|
-
)
|
|
227
|
+
"""Hausman检验 - 支持文件输入"""
|
|
228
|
+
return await handle_panel_hausman_test(ctx, y_data, x_data, entity_ids, time_periods, feature_names)
|
|
1601
229
|
|
|
1602
230
|
|
|
1603
231
|
@mcp.tool()
|
|
232
|
+
@econometric_tool('panel') # 保持panel类型以获取entity_ids和time_periods
|
|
1604
233
|
async def panel_unit_root_test(
|
|
1605
234
|
ctx: Context[ServerSession, AppContext],
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
],
|
|
1620
|
-
entity_ids: Annotated[
|
|
1621
|
-
List[str],
|
|
1622
|
-
Field(
|
|
1623
|
-
description="""个体标识符列表
|
|
1624
|
-
|
|
1625
|
-
示例:["公司A", "公司A", "公司A", "公司B", "公司B", "公司B"]
|
|
1626
|
-
|
|
1627
|
-
要求:
|
|
1628
|
-
- 长度必须与数据序列长度一致
|
|
1629
|
-
- 建议使用有意义的标识符
|
|
1630
|
-
- 每个个体应有多个时间观测"""
|
|
1631
|
-
)
|
|
1632
|
-
],
|
|
1633
|
-
time_periods: Annotated[
|
|
1634
|
-
List[str],
|
|
1635
|
-
Field(
|
|
1636
|
-
description="""时间标识符列表
|
|
1637
|
-
|
|
1638
|
-
示例:["2020Q1", "2020Q2", "2020Q3", "2020Q1", "2020Q2", "2020Q3"]
|
|
1639
|
-
|
|
1640
|
-
要求:
|
|
1641
|
-
- 长度必须与数据序列长度一致
|
|
1642
|
-
- 建议使用标准时间格式
|
|
1643
|
-
- 每个时间点可以有多个个体观测"""
|
|
1644
|
-
)
|
|
1645
|
-
],
|
|
1646
|
-
test_type: Annotated[
|
|
1647
|
-
str,
|
|
1648
|
-
Field(
|
|
1649
|
-
default="levinlin",
|
|
1650
|
-
description="""面板单位根检验类型
|
|
1651
|
-
|
|
1652
|
-
可选值:
|
|
1653
|
-
- "levinlin": Levin-Lin-Chu检验(默认)
|
|
1654
|
-
* 假设所有个体有相同的自回归系数
|
|
1655
|
-
* 适用于平衡面板数据
|
|
1656
|
-
|
|
1657
|
-
- "ips": Im-Pesaran-Shin检验
|
|
1658
|
-
* 允许个体间有不同的自回归系数
|
|
1659
|
-
* 适用于非平衡面板数据
|
|
1660
|
-
|
|
1661
|
-
- "fisher": Fisher组合检验
|
|
1662
|
-
* 基于个体ADF检验的组合
|
|
1663
|
-
* 适用于各种面板数据类型
|
|
1664
|
-
|
|
1665
|
-
选择建议:
|
|
1666
|
-
- 平衡面板 + 同质系数 → levinlin
|
|
1667
|
-
- 非平衡面板 + 异质系数 → ips
|
|
1668
|
-
- 小样本或复杂情况 → fisher"""
|
|
1669
|
-
)
|
|
1670
|
-
] = "levinlin"
|
|
235
|
+
file_path: Annotated[Optional[str], Field(
|
|
236
|
+
default=None,
|
|
237
|
+
description="CSV文件路径。CSV格式要求:必须包含实体ID列(列名含entity_id/id/entity/firm/company/country/region之一)和时间列(列名含time_period/time/date/year/month/period/quarter之一)。数据量要求:至少3个实体,每个实体至少5个时间点"
|
|
238
|
+
)] = None,
|
|
239
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
240
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
241
|
+
data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
242
|
+
y_data: Annotated[Optional[List[float]], Field(default=None)] = None, # 从panel转换来的
|
|
243
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None)] = None, # 从panel转换来的,忽略
|
|
244
|
+
entity_ids: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
245
|
+
time_periods: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
246
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None)] = None, # 从panel转换来的,忽略
|
|
247
|
+
test_type: Annotated[str, Field(default="levinlin")] = "levinlin"
|
|
1671
248
|
) -> CallToolResult:
|
|
1672
|
-
"""面板单位根检验
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
Args:
|
|
1689
|
-
data: 面板数据序列
|
|
1690
|
-
entity_ids: 个体标识符
|
|
1691
|
-
time_periods: 时间标识符
|
|
1692
|
-
test_type: 检验类型
|
|
1693
|
-
ctx: MCP上下文对象
|
|
1694
|
-
"""
|
|
1695
|
-
await ctx.info(f"开始面板单位根检验: {test_type},样本大小: {len(data)},个体数量: {len(set(entity_ids))}")
|
|
1696
|
-
|
|
1697
|
-
try:
|
|
1698
|
-
# 数据验证
|
|
1699
|
-
if not data:
|
|
1700
|
-
raise ValueError("面板数据不能为空")
|
|
1701
|
-
if len(data) != len(entity_ids):
|
|
1702
|
-
raise ValueError(f"数据和个体标识符数量不一致: data={len(data)}, entity_ids={len(entity_ids)}")
|
|
1703
|
-
if len(data) != len(time_periods):
|
|
1704
|
-
raise ValueError(f"数据和时间标识符数量不一致: data={len(data)}, time_periods={len(time_periods)}")
|
|
1705
|
-
|
|
1706
|
-
# 执行面板单位根检验
|
|
1707
|
-
result = panel_unit_root_test(data, entity_ids, time_periods, test_type)
|
|
1708
|
-
|
|
1709
|
-
await ctx.info("面板单位根检验完成")
|
|
1710
|
-
|
|
1711
|
-
return CallToolResult(
|
|
1712
|
-
content=[
|
|
1713
|
-
TextContent(
|
|
1714
|
-
type="text",
|
|
1715
|
-
text=f"面板单位根检验结果 ({result.test_type}):\n"
|
|
1716
|
-
f"检验统计量 = {result.statistic:.4f}\n"
|
|
1717
|
-
f"p值 = {result.p_value:.4f}\n"
|
|
1718
|
-
f"{'平稳' if result.stationary else '非平稳'}序列\n"
|
|
1719
|
-
f"建议:{'可直接建模' if result.stationary else '需要差分处理'}"
|
|
1720
|
-
)
|
|
1721
|
-
],
|
|
1722
|
-
structuredContent=result.model_dump()
|
|
1723
|
-
)
|
|
1724
|
-
|
|
1725
|
-
except Exception as e:
|
|
1726
|
-
await ctx.error(f"面板单位根检验出错: {str(e)}")
|
|
1727
|
-
return CallToolResult(
|
|
1728
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
1729
|
-
isError=True
|
|
1730
|
-
)
|
|
249
|
+
"""面板单位根检验 - 支持文件输入"""
|
|
250
|
+
# 传递所有参数给handler
|
|
251
|
+
return await handle_panel_unit_root_test(
|
|
252
|
+
ctx,
|
|
253
|
+
data=data,
|
|
254
|
+
y_data=y_data,
|
|
255
|
+
entity_ids=entity_ids,
|
|
256
|
+
time_periods=time_periods,
|
|
257
|
+
test_type=test_type
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
# ============================================================================
|
|
262
|
+
# 高级时间序列工具 (5个) - 自动支持文件输入
|
|
263
|
+
# ============================================================================
|
|
1731
264
|
|
|
1732
265
|
@mcp.tool()
|
|
266
|
+
@econometric_tool('time_series')
|
|
1733
267
|
async def var_model_analysis(
|
|
1734
268
|
ctx: Context[ServerSession, AppContext],
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
{
|
|
1742
|
-
"GDP增长率": [3.2, 2.8, 3.5, 2.9, 3.1, 2.7, 3.3, 3.0],
|
|
1743
|
-
"通货膨胀率": [2.1, 2.3, 1.9, 2.4, 2.2, 2.5, 2.0, 2.3],
|
|
1744
|
-
"失业率": [4.5, 4.2, 4.0, 4.3, 4.1, 4.4, 3.9, 4.2]
|
|
1745
|
-
}
|
|
1746
|
-
|
|
1747
|
-
要求:
|
|
1748
|
-
- 至少包含2个变量
|
|
1749
|
-
- 所有变量的数据点数量必须相同
|
|
1750
|
-
- 建议样本量 >= 30
|
|
1751
|
-
- 数据应平稳或经过差分处理"""
|
|
1752
|
-
)
|
|
1753
|
-
],
|
|
1754
|
-
max_lags: Annotated[
|
|
1755
|
-
int,
|
|
1756
|
-
Field(
|
|
1757
|
-
default=5,
|
|
1758
|
-
description="""最大滞后阶数
|
|
1759
|
-
|
|
1760
|
-
说明:
|
|
1761
|
-
- 用于自动选择最优滞后阶数
|
|
1762
|
-
- 建议值:3-8
|
|
1763
|
-
- 样本量越大,可选择的滞后阶数越多"""
|
|
1764
|
-
)
|
|
1765
|
-
] = 5,
|
|
1766
|
-
ic: Annotated[
|
|
1767
|
-
str,
|
|
1768
|
-
Field(
|
|
1769
|
-
default="aic",
|
|
1770
|
-
description="""信息准则
|
|
1771
|
-
|
|
1772
|
-
可选值:
|
|
1773
|
-
- "aic": Akaike信息准则(默认)
|
|
1774
|
-
- "bic": Bayesian信息准则
|
|
1775
|
-
- "hqic": Hannan-Quinn信息准则
|
|
1776
|
-
|
|
1777
|
-
选择建议:
|
|
1778
|
-
- 小样本 → AIC
|
|
1779
|
-
- 大样本 → BIC
|
|
1780
|
-
- 中等样本 → HQIC"""
|
|
1781
|
-
)
|
|
1782
|
-
] = "aic"
|
|
269
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
270
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
271
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
272
|
+
data: Annotated[Optional[Dict[str, List[float]]], Field(default=None)] = None,
|
|
273
|
+
max_lags: Annotated[int, Field(default=5)] = 5,
|
|
274
|
+
ic: Annotated[str, Field(default="aic")] = "aic"
|
|
1783
275
|
) -> CallToolResult:
|
|
1784
|
-
"""VAR模型分析
|
|
1785
|
-
|
|
1786
|
-
📊 功能说明:
|
|
1787
|
-
向量自回归模型用于分析多个时间序列变量之间的动态关系。
|
|
1788
|
-
每个变量的当前值都依赖于所有变量的滞后值。
|
|
1789
|
-
|
|
1790
|
-
📈 模型形式:
|
|
1791
|
-
Y_t = A_1 Y_{t-1} + A_2 Y_{t-2} + ... + A_p Y_{t-p} + ε_t
|
|
1792
|
-
|
|
1793
|
-
💡 使用场景:
|
|
1794
|
-
- 宏观经济变量间的相互影响分析
|
|
1795
|
-
- 金融市场联动性研究
|
|
1796
|
-
- 脉冲响应函数和方差分解
|
|
1797
|
-
- 格兰杰因果关系检验
|
|
1798
|
-
|
|
1799
|
-
⚠️ 注意事项:
|
|
1800
|
-
- 所有变量都应该是平稳的
|
|
1801
|
-
- 滞后阶数选择很重要
|
|
1802
|
-
- 变量数量不宜过多(避免维度灾难)
|
|
1803
|
-
- 样本量应足够大
|
|
1804
|
-
|
|
1805
|
-
Args:
|
|
1806
|
-
data: 多变量时间序列数据
|
|
1807
|
-
max_lags: 最大滞后阶数
|
|
1808
|
-
ic: 信息准则
|
|
1809
|
-
ctx: MCP上下文对象
|
|
1810
|
-
"""
|
|
1811
|
-
await ctx.info(f"开始VAR模型分析,变量数量: {len(data)},最大滞后阶数: {max_lags}")
|
|
1812
|
-
|
|
1813
|
-
try:
|
|
1814
|
-
# 数据验证
|
|
1815
|
-
if not data:
|
|
1816
|
-
raise ValueError("数据不能为空")
|
|
1817
|
-
if len(data) < 2:
|
|
1818
|
-
raise ValueError("VAR模型至少需要2个变量")
|
|
1819
|
-
|
|
1820
|
-
# 执行VAR模型分析
|
|
1821
|
-
result = var_model(data, max_lags=max_lags, ic=ic)
|
|
1822
|
-
|
|
1823
|
-
await ctx.info("VAR模型分析完成")
|
|
1824
|
-
|
|
1825
|
-
return CallToolResult(
|
|
1826
|
-
content=[
|
|
1827
|
-
TextContent(
|
|
1828
|
-
type="text",
|
|
1829
|
-
text=f"VAR模型分析结果:\n"
|
|
1830
|
-
f"最优滞后阶数: {result.order}\n"
|
|
1831
|
-
f"AIC = {result.aic:.2f}, BIC = {result.bic:.2f}, HQIC = {result.hqic:.2f}\n"
|
|
1832
|
-
f"变量数量: {len(data)}\n"
|
|
1833
|
-
f"格兰杰因果关系检验完成"
|
|
1834
|
-
)
|
|
1835
|
-
],
|
|
1836
|
-
structuredContent=result.model_dump()
|
|
1837
|
-
)
|
|
1838
|
-
|
|
1839
|
-
except Exception as e:
|
|
1840
|
-
await ctx.error(f"VAR模型分析出错: {str(e)}")
|
|
1841
|
-
return CallToolResult(
|
|
1842
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
1843
|
-
isError=True
|
|
1844
|
-
)
|
|
276
|
+
"""VAR模型分析 - 支持文件输入"""
|
|
277
|
+
return await handle_var_model(ctx, data, max_lags, ic)
|
|
1845
278
|
|
|
1846
279
|
|
|
1847
280
|
@mcp.tool()
|
|
281
|
+
@econometric_tool('time_series')
|
|
1848
282
|
async def vecm_model_analysis(
|
|
1849
283
|
ctx: Context[ServerSession, AppContext],
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
"GDP": [100, 102, 105, 103, 108, 110, 109, 112],
|
|
1858
|
-
"消费": [80, 82, 85, 83, 88, 90, 89, 92],
|
|
1859
|
-
"投资": [20, 21, 22, 21, 23, 24, 23, 25]
|
|
1860
|
-
}
|
|
1861
|
-
|
|
1862
|
-
要求:
|
|
1863
|
-
- 至少包含2个变量
|
|
1864
|
-
- 所有变量的数据点数量必须相同
|
|
1865
|
-
- 建议样本量 >= 50
|
|
1866
|
-
- 变量应为一阶单整I(1)"""
|
|
1867
|
-
)
|
|
1868
|
-
],
|
|
1869
|
-
coint_rank: Annotated[
|
|
1870
|
-
int,
|
|
1871
|
-
Field(
|
|
1872
|
-
default=1,
|
|
1873
|
-
description="""协整秩
|
|
1874
|
-
|
|
1875
|
-
说明:
|
|
1876
|
-
- 协整向量的数量
|
|
1877
|
-
- 通常为变量数量-1
|
|
1878
|
-
- 需要根据协整检验确定"""
|
|
1879
|
-
)
|
|
1880
|
-
] = 1,
|
|
1881
|
-
deterministic: Annotated[
|
|
1882
|
-
str,
|
|
1883
|
-
Field(
|
|
1884
|
-
default="co",
|
|
1885
|
-
description="""确定性项
|
|
1886
|
-
|
|
1887
|
-
可选值:
|
|
1888
|
-
- "co": 常数项(默认)
|
|
1889
|
-
- "ci": 常数项和趋势项
|
|
1890
|
-
- "lo": 线性趋势
|
|
1891
|
-
- "li": 线性趋势和二次趋势"""
|
|
1892
|
-
)
|
|
1893
|
-
] = "co",
|
|
1894
|
-
max_lags: Annotated[
|
|
1895
|
-
int,
|
|
1896
|
-
Field(
|
|
1897
|
-
default=5,
|
|
1898
|
-
description="""最大滞后阶数
|
|
1899
|
-
|
|
1900
|
-
说明:
|
|
1901
|
-
- 用于误差修正模型
|
|
1902
|
-
- 建议值:2-6
|
|
1903
|
-
- 根据样本量调整"""
|
|
1904
|
-
)
|
|
1905
|
-
] = 5
|
|
284
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
285
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
286
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
287
|
+
data: Annotated[Optional[Dict[str, List[float]]], Field(default=None)] = None,
|
|
288
|
+
coint_rank: Annotated[int, Field(default=1)] = 1,
|
|
289
|
+
deterministic: Annotated[str, Field(default="co")] = "co",
|
|
290
|
+
max_lags: Annotated[int, Field(default=5)] = 5
|
|
1906
291
|
) -> CallToolResult:
|
|
1907
|
-
"""VECM模型分析
|
|
1908
|
-
|
|
1909
|
-
📊 功能说明:
|
|
1910
|
-
用于分析非平稳时间序列之间的长期均衡关系和短期动态调整。
|
|
1911
|
-
适用于存在协整关系的多变量系统。
|
|
1912
|
-
|
|
1913
|
-
📈 模型形式:
|
|
1914
|
-
ΔY_t = αβ' Y_{t-1} + Γ_1 ΔY_{t-1} + ... + Γ_{p-1} ΔY_{t-p+1} + ε_t
|
|
1915
|
-
|
|
1916
|
-
💡 使用场景:
|
|
1917
|
-
- 存在长期均衡关系的经济变量分析
|
|
1918
|
-
- 误差修正机制研究
|
|
1919
|
-
- 协整关系检验
|
|
1920
|
-
- 短期动态调整分析
|
|
1921
|
-
|
|
1922
|
-
⚠️ 注意事项:
|
|
1923
|
-
- 所有变量应该是一阶单整的I(1)
|
|
1924
|
-
- 协整秩的选择很重要
|
|
1925
|
-
- 需要较大的样本量
|
|
1926
|
-
- 对模型设定敏感
|
|
1927
|
-
|
|
1928
|
-
Args:
|
|
1929
|
-
data: 多变量时间序列数据
|
|
1930
|
-
coint_rank: 协整秩
|
|
1931
|
-
deterministic: 确定性项
|
|
1932
|
-
max_lags: 最大滞后阶数
|
|
1933
|
-
ctx: MCP上下文对象
|
|
1934
|
-
"""
|
|
1935
|
-
await ctx.info(f"开始VECM模型分析,变量数量: {len(data)},协整秩: {coint_rank}")
|
|
1936
|
-
|
|
1937
|
-
try:
|
|
1938
|
-
# 数据验证
|
|
1939
|
-
if not data:
|
|
1940
|
-
raise ValueError("数据不能为空")
|
|
1941
|
-
if len(data) < 2:
|
|
1942
|
-
raise ValueError("VECM模型至少需要2个变量")
|
|
1943
|
-
|
|
1944
|
-
# 执行VECM模型分析
|
|
1945
|
-
result = vecm_model(data, coint_rank=coint_rank, deterministic=deterministic, max_lags=max_lags)
|
|
1946
|
-
|
|
1947
|
-
await ctx.info("VECM模型分析完成")
|
|
1948
|
-
|
|
1949
|
-
return CallToolResult(
|
|
1950
|
-
content=[
|
|
1951
|
-
TextContent(
|
|
1952
|
-
type="text",
|
|
1953
|
-
text=f"VECM模型分析结果:\n"
|
|
1954
|
-
f"协整秩: {result.coint_rank}\n"
|
|
1955
|
-
f"AIC = {result.aic:.2f}, BIC = {result.bic:.2f}, HQIC = {result.hqic:.2f}\n"
|
|
1956
|
-
f"协整关系数量: {len(result.cointegration_relations)}\n"
|
|
1957
|
-
f"调整速度计算完成"
|
|
1958
|
-
)
|
|
1959
|
-
],
|
|
1960
|
-
structuredContent=result.model_dump()
|
|
1961
|
-
)
|
|
1962
|
-
|
|
1963
|
-
except Exception as e:
|
|
1964
|
-
await ctx.error(f"VECM模型分析出错: {str(e)}")
|
|
1965
|
-
return CallToolResult(
|
|
1966
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
1967
|
-
isError=True
|
|
1968
|
-
)
|
|
292
|
+
"""VECM模型分析 - 支持文件输入"""
|
|
293
|
+
return await handle_vecm_model(ctx, data, coint_rank, deterministic, max_lags)
|
|
1969
294
|
|
|
1970
295
|
|
|
1971
296
|
@mcp.tool()
|
|
297
|
+
@econometric_tool('single_var')
|
|
1972
298
|
async def garch_model_analysis(
|
|
1973
299
|
ctx: Context[ServerSession, AppContext],
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
要求:
|
|
1982
|
-
- 建议使用收益率数据
|
|
1983
|
-
- 不能包含缺失值
|
|
1984
|
-
- 建议样本量 >= 50
|
|
1985
|
-
- 数据应具有波动率聚类特征"""
|
|
1986
|
-
)
|
|
1987
|
-
],
|
|
1988
|
-
order: Annotated[
|
|
1989
|
-
Tuple[int, int],
|
|
1990
|
-
Field(
|
|
1991
|
-
default=(1, 1),
|
|
1992
|
-
description="""GARCH阶数
|
|
1993
|
-
|
|
1994
|
-
说明:
|
|
1995
|
-
- 第一个数:ARCH项阶数
|
|
1996
|
-
- 第二个数:GARCH项阶数
|
|
1997
|
-
- 常用阶数:(1,1)"""
|
|
1998
|
-
)
|
|
1999
|
-
] = (1, 1),
|
|
2000
|
-
dist: Annotated[
|
|
2001
|
-
str,
|
|
2002
|
-
Field(
|
|
2003
|
-
default="normal",
|
|
2004
|
-
description="""误差分布
|
|
2005
|
-
|
|
2006
|
-
可选值:
|
|
2007
|
-
- "normal": 正态分布(默认)
|
|
2008
|
-
- "t": t分布
|
|
2009
|
-
- "skewt": 偏t分布
|
|
2010
|
-
|
|
2011
|
-
选择建议:
|
|
2012
|
-
- 一般情况 → normal
|
|
2013
|
-
- 厚尾数据 → t
|
|
2014
|
-
- 非对称数据 → skewt"""
|
|
2015
|
-
)
|
|
2016
|
-
] = "normal"
|
|
300
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
301
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
302
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
303
|
+
data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
304
|
+
order: Annotated[tuple, Field(default=(1, 1))] = (1, 1),
|
|
305
|
+
dist: Annotated[str, Field(default="normal")] = "normal"
|
|
2017
306
|
) -> CallToolResult:
|
|
2018
|
-
"""GARCH模型分析
|
|
2019
|
-
|
|
2020
|
-
📊 功能说明:
|
|
2021
|
-
用于建模金融时间序列的波动率聚类现象,捕捉条件方差的时变特征。
|
|
2022
|
-
|
|
2023
|
-
📈 模型形式:
|
|
2024
|
-
r_t = μ + ε_t, ε_t = σ_t z_t
|
|
2025
|
-
σ_t² = ω + α ε_{t-1}² + β σ_{t-1}²
|
|
2026
|
-
|
|
2027
|
-
💡 使用场景:
|
|
2028
|
-
- 金融资产波动率建模
|
|
2029
|
-
- 风险管理和VaR计算
|
|
2030
|
-
- 期权定价
|
|
2031
|
-
- 波动率预测
|
|
2032
|
-
|
|
2033
|
-
⚠️ 注意事项:
|
|
2034
|
-
- 数据应具有波动率聚类特征
|
|
2035
|
-
- 需要较大的样本量
|
|
2036
|
-
- 对分布假设敏感
|
|
2037
|
-
- 高阶GARCH可能不稳定
|
|
2038
|
-
|
|
2039
|
-
Args:
|
|
2040
|
-
data: 时间序列数据
|
|
2041
|
-
order: GARCH阶数
|
|
2042
|
-
dist: 误差分布
|
|
2043
|
-
ctx: MCP上下文对象
|
|
2044
|
-
"""
|
|
2045
|
-
await ctx.info(f"开始GARCH模型分析,样本大小: {len(data)},阶数: {order}")
|
|
2046
|
-
|
|
2047
|
-
try:
|
|
2048
|
-
# 数据验证
|
|
2049
|
-
if not data:
|
|
2050
|
-
raise ValueError("数据不能为空")
|
|
2051
|
-
if len(data) < 50:
|
|
2052
|
-
raise ValueError("GARCH模型至少需要50个观测点")
|
|
2053
|
-
|
|
2054
|
-
# 执行GARCH模型分析
|
|
2055
|
-
result = garch_model(data, order=order, dist=dist)
|
|
2056
|
-
|
|
2057
|
-
await ctx.info("GARCH模型分析完成")
|
|
2058
|
-
|
|
2059
|
-
return CallToolResult(
|
|
2060
|
-
content=[
|
|
2061
|
-
TextContent(
|
|
2062
|
-
type="text",
|
|
2063
|
-
text=f"GARCH模型分析结果:\n"
|
|
2064
|
-
f"阶数: {result.order}\n"
|
|
2065
|
-
f"AIC = {result.aic:.2f}, BIC = {result.bic:.2f}\n"
|
|
2066
|
-
f"持久性: {result.persistence:.4f}\n"
|
|
2067
|
-
f"无条件方差: {result.unconditional_variance:.6f}"
|
|
2068
|
-
)
|
|
2069
|
-
],
|
|
2070
|
-
structuredContent=result.model_dump()
|
|
2071
|
-
)
|
|
2072
|
-
|
|
2073
|
-
except Exception as e:
|
|
2074
|
-
await ctx.error(f"GARCH模型分析出错: {str(e)}")
|
|
2075
|
-
return CallToolResult(
|
|
2076
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
2077
|
-
isError=True
|
|
2078
|
-
)
|
|
307
|
+
"""GARCH模型分析 - 支持文件输入"""
|
|
308
|
+
return await handle_garch_model(ctx, data, order, dist)
|
|
2079
309
|
|
|
2080
310
|
|
|
2081
311
|
@mcp.tool()
|
|
312
|
+
@econometric_tool('single_var')
|
|
2082
313
|
async def state_space_model_analysis(
|
|
2083
314
|
ctx: Context[ServerSession, AppContext],
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
- 建议样本量 >= 20
|
|
2094
|
-
- 数据应具有趋势或季节特征"""
|
|
2095
|
-
)
|
|
2096
|
-
],
|
|
2097
|
-
state_dim: Annotated[
|
|
2098
|
-
int,
|
|
2099
|
-
Field(
|
|
2100
|
-
default=1,
|
|
2101
|
-
description="""状态维度
|
|
2102
|
-
|
|
2103
|
-
说明:
|
|
2104
|
-
- 不可观测状态变量的维度
|
|
2105
|
-
- 通常为1-3
|
|
2106
|
-
- 根据模型复杂度选择"""
|
|
2107
|
-
)
|
|
2108
|
-
] = 1,
|
|
2109
|
-
observation_dim: Annotated[
|
|
2110
|
-
int,
|
|
2111
|
-
Field(
|
|
2112
|
-
default=1,
|
|
2113
|
-
description="""观测维度
|
|
2114
|
-
|
|
2115
|
-
说明:
|
|
2116
|
-
- 观测变量的维度
|
|
2117
|
-
- 通常为1
|
|
2118
|
-
- 多变量时为变量数量"""
|
|
2119
|
-
)
|
|
2120
|
-
] = 1,
|
|
2121
|
-
trend: Annotated[
|
|
2122
|
-
bool,
|
|
2123
|
-
Field(
|
|
2124
|
-
default=True,
|
|
2125
|
-
description="""是否包含趋势项
|
|
2126
|
-
|
|
2127
|
-
说明:
|
|
2128
|
-
- True:包含趋势项(默认)
|
|
2129
|
-
- False:不包含趋势项
|
|
2130
|
-
- 适用于有趋势的数据"""
|
|
2131
|
-
)
|
|
2132
|
-
] = True,
|
|
2133
|
-
seasonal: Annotated[
|
|
2134
|
-
bool,
|
|
2135
|
-
Field(
|
|
2136
|
-
default=False,
|
|
2137
|
-
description="""是否包含季节项
|
|
2138
|
-
|
|
2139
|
-
说明:
|
|
2140
|
-
- True:包含季节项
|
|
2141
|
-
- False:不包含季节项(默认)
|
|
2142
|
-
- 适用于有季节性的数据"""
|
|
2143
|
-
)
|
|
2144
|
-
] = False,
|
|
2145
|
-
period: Annotated[
|
|
2146
|
-
int,
|
|
2147
|
-
Field(
|
|
2148
|
-
default=12,
|
|
2149
|
-
description="""季节周期
|
|
2150
|
-
|
|
2151
|
-
说明:
|
|
2152
|
-
- 季节周期的长度
|
|
2153
|
-
- 月度数据:12
|
|
2154
|
-
- 季度数据:4
|
|
2155
|
-
- 日度数据:7"""
|
|
2156
|
-
)
|
|
2157
|
-
] = 12
|
|
2158
|
-
) -> CallToolResult:
|
|
2159
|
-
"""状态空间模型分析
|
|
2160
|
-
|
|
2161
|
-
📊 功能说明:
|
|
2162
|
-
使用状态空间表示和卡尔曼滤波进行时间序列建模,可以处理不可观测的状态变量。
|
|
2163
|
-
|
|
2164
|
-
📈 模型形式:
|
|
2165
|
-
状态方程: α_t = T α_{t-1} + R η_t
|
|
2166
|
-
观测方程: y_t = Z α_t + ε_t
|
|
2167
|
-
|
|
2168
|
-
💡 使用场景:
|
|
2169
|
-
- 不可观测状态变量的估计
|
|
2170
|
-
- 结构时间序列建模
|
|
2171
|
-
- 实时滤波和平滑
|
|
2172
|
-
- 缺失数据处理
|
|
2173
|
-
|
|
2174
|
-
⚠️ 注意事项:
|
|
2175
|
-
- 模型设定复杂
|
|
2176
|
-
- 需要先验知识
|
|
2177
|
-
- 计算量较大
|
|
2178
|
-
- 对初始值敏感
|
|
2179
|
-
|
|
2180
|
-
Args:
|
|
2181
|
-
data: 时间序列数据
|
|
2182
|
-
state_dim: 状态维度
|
|
2183
|
-
observation_dim: 观测维度
|
|
2184
|
-
trend: 是否包含趋势项
|
|
2185
|
-
seasonal: 是否包含季节项
|
|
2186
|
-
period: 季节周期
|
|
2187
|
-
ctx: MCP上下文对象
|
|
2188
|
-
"""
|
|
2189
|
-
await ctx.info(f"开始状态空间模型分析,样本大小: {len(data)},状态维度: {state_dim}")
|
|
2190
|
-
|
|
2191
|
-
try:
|
|
2192
|
-
# 数据验证
|
|
2193
|
-
if not data:
|
|
2194
|
-
raise ValueError("数据不能为空")
|
|
2195
|
-
if len(data) < 20:
|
|
2196
|
-
raise ValueError("状态空间模型至少需要20个观测点")
|
|
2197
|
-
|
|
2198
|
-
# 执行状态空间模型分析
|
|
2199
|
-
result = state_space_model(
|
|
2200
|
-
data,
|
|
2201
|
-
state_dim=state_dim,
|
|
2202
|
-
observation_dim=observation_dim,
|
|
2203
|
-
trend=trend,
|
|
2204
|
-
seasonal=seasonal,
|
|
2205
|
-
period=period
|
|
2206
|
-
)
|
|
2207
|
-
|
|
2208
|
-
await ctx.info("状态空间模型分析完成")
|
|
2209
|
-
|
|
2210
|
-
return CallToolResult(
|
|
2211
|
-
content=[
|
|
2212
|
-
TextContent(
|
|
2213
|
-
type="text",
|
|
2214
|
-
text=f"状态空间模型分析结果:\n"
|
|
2215
|
-
f"状态变量: {result.state_names}\n"
|
|
2216
|
-
f"对数似然: {result.log_likelihood:.2f}\n"
|
|
2217
|
-
f"AIC = {result.aic:.2f}, BIC = {result.bic:.2f}\n"
|
|
2218
|
-
f"滤波和平滑完成"
|
|
2219
|
-
)
|
|
2220
|
-
],
|
|
2221
|
-
structuredContent=result.model_dump()
|
|
2222
|
-
)
|
|
2223
|
-
|
|
2224
|
-
except Exception as e:
|
|
2225
|
-
await ctx.error(f"状态空间模型分析出错: {str(e)}")
|
|
2226
|
-
return CallToolResult(
|
|
2227
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
2228
|
-
isError=True
|
|
2229
|
-
)
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
@mcp.tool()
|
|
2233
|
-
async def var_forecast(
|
|
2234
|
-
ctx: Context[ServerSession, AppContext],
|
|
2235
|
-
data: Annotated[
|
|
2236
|
-
Dict[str, List[float]],
|
|
2237
|
-
Field(
|
|
2238
|
-
description="""多变量时间序列数据
|
|
2239
|
-
|
|
2240
|
-
示例格式:
|
|
2241
|
-
{
|
|
2242
|
-
"GDP增长率": [3.2, 2.8, 3.5, 2.9, 3.1, 2.7, 3.3, 3.0],
|
|
2243
|
-
"通货膨胀率": [2.1, 2.3, 1.9, 2.4, 2.2, 2.5, 2.0, 2.3]
|
|
2244
|
-
}
|
|
2245
|
-
|
|
2246
|
-
要求:
|
|
2247
|
-
- 至少包含2个变量
|
|
2248
|
-
- 所有变量的数据点数量必须相同
|
|
2249
|
-
- 建议样本量 >= 30
|
|
2250
|
-
- 数据应平稳或经过差分处理"""
|
|
2251
|
-
)
|
|
2252
|
-
],
|
|
2253
|
-
steps: Annotated[
|
|
2254
|
-
int,
|
|
2255
|
-
Field(
|
|
2256
|
-
default=10,
|
|
2257
|
-
description="""预测步数
|
|
2258
|
-
|
|
2259
|
-
说明:
|
|
2260
|
-
- 向前预测的期数
|
|
2261
|
-
- 建议值:5-20
|
|
2262
|
-
- 预测期数越长,不确定性越大"""
|
|
2263
|
-
)
|
|
2264
|
-
] = 10,
|
|
2265
|
-
max_lags: Annotated[
|
|
2266
|
-
int,
|
|
2267
|
-
Field(
|
|
2268
|
-
default=5,
|
|
2269
|
-
description="""最大滞后阶数
|
|
2270
|
-
|
|
2271
|
-
说明:
|
|
2272
|
-
- 用于VAR模型拟合
|
|
2273
|
-
- 建议值:3-8
|
|
2274
|
-
- 根据样本量调整"""
|
|
2275
|
-
)
|
|
2276
|
-
] = 5
|
|
2277
|
-
) -> CallToolResult:
|
|
2278
|
-
"""VAR模型预测
|
|
2279
|
-
|
|
2280
|
-
📊 功能说明:
|
|
2281
|
-
基于VAR模型进行多变量时间序列预测。
|
|
2282
|
-
|
|
2283
|
-
💡 使用场景:
|
|
2284
|
-
- 宏观经济变量联合预测
|
|
2285
|
-
- 金融市场联动预测
|
|
2286
|
-
- 政策模拟和情景分析
|
|
2287
|
-
|
|
2288
|
-
⚠️ 注意事项:
|
|
2289
|
-
- 预测精度随步数增加而下降
|
|
2290
|
-
- 需要平稳数据
|
|
2291
|
-
- 预测结果包含不确定性
|
|
2292
|
-
|
|
2293
|
-
Args:
|
|
2294
|
-
|
|
2295
|
-
data: 多变量时间序列数据
|
|
2296
|
-
steps: 预测步数
|
|
2297
|
-
max_lags: 最大滞后阶数
|
|
2298
|
-
ctx: MCP上下文对象
|
|
2299
|
-
"""
|
|
2300
|
-
await ctx.info(f"开始VAR模型预测,变量数量: {len(data)},预测步数: {steps}")
|
|
2301
|
-
|
|
2302
|
-
try:
|
|
2303
|
-
# 数据验证
|
|
2304
|
-
if not data:
|
|
2305
|
-
raise ValueError("数据不能为空")
|
|
2306
|
-
if len(data) < 2:
|
|
2307
|
-
raise ValueError("VAR预测至少需要2个变量")
|
|
2308
|
-
|
|
2309
|
-
# 执行VAR预测
|
|
2310
|
-
result = forecast_var(data, steps=steps, max_lags=max_lags)
|
|
2311
|
-
|
|
2312
|
-
await ctx.info("VAR模型预测完成")
|
|
2313
|
-
|
|
2314
|
-
return CallToolResult(
|
|
2315
|
-
content=[
|
|
2316
|
-
TextContent(
|
|
2317
|
-
type="text",
|
|
2318
|
-
text=f"VAR模型预测结果:\n"
|
|
2319
|
-
f"预测步数: {steps}\n"
|
|
2320
|
-
f"模型滞后阶数: {result['model_order']}\n"
|
|
2321
|
-
f"AIC = {result.get('model_aic', 0):.2f}, BIC = {result.get('model_bic', 0):.2f}\n"
|
|
2322
|
-
f"各变量预测值已生成"
|
|
2323
|
-
)
|
|
2324
|
-
],
|
|
2325
|
-
structuredContent=result
|
|
2326
|
-
)
|
|
2327
|
-
|
|
2328
|
-
except Exception as e:
|
|
2329
|
-
await ctx.error(f"VAR模型预测出错: {str(e)}")
|
|
2330
|
-
return CallToolResult(
|
|
2331
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
2332
|
-
isError=True
|
|
2333
|
-
)
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
@mcp.tool()
|
|
2337
|
-
async def impulse_response_analysis(
|
|
2338
|
-
ctx: Context[ServerSession, AppContext],
|
|
2339
|
-
data: Annotated[
|
|
2340
|
-
Dict[str, List[float]],
|
|
2341
|
-
Field(
|
|
2342
|
-
description="""多变量时间序列数据
|
|
2343
|
-
|
|
2344
|
-
示例格式:
|
|
2345
|
-
{
|
|
2346
|
-
"GDP增长率": [3.2, 2.8, 3.5, 2.9, 3.1, 2.7, 3.3, 3.0],
|
|
2347
|
-
"通货膨胀率": [2.1, 2.3, 1.9, 2.4, 2.2, 2.5, 2.0, 2.3],
|
|
2348
|
-
"利率": [2.5, 2.6, 2.4, 2.7, 2.5, 2.8, 2.3, 2.6]
|
|
2349
|
-
}
|
|
2350
|
-
|
|
2351
|
-
要求:
|
|
2352
|
-
- 至少包含2个变量
|
|
2353
|
-
- 所有变量的数据点数量必须相同
|
|
2354
|
-
- 建议样本量 >= 30
|
|
2355
|
-
- 数据应平稳或经过差分处理"""
|
|
2356
|
-
)
|
|
2357
|
-
],
|
|
2358
|
-
periods: Annotated[
|
|
2359
|
-
int,
|
|
2360
|
-
Field(
|
|
2361
|
-
default=10,
|
|
2362
|
-
description="""响应期数
|
|
2363
|
-
|
|
2364
|
-
说明:
|
|
2365
|
-
- 脉冲响应的追踪期数
|
|
2366
|
-
- 建议值:5-20
|
|
2367
|
-
- 期数越长,计算量越大"""
|
|
2368
|
-
)
|
|
2369
|
-
] = 10,
|
|
2370
|
-
max_lags: Annotated[
|
|
2371
|
-
int,
|
|
2372
|
-
Field(
|
|
2373
|
-
default=5,
|
|
2374
|
-
description="""最大滞后阶数
|
|
2375
|
-
|
|
2376
|
-
说明:
|
|
2377
|
-
- 用于VAR模型拟合
|
|
2378
|
-
- 建议值:3-8
|
|
2379
|
-
- 根据样本量调整"""
|
|
2380
|
-
)
|
|
2381
|
-
] = 5
|
|
315
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
316
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
317
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
318
|
+
data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
319
|
+
state_dim: Annotated[int, Field(default=1)] = 1,
|
|
320
|
+
observation_dim: Annotated[int, Field(default=1)] = 1,
|
|
321
|
+
trend: Annotated[bool, Field(default=True)] = True,
|
|
322
|
+
seasonal: Annotated[bool, Field(default=False)] = False,
|
|
323
|
+
period: Annotated[int, Field(default=12)] = 12
|
|
2382
324
|
) -> CallToolResult:
|
|
2383
|
-
"""
|
|
2384
|
-
|
|
2385
|
-
📊 功能说明:
|
|
2386
|
-
分析一个变量的冲击对其他变量的动态影响。
|
|
2387
|
-
|
|
2388
|
-
💡 使用场景:
|
|
2389
|
-
- 政策冲击效应分析
|
|
2390
|
-
- 变量间动态关系研究
|
|
2391
|
-
- 经济传导机制分析
|
|
2392
|
-
|
|
2393
|
-
⚠️ 注意事项:
|
|
2394
|
-
- 需要正交化处理
|
|
2395
|
-
- 结果对变量顺序敏感
|
|
2396
|
-
- 需要平稳数据
|
|
2397
|
-
|
|
2398
|
-
Args:
|
|
2399
|
-
data: 多变量时间序列数据
|
|
2400
|
-
periods: 响应期数
|
|
2401
|
-
max_lags: 最大滞后阶数
|
|
2402
|
-
ctx: MCP上下文对象
|
|
2403
|
-
"""
|
|
2404
|
-
await ctx.info(f"开始脉冲响应分析,变量数量: {len(data)},响应期数: {periods}")
|
|
2405
|
-
|
|
2406
|
-
try:
|
|
2407
|
-
# 数据验证
|
|
2408
|
-
if not data:
|
|
2409
|
-
raise ValueError("数据不能为空")
|
|
2410
|
-
if len(data) < 2:
|
|
2411
|
-
raise ValueError("脉冲响应分析至少需要2个变量")
|
|
2412
|
-
|
|
2413
|
-
# 执行脉冲响应分析
|
|
2414
|
-
result = impulse_response_analysis(data, periods=periods, max_lags=max_lags)
|
|
2415
|
-
|
|
2416
|
-
await ctx.info("脉冲响应分析完成")
|
|
2417
|
-
|
|
2418
|
-
return CallToolResult(
|
|
2419
|
-
content=[
|
|
2420
|
-
TextContent(
|
|
2421
|
-
type="text",
|
|
2422
|
-
text=f"脉冲响应分析结果:\n"
|
|
2423
|
-
f"响应期数: {periods}\n"
|
|
2424
|
-
f"变量数量: {len(data)}\n"
|
|
2425
|
-
f"所有冲击-响应组合的脉冲响应函数已计算"
|
|
2426
|
-
)
|
|
2427
|
-
],
|
|
2428
|
-
structuredContent=result
|
|
2429
|
-
)
|
|
2430
|
-
|
|
2431
|
-
except Exception as e:
|
|
2432
|
-
await ctx.error(f"脉冲响应分析出错: {str(e)}")
|
|
2433
|
-
return CallToolResult(
|
|
2434
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
2435
|
-
isError=True
|
|
2436
|
-
)
|
|
325
|
+
"""状态空间模型分析 - 支持文件输入"""
|
|
326
|
+
return await handle_state_space_model(ctx, data, state_dim, observation_dim, trend, seasonal, period)
|
|
2437
327
|
|
|
2438
328
|
|
|
2439
329
|
@mcp.tool()
|
|
330
|
+
@econometric_tool('time_series')
|
|
2440
331
|
async def variance_decomposition_analysis(
|
|
2441
332
|
ctx: Context[ServerSession, AppContext],
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
{
|
|
2449
|
-
"GDP增长率": [3.2, 2.8, 3.5, 2.9, 3.1, 2.7, 3.3, 3.0],
|
|
2450
|
-
"通货膨胀率": [2.1, 2.3, 1.9, 2.4, 2.2, 2.5, 2.0, 2.3],
|
|
2451
|
-
"利率": [2.5, 2.6, 2.4, 2.7, 2.5, 2.8, 2.3, 2.6]
|
|
2452
|
-
}
|
|
2453
|
-
|
|
2454
|
-
要求:
|
|
2455
|
-
- 至少包含2个变量
|
|
2456
|
-
- 所有变量的数据点数量必须相同
|
|
2457
|
-
- 建议样本量 >= 30
|
|
2458
|
-
- 数据应平稳或经过差分处理"""
|
|
2459
|
-
)
|
|
2460
|
-
],
|
|
2461
|
-
periods: Annotated[
|
|
2462
|
-
int,
|
|
2463
|
-
Field(
|
|
2464
|
-
default=10,
|
|
2465
|
-
description="""分解期数
|
|
2466
|
-
|
|
2467
|
-
说明:
|
|
2468
|
-
- 方差分解的期数
|
|
2469
|
-
- 建议值:5-20
|
|
2470
|
-
- 期数越长,结果越稳定"""
|
|
2471
|
-
)
|
|
2472
|
-
] = 10,
|
|
2473
|
-
max_lags: Annotated[
|
|
2474
|
-
int,
|
|
2475
|
-
Field(
|
|
2476
|
-
default=5,
|
|
2477
|
-
description="""最大滞后阶数
|
|
2478
|
-
|
|
2479
|
-
说明:
|
|
2480
|
-
- 用于VAR模型拟合
|
|
2481
|
-
- 建议值:3-8
|
|
2482
|
-
- 根据样本量调整"""
|
|
2483
|
-
)
|
|
2484
|
-
] = 5
|
|
333
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
334
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
335
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
336
|
+
data: Annotated[Optional[Dict[str, List[float]]], Field(default=None)] = None,
|
|
337
|
+
periods: Annotated[int, Field(default=10)] = 10,
|
|
338
|
+
max_lags: Annotated[int, Field(default=5)] = 5
|
|
2485
339
|
) -> CallToolResult:
|
|
2486
|
-
"""方差分解分析
|
|
2487
|
-
|
|
2488
|
-
📊 功能说明:
|
|
2489
|
-
将每个变量的预测误差方差分解为各冲击源的贡献。
|
|
2490
|
-
|
|
2491
|
-
💡 使用场景:
|
|
2492
|
-
- 变量重要性分析
|
|
2493
|
-
- 冲击来源识别
|
|
2494
|
-
- 系统稳定性分析
|
|
2495
|
-
|
|
2496
|
-
⚠️ 注意事项:
|
|
2497
|
-
- 需要正交化处理
|
|
2498
|
-
- 结果对变量顺序敏感
|
|
2499
|
-
- 需要平稳数据
|
|
2500
|
-
|
|
2501
|
-
Args:
|
|
2502
|
-
data: 多变量时间序列数据
|
|
2503
|
-
periods: 分解期数
|
|
2504
|
-
max_lags: 最大滞后阶数
|
|
2505
|
-
ctx: MCP上下文对象
|
|
2506
|
-
"""
|
|
2507
|
-
await ctx.info(f"开始方差分解分析,变量数量: {len(data)},分解期数: {periods}")
|
|
2508
|
-
|
|
2509
|
-
try:
|
|
2510
|
-
# 数据验证
|
|
2511
|
-
if not data:
|
|
2512
|
-
raise ValueError("数据不能为空")
|
|
2513
|
-
if len(data) < 2:
|
|
2514
|
-
raise ValueError("方差分解分析至少需要2个变量")
|
|
2515
|
-
|
|
2516
|
-
# 执行方差分解分析
|
|
2517
|
-
result = variance_decomposition(data, periods=periods, max_lags=max_lags)
|
|
2518
|
-
|
|
2519
|
-
await ctx.info("方差分解分析完成")
|
|
2520
|
-
|
|
2521
|
-
return CallToolResult(
|
|
2522
|
-
content=[
|
|
2523
|
-
TextContent(
|
|
2524
|
-
type="text",
|
|
2525
|
-
text=f"方差分解分析结果:\n"
|
|
2526
|
-
f"分解期数: {periods}\n"
|
|
2527
|
-
f"变量数量: {len(data)}\n"
|
|
2528
|
-
f"各变量方差分解已完成"
|
|
2529
|
-
)
|
|
2530
|
-
],
|
|
2531
|
-
structuredContent=result
|
|
2532
|
-
)
|
|
2533
|
-
|
|
2534
|
-
except Exception as e:
|
|
2535
|
-
await ctx.error(f"方差分解分析出错: {str(e)}")
|
|
2536
|
-
return CallToolResult(
|
|
2537
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
2538
|
-
isError=True
|
|
2539
|
-
)
|
|
2540
|
-
|
|
2541
|
-
# 机器学习工具导入
|
|
2542
|
-
from .tools.machine_learning import (
|
|
2543
|
-
RandomForestResult,
|
|
2544
|
-
GradientBoostingResult,
|
|
2545
|
-
RegularizedRegressionResult,
|
|
2546
|
-
CrossValidationResult,
|
|
2547
|
-
FeatureImportanceResult,
|
|
2548
|
-
random_forest_regression,
|
|
2549
|
-
gradient_boosting_regression,
|
|
2550
|
-
lasso_regression,
|
|
2551
|
-
ridge_regression,
|
|
2552
|
-
cross_validation,
|
|
2553
|
-
feature_importance_analysis,
|
|
2554
|
-
compare_ml_models
|
|
2555
|
-
)
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
class RandomForestArguments(BaseModel):
|
|
2559
|
-
"""随机森林回归参数"""
|
|
2560
|
-
y_data: List[float] = Field(description="因变量数据")
|
|
2561
|
-
x_data: List[List[float]] = Field(description="自变量数据")
|
|
2562
|
-
feature_names: Optional[List[str]] = Field(default=None, description="特征名称")
|
|
2563
|
-
n_estimators: int = Field(default=100, description="树的数量")
|
|
2564
|
-
max_depth: Optional[int] = Field(default=None, description="最大深度")
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
class GradientBoostingArguments(BaseModel):
|
|
2568
|
-
"""梯度提升树回归参数"""
|
|
2569
|
-
y_data: List[float] = Field(description="因变量数据")
|
|
2570
|
-
x_data: List[List[float]] = Field(description="自变量数据")
|
|
2571
|
-
feature_names: Optional[List[str]] = Field(default=None, description="特征名称")
|
|
2572
|
-
n_estimators: int = Field(default=100, description="树的数量")
|
|
2573
|
-
learning_rate: float = Field(default=0.1, description="学习率")
|
|
2574
|
-
max_depth: int = Field(default=3, description="最大深度")
|
|
340
|
+
"""方差分解分析 - 支持文件输入"""
|
|
341
|
+
return await handle_variance_decomposition(ctx, data, periods, max_lags)
|
|
2575
342
|
|
|
2576
343
|
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
x_data: List[List[float]] = Field(description="自变量数据")
|
|
2581
|
-
feature_names: Optional[List[str]] = Field(default=None, description="特征名称")
|
|
2582
|
-
alpha: float = Field(default=1.0, description="正则化强度")
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
class RidgeRegressionArguments(BaseModel):
|
|
2586
|
-
"""Ridge回归参数"""
|
|
2587
|
-
y_data: List[float] = Field(description="因变量数据")
|
|
2588
|
-
x_data: List[List[float]] = Field(description="自变量数据")
|
|
2589
|
-
feature_names: Optional[List[str]] = Field(default=None, description="特征名称")
|
|
2590
|
-
alpha: float = Field(default=1.0, description="正则化强度")
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
class CrossValidationArguments(BaseModel):
|
|
2594
|
-
"""交叉验证参数"""
|
|
2595
|
-
y_data: List[float] = Field(description="因变量数据")
|
|
2596
|
-
x_data: List[List[float]] = Field(description="自变量数据")
|
|
2597
|
-
model_type: str = Field(default="random_forest", description="模型类型")
|
|
2598
|
-
cv_folds: int = Field(default=5, description="交叉验证折数")
|
|
2599
|
-
scoring: str = Field(default="r2", description="评分指标")
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
class FeatureImportanceArguments(BaseModel):
|
|
2603
|
-
"""特征重要性分析参数"""
|
|
2604
|
-
y_data: List[float] = Field(description="因变量数据")
|
|
2605
|
-
x_data: List[List[float]] = Field(description="自变量数据")
|
|
2606
|
-
feature_names: Optional[List[str]] = Field(default=None, description="特征名称")
|
|
2607
|
-
method: str = Field(default="random_forest", description="分析方法")
|
|
2608
|
-
top_k: int = Field(default=5, description="最重要的特征数量")
|
|
2609
|
-
|
|
344
|
+
# ============================================================================
|
|
345
|
+
# 机器学习工具 (6个) - 自动支持文件输入
|
|
346
|
+
# ============================================================================
|
|
2610
347
|
|
|
2611
348
|
@mcp.tool()
|
|
349
|
+
@econometric_tool('regression')
|
|
2612
350
|
async def random_forest_regression_analysis(
|
|
2613
351
|
ctx: Context[ServerSession, AppContext],
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
- 必须为数值列表
|
|
2623
|
-
- 长度必须与自变量观测数量一致
|
|
2624
|
-
- 不能包含缺失值(NaN)
|
|
2625
|
-
- 建议样本量 >= 30"""
|
|
2626
|
-
)
|
|
2627
|
-
],
|
|
2628
|
-
x_data: Annotated[
|
|
2629
|
-
List[List[float]],
|
|
2630
|
-
Field(
|
|
2631
|
-
description="""自变量数据(解释变量),二维列表格式
|
|
2632
|
-
|
|
2633
|
-
示例格式(4个观测,2个自变量):
|
|
2634
|
-
[
|
|
2635
|
-
[5, 100], # 第1个观测的自变量值
|
|
2636
|
-
[6, 98], # 第2个观测的自变量值
|
|
2637
|
-
[7.5, 95], # 第3个观测的自变量值
|
|
2638
|
-
[6.5, 97] # 第4个观测的自变量值
|
|
2639
|
-
]
|
|
2640
|
-
|
|
2641
|
-
要求:
|
|
2642
|
-
- 外层列表:每个元素代表一个观测
|
|
2643
|
-
- 内层列表:该观测的所有自变量值
|
|
2644
|
-
- 所有观测的自变量数量必须相同
|
|
2645
|
-
- 观测数量必须与y_data长度一致"""
|
|
2646
|
-
)
|
|
2647
|
-
],
|
|
2648
|
-
feature_names: Annotated[
|
|
2649
|
-
Optional[List[str]],
|
|
2650
|
-
Field(
|
|
2651
|
-
default=None,
|
|
2652
|
-
description="""特征名称列表(可选)
|
|
2653
|
-
|
|
2654
|
-
示例:["广告支出", "价格"]
|
|
2655
|
-
|
|
2656
|
-
说明:
|
|
2657
|
-
- 如果不提供,将自动命名为 x1, x2, x3...
|
|
2658
|
-
- 名称数量必须与自变量数量一致
|
|
2659
|
-
- 建议使用有意义的名称以便解释结果"""
|
|
2660
|
-
)
|
|
2661
|
-
] = None,
|
|
2662
|
-
n_estimators: Annotated[
|
|
2663
|
-
int,
|
|
2664
|
-
Field(
|
|
2665
|
-
default=100,
|
|
2666
|
-
description="""树的数量
|
|
2667
|
-
|
|
2668
|
-
说明:
|
|
2669
|
-
- 随机森林中决策树的数量
|
|
2670
|
-
- 默认值:100
|
|
2671
|
-
- 建议范围:50-500
|
|
2672
|
-
- 树越多,模型越稳定但计算成本越高"""
|
|
2673
|
-
)
|
|
2674
|
-
] = 100,
|
|
2675
|
-
max_depth: Annotated[
|
|
2676
|
-
Optional[int],
|
|
2677
|
-
Field(
|
|
2678
|
-
default=None,
|
|
2679
|
-
description="""最大深度
|
|
2680
|
-
|
|
2681
|
-
说明:
|
|
2682
|
-
- 决策树的最大深度
|
|
2683
|
-
- None:不限制深度
|
|
2684
|
-
- 建议值:3-20
|
|
2685
|
-
- 深度越大,模型越复杂,可能过拟合"""
|
|
2686
|
-
)
|
|
2687
|
-
] = None
|
|
352
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
353
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
354
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
355
|
+
y_data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
356
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None)] = None,
|
|
357
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
358
|
+
n_estimators: Annotated[int, Field(default=100)] = 100,
|
|
359
|
+
max_depth: Annotated[Optional[int], Field(default=None)] = None
|
|
2688
360
|
) -> CallToolResult:
|
|
2689
|
-
"""
|
|
2690
|
-
|
|
2691
|
-
📊 功能说明:
|
|
2692
|
-
使用随机森林算法进行回归分析,适用于非线性关系和复杂交互效应。
|
|
2693
|
-
|
|
2694
|
-
📈 算法特点:
|
|
2695
|
-
- 集成学习:多个决策树的组合
|
|
2696
|
-
- 抗过拟合:通过袋外样本和特征随机选择
|
|
2697
|
-
- 非线性建模:能够捕捉复杂的非线性关系
|
|
2698
|
-
- 特征重要性:提供特征重要性排序
|
|
2699
|
-
|
|
2700
|
-
💡 使用场景:
|
|
2701
|
-
- 复杂非线性关系建模
|
|
2702
|
-
- 特征重要性分析
|
|
2703
|
-
- 高维数据回归
|
|
2704
|
-
- 稳健预测建模
|
|
2705
|
-
|
|
2706
|
-
⚠️ 注意事项:
|
|
2707
|
-
- 计算复杂度较高
|
|
2708
|
-
- 需要调整超参数(n_estimators, max_depth)
|
|
2709
|
-
- 对异常值相对稳健
|
|
2710
|
-
|
|
2711
|
-
Args:
|
|
2712
|
-
y_data: 因变量数据
|
|
2713
|
-
x_data: 自变量数据
|
|
2714
|
-
feature_names: 特征名称
|
|
2715
|
-
n_estimators: 树的数量
|
|
2716
|
-
max_depth: 最大深度
|
|
2717
|
-
ctx: MCP上下文对象
|
|
2718
|
-
"""
|
|
2719
|
-
await ctx.info(f"开始随机森林回归分析,样本大小: {len(y_data)},特征数量: {len(x_data[0]) if x_data else 0}")
|
|
2720
|
-
|
|
2721
|
-
try:
|
|
2722
|
-
# 执行随机森林回归
|
|
2723
|
-
result = random_forest_regression(
|
|
2724
|
-
y_data, x_data, feature_names, n_estimators, max_depth
|
|
2725
|
-
)
|
|
2726
|
-
|
|
2727
|
-
await ctx.info("随机森林回归分析完成")
|
|
2728
|
-
|
|
2729
|
-
return CallToolResult(
|
|
2730
|
-
content=[
|
|
2731
|
-
TextContent(
|
|
2732
|
-
type="text",
|
|
2733
|
-
text=f"随机森林回归分析结果:\n"
|
|
2734
|
-
f"R² = {result.r2_score:.4f}\n"
|
|
2735
|
-
f"均方误差 = {result.mse:.4f}\n"
|
|
2736
|
-
f"平均绝对误差 = {result.mae:.4f}\n"
|
|
2737
|
-
f"树的数量 = {result.n_estimators}\n"
|
|
2738
|
-
f"最大深度 = {result.max_depth if result.max_depth != -1 else '无限制'}\n"
|
|
2739
|
-
f"袋外得分 = {result.oob_score:.4f if result.oob_score is not None else 'N/A'}\n\n"
|
|
2740
|
-
f"特征重要性:\n" + "\n".join([
|
|
2741
|
-
f" {feature}: {importance:.4f}"
|
|
2742
|
-
for feature, importance in result.feature_importance.items()
|
|
2743
|
-
])
|
|
2744
|
-
)
|
|
2745
|
-
],
|
|
2746
|
-
structuredContent=result.model_dump()
|
|
2747
|
-
)
|
|
2748
|
-
|
|
2749
|
-
except Exception as e:
|
|
2750
|
-
await ctx.error(f"随机森林回归分析出错: {str(e)}")
|
|
2751
|
-
return CallToolResult(
|
|
2752
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
2753
|
-
isError=True
|
|
2754
|
-
)
|
|
361
|
+
"""随机森林回归 - 支持文件输入"""
|
|
362
|
+
return await handle_random_forest(ctx, y_data, x_data, feature_names, n_estimators, max_depth)
|
|
2755
363
|
|
|
2756
364
|
|
|
2757
365
|
@mcp.tool()
|
|
366
|
+
@econometric_tool('regression')
|
|
2758
367
|
async def gradient_boosting_regression_analysis(
|
|
2759
368
|
ctx: Context[ServerSession, AppContext],
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
- 长度必须与自变量观测数量一致
|
|
2770
|
-
- 不能包含缺失值(NaN)
|
|
2771
|
-
- 建议样本量 >= 30"""
|
|
2772
|
-
)
|
|
2773
|
-
],
|
|
2774
|
-
x_data: Annotated[
|
|
2775
|
-
List[List[float]],
|
|
2776
|
-
Field(
|
|
2777
|
-
description="""自变量数据(解释变量),二维列表格式
|
|
2778
|
-
|
|
2779
|
-
示例格式(4个观测,2个自变量):
|
|
2780
|
-
[
|
|
2781
|
-
[5, 100], # 第1个观测的自变量值
|
|
2782
|
-
[6, 98], # 第2个观测的自变量值
|
|
2783
|
-
[7.5, 95], # 第3个观测的自变量值
|
|
2784
|
-
[6.5, 97] # 第4个观测的自变量值
|
|
2785
|
-
]
|
|
2786
|
-
|
|
2787
|
-
要求:
|
|
2788
|
-
- 外层列表:每个元素代表一个观测
|
|
2789
|
-
- 内层列表:该观测的所有自变量值
|
|
2790
|
-
- 所有观测的自变量数量必须相同
|
|
2791
|
-
- 观测数量必须与y_data长度一致"""
|
|
2792
|
-
)
|
|
2793
|
-
],
|
|
2794
|
-
feature_names: Annotated[
|
|
2795
|
-
Optional[List[str]],
|
|
2796
|
-
Field(
|
|
2797
|
-
default=None,
|
|
2798
|
-
description="""特征名称列表(可选)
|
|
2799
|
-
|
|
2800
|
-
示例:["广告支出", "价格"]
|
|
2801
|
-
|
|
2802
|
-
说明:
|
|
2803
|
-
- 如果不提供,将自动命名为 x1, x2, x3...
|
|
2804
|
-
- 名称数量必须与自变量数量一致
|
|
2805
|
-
- 建议使用有意义的名称以便解释结果"""
|
|
2806
|
-
)
|
|
2807
|
-
] = None,
|
|
2808
|
-
n_estimators: Annotated[
|
|
2809
|
-
int,
|
|
2810
|
-
Field(
|
|
2811
|
-
default=100,
|
|
2812
|
-
description="""树的数量
|
|
2813
|
-
|
|
2814
|
-
说明:
|
|
2815
|
-
- 梯度提升树中决策树的数量
|
|
2816
|
-
- 默认值:100
|
|
2817
|
-
- 建议范围:50-500
|
|
2818
|
-
- 树越多,模型越精确但计算成本越高"""
|
|
2819
|
-
)
|
|
2820
|
-
] = 100,
|
|
2821
|
-
learning_rate: Annotated[
|
|
2822
|
-
float,
|
|
2823
|
-
Field(
|
|
2824
|
-
default=0.1,
|
|
2825
|
-
description="""学习率
|
|
2826
|
-
|
|
2827
|
-
说明:
|
|
2828
|
-
- 每棵树对最终预测的贡献程度
|
|
2829
|
-
- 默认值:0.1
|
|
2830
|
-
- 建议范围:0.01-0.3
|
|
2831
|
-
- 学习率越小,需要更多的树"""
|
|
2832
|
-
)
|
|
2833
|
-
] = 0.1,
|
|
2834
|
-
max_depth: Annotated[
|
|
2835
|
-
int,
|
|
2836
|
-
Field(
|
|
2837
|
-
default=3,
|
|
2838
|
-
description="""最大深度
|
|
2839
|
-
|
|
2840
|
-
说明:
|
|
2841
|
-
- 决策树的最大深度
|
|
2842
|
-
- 默认值:3
|
|
2843
|
-
- 建议范围:2-8
|
|
2844
|
-
- 深度越大,模型越复杂,可能过拟合"""
|
|
2845
|
-
)
|
|
2846
|
-
] = 3
|
|
369
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
370
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
371
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
372
|
+
y_data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
373
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None)] = None,
|
|
374
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
375
|
+
n_estimators: Annotated[int, Field(default=100)] = 100,
|
|
376
|
+
learning_rate: Annotated[float, Field(default=0.1)] = 0.1,
|
|
377
|
+
max_depth: Annotated[int, Field(default=3)] = 3
|
|
2847
378
|
) -> CallToolResult:
|
|
2848
|
-
"""
|
|
2849
|
-
|
|
2850
|
-
📊 功能说明:
|
|
2851
|
-
使用梯度提升算法进行回归分析,通过逐步优化残差来提升模型性能。
|
|
2852
|
-
|
|
2853
|
-
📈 算法特点:
|
|
2854
|
-
- 逐步优化:通过梯度下降逐步改进模型
|
|
2855
|
-
- 高精度:通常比随机森林有更好的预测精度
|
|
2856
|
-
- 正则化:通过学习率和树深度控制过拟合
|
|
2857
|
-
- 特征重要性:提供特征重要性排序
|
|
2858
|
-
|
|
2859
|
-
💡 使用场景:
|
|
2860
|
-
- 高精度预测需求
|
|
2861
|
-
- 结构化数据建模
|
|
2862
|
-
- 竞赛和实际应用
|
|
2863
|
-
- 需要精细调优的场景
|
|
2864
|
-
|
|
2865
|
-
⚠️ 注意事项:
|
|
2866
|
-
- 对超参数敏感
|
|
2867
|
-
- 训练时间较长
|
|
2868
|
-
- 容易过拟合(需要仔细调参)
|
|
2869
|
-
|
|
2870
|
-
Args:
|
|
2871
|
-
y_data: 因变量数据
|
|
2872
|
-
x_data: 自变量数据
|
|
2873
|
-
feature_names: 特征名称
|
|
2874
|
-
n_estimators: 树的数量
|
|
2875
|
-
learning_rate: 学习率
|
|
2876
|
-
max_depth: 最大深度
|
|
2877
|
-
ctx: MCP上下文对象
|
|
2878
|
-
"""
|
|
2879
|
-
await ctx.info(f"开始梯度提升树回归分析,样本大小: {len(y_data)},特征数量: {len(x_data[0]) if x_data else 0}")
|
|
2880
|
-
|
|
2881
|
-
try:
|
|
2882
|
-
# 执行梯度提升树回归
|
|
2883
|
-
result = gradient_boosting_regression(
|
|
2884
|
-
y_data, x_data, feature_names, n_estimators, learning_rate, max_depth
|
|
2885
|
-
)
|
|
2886
|
-
|
|
2887
|
-
await ctx.info("梯度提升树回归分析完成")
|
|
2888
|
-
|
|
2889
|
-
return CallToolResult(
|
|
2890
|
-
content=[
|
|
2891
|
-
TextContent(
|
|
2892
|
-
type="text",
|
|
2893
|
-
text=f"梯度提升树回归分析结果:\n"
|
|
2894
|
-
f"R² = {result.r2_score:.4f}\n"
|
|
2895
|
-
f"均方误差 = {result.mse:.4f}\n"
|
|
2896
|
-
f"平均绝对误差 = {result.mae:.4f}\n"
|
|
2897
|
-
f"树的数量 = {result.n_estimators}\n"
|
|
2898
|
-
f"学习率 = {result.learning_rate}\n"
|
|
2899
|
-
f"最大深度 = {result.max_depth}\n\n"
|
|
2900
|
-
f"特征重要性:\n" + "\n".join([
|
|
2901
|
-
f" {feature}: {importance:.4f}"
|
|
2902
|
-
for feature, importance in result.feature_importance.items()
|
|
2903
|
-
])
|
|
2904
|
-
)
|
|
2905
|
-
],
|
|
2906
|
-
structuredContent=result.model_dump()
|
|
2907
|
-
)
|
|
2908
|
-
|
|
2909
|
-
except Exception as e:
|
|
2910
|
-
await ctx.error(f"梯度提升树回归分析出错: {str(e)}")
|
|
2911
|
-
return CallToolResult(
|
|
2912
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
2913
|
-
isError=True
|
|
2914
|
-
)
|
|
379
|
+
"""梯度提升树回归 - 支持文件输入"""
|
|
380
|
+
return await handle_gradient_boosting(ctx, y_data, x_data, feature_names, n_estimators, learning_rate, max_depth)
|
|
2915
381
|
|
|
2916
382
|
|
|
2917
383
|
@mcp.tool()
|
|
384
|
+
@econometric_tool('regression')
|
|
2918
385
|
async def lasso_regression_analysis(
|
|
2919
386
|
ctx: Context[ServerSession, AppContext],
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
要求:
|
|
2928
|
-
- 必须为数值列表
|
|
2929
|
-
- 长度必须与自变量观测数量一致
|
|
2930
|
-
- 不能包含缺失值(NaN)
|
|
2931
|
-
- 建议样本量 >= 30"""
|
|
2932
|
-
)
|
|
2933
|
-
],
|
|
2934
|
-
x_data: Annotated[
|
|
2935
|
-
List[List[float]],
|
|
2936
|
-
Field(
|
|
2937
|
-
description="""自变量数据(解释变量),二维列表格式
|
|
2938
|
-
|
|
2939
|
-
示例格式(4个观测,2个自变量):
|
|
2940
|
-
[
|
|
2941
|
-
[5, 100], # 第1个观测的自变量值
|
|
2942
|
-
[6, 98], # 第2个观测的自变量值
|
|
2943
|
-
[7.5, 95], # 第3个观测的自变量值
|
|
2944
|
-
[6.5, 97] # 第4个观测的自变量值
|
|
2945
|
-
]
|
|
2946
|
-
|
|
2947
|
-
要求:
|
|
2948
|
-
- 外层列表:每个元素代表一个观测
|
|
2949
|
-
- 内层列表:该观测的所有自变量值
|
|
2950
|
-
- 所有观测的自变量数量必须相同
|
|
2951
|
-
- 观测数量必须与y_data长度一致"""
|
|
2952
|
-
)
|
|
2953
|
-
],
|
|
2954
|
-
feature_names: Annotated[
|
|
2955
|
-
Optional[List[str]],
|
|
2956
|
-
Field(
|
|
2957
|
-
default=None,
|
|
2958
|
-
description="""特征名称列表(可选)
|
|
2959
|
-
|
|
2960
|
-
示例:["广告支出", "价格"]
|
|
2961
|
-
|
|
2962
|
-
说明:
|
|
2963
|
-
- 如果不提供,将自动命名为 x1, x2, x3...
|
|
2964
|
-
- 名称数量必须与自变量数量一致
|
|
2965
|
-
- 建议使用有意义的名称以便解释结果"""
|
|
2966
|
-
)
|
|
2967
|
-
] = None,
|
|
2968
|
-
alpha: Annotated[
|
|
2969
|
-
float,
|
|
2970
|
-
Field(
|
|
2971
|
-
default=1.0,
|
|
2972
|
-
description="""正则化强度
|
|
2973
|
-
|
|
2974
|
-
说明:
|
|
2975
|
-
- L1正则化的强度参数
|
|
2976
|
-
- 默认值:1.0
|
|
2977
|
-
- 建议范围:0.001-10
|
|
2978
|
-
- alpha越大,正则化越强,更多系数变为0"""
|
|
2979
|
-
)
|
|
2980
|
-
] = 1.0
|
|
387
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
388
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
389
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
390
|
+
y_data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
391
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None)] = None,
|
|
392
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
393
|
+
alpha: Annotated[float, Field(default=1.0)] = 1.0
|
|
2981
394
|
) -> CallToolResult:
|
|
2982
|
-
"""Lasso
|
|
2983
|
-
|
|
2984
|
-
📊 功能说明:
|
|
2985
|
-
使用L1正则化的线性回归,能够进行特征选择和稀疏建模。
|
|
2986
|
-
|
|
2987
|
-
📈 算法特点:
|
|
2988
|
-
- 特征选择:自动将不重要的特征系数压缩为0
|
|
2989
|
-
- 稀疏解:产生稀疏的系数向量
|
|
2990
|
-
- 可解释性:保留重要特征,去除冗余特征
|
|
2991
|
-
- 处理多重共线性:对高度相关的特征进行选择
|
|
2992
|
-
|
|
2993
|
-
💡 使用场景:
|
|
2994
|
-
- 高维数据特征选择
|
|
2995
|
-
- 多重共线性问题
|
|
2996
|
-
- 稀疏建模需求
|
|
2997
|
-
- 可解释性要求高的场景
|
|
2998
|
-
|
|
2999
|
-
⚠️ 注意事项:
|
|
3000
|
-
- 对alpha参数敏感
|
|
3001
|
-
- 可能过度压缩重要特征
|
|
3002
|
-
- 需要数据标准化
|
|
3003
|
-
|
|
3004
|
-
Args:
|
|
3005
|
-
y_data: 因变量数据
|
|
3006
|
-
x_data: 自变量数据
|
|
3007
|
-
feature_names: 特征名称
|
|
3008
|
-
alpha: 正则化强度
|
|
3009
|
-
ctx: MCP上下文对象
|
|
3010
|
-
"""
|
|
3011
|
-
await ctx.info(f"开始Lasso回归分析,样本大小: {len(y_data)},特征数量: {len(x_data[0]) if x_data else 0}")
|
|
3012
|
-
|
|
3013
|
-
try:
|
|
3014
|
-
# 执行Lasso回归
|
|
3015
|
-
result = lasso_regression(y_data, x_data, feature_names, alpha)
|
|
3016
|
-
|
|
3017
|
-
await ctx.info("Lasso回归分析完成")
|
|
3018
|
-
|
|
3019
|
-
return CallToolResult(
|
|
3020
|
-
content=[
|
|
3021
|
-
TextContent(
|
|
3022
|
-
type="text",
|
|
3023
|
-
text=f"Lasso回归分析结果:\n"
|
|
3024
|
-
f"R² = {result.r2_score:.4f}\n"
|
|
3025
|
-
f"均方误差 = {result.mse:.4f}\n"
|
|
3026
|
-
f"平均绝对误差 = {result.mae:.4f}\n"
|
|
3027
|
-
f"正则化强度 = {result.alpha}\n\n"
|
|
3028
|
-
f"回归系数:\n" + "\n".join([
|
|
3029
|
-
f" {feature}: {coef:.4f}"
|
|
3030
|
-
for feature, coef in result.coefficients.items()
|
|
3031
|
-
])
|
|
3032
|
-
)
|
|
3033
|
-
],
|
|
3034
|
-
structuredContent=result.model_dump()
|
|
3035
|
-
)
|
|
3036
|
-
|
|
3037
|
-
except Exception as e:
|
|
3038
|
-
await ctx.error(f"Lasso回归分析出错: {str(e)}")
|
|
3039
|
-
return CallToolResult(
|
|
3040
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
3041
|
-
isError=True
|
|
3042
|
-
)
|
|
395
|
+
"""Lasso回归 - 支持文件输入"""
|
|
396
|
+
return await handle_lasso_regression(ctx, y_data, x_data, feature_names, alpha)
|
|
3043
397
|
|
|
3044
398
|
|
|
3045
399
|
@mcp.tool()
|
|
400
|
+
@econometric_tool('regression')
|
|
3046
401
|
async def ridge_regression_analysis(
|
|
3047
402
|
ctx: Context[ServerSession, AppContext],
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
要求:
|
|
3056
|
-
- 必须为数值列表
|
|
3057
|
-
- 长度必须与自变量观测数量一致
|
|
3058
|
-
- 不能包含缺失值(NaN)
|
|
3059
|
-
- 建议样本量 >= 30"""
|
|
3060
|
-
)
|
|
3061
|
-
],
|
|
3062
|
-
x_data: Annotated[
|
|
3063
|
-
List[List[float]],
|
|
3064
|
-
Field(
|
|
3065
|
-
description="""自变量数据(解释变量),二维列表格式
|
|
3066
|
-
|
|
3067
|
-
示例格式(4个观测,2个自变量):
|
|
3068
|
-
[
|
|
3069
|
-
[5, 100], # 第1个观测的自变量值
|
|
3070
|
-
[6, 98], # 第2个观测的自变量值
|
|
3071
|
-
[7.5, 95], # 第3个观测的自变量值
|
|
3072
|
-
[6.5, 97] # 第4个观测的自变量值
|
|
3073
|
-
]
|
|
3074
|
-
|
|
3075
|
-
要求:
|
|
3076
|
-
- 外层列表:每个元素代表一个观测
|
|
3077
|
-
- 内层列表:该观测的所有自变量值
|
|
3078
|
-
- 所有观测的自变量数量必须相同
|
|
3079
|
-
- 观测数量必须与y_data长度一致"""
|
|
3080
|
-
)
|
|
3081
|
-
],
|
|
3082
|
-
feature_names: Annotated[
|
|
3083
|
-
Optional[List[str]],
|
|
3084
|
-
Field(
|
|
3085
|
-
default=None,
|
|
3086
|
-
description="""特征名称列表(可选)
|
|
3087
|
-
|
|
3088
|
-
示例:["广告支出", "价格"]
|
|
3089
|
-
|
|
3090
|
-
说明:
|
|
3091
|
-
- 如果不提供,将自动命名为 x1, x2, x3...
|
|
3092
|
-
- 名称数量必须与自变量数量一致
|
|
3093
|
-
- 建议使用有意义的名称以便解释结果"""
|
|
3094
|
-
)
|
|
3095
|
-
] = None,
|
|
3096
|
-
alpha: Annotated[
|
|
3097
|
-
float,
|
|
3098
|
-
Field(
|
|
3099
|
-
default=1.0,
|
|
3100
|
-
description="""正则化强度
|
|
3101
|
-
|
|
3102
|
-
说明:
|
|
3103
|
-
- L2正则化的强度参数
|
|
3104
|
-
- 默认值:1.0
|
|
3105
|
-
- 建议范围:0.001-10
|
|
3106
|
-
- alpha越大,正则化越强,系数收缩越明显"""
|
|
3107
|
-
)
|
|
3108
|
-
] = 1.0
|
|
403
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
404
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
405
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
406
|
+
y_data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
407
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None)] = None,
|
|
408
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
409
|
+
alpha: Annotated[float, Field(default=1.0)] = 1.0
|
|
3109
410
|
) -> CallToolResult:
|
|
3110
|
-
"""Ridge
|
|
3111
|
-
|
|
3112
|
-
📊 功能说明:
|
|
3113
|
-
使用L2正则化的线性回归,能够处理多重共线性问题。
|
|
3114
|
-
|
|
3115
|
-
📈 算法特点:
|
|
3116
|
-
- 稳定性:对多重共线性稳健
|
|
3117
|
-
- 收缩系数:将所有系数向0收缩
|
|
3118
|
-
- 无特征选择:保留所有特征
|
|
3119
|
-
- 数值稳定性:改善矩阵条件数
|
|
3120
|
-
|
|
3121
|
-
💡 使用场景:
|
|
3122
|
-
- 多重共线性问题
|
|
3123
|
-
- 需要稳定估计的场景
|
|
3124
|
-
- 所有特征都可能有贡献的情况
|
|
3125
|
-
- 小样本高维数据
|
|
3126
|
-
|
|
3127
|
-
⚠️ 注意事项:
|
|
3128
|
-
- 不进行特征选择
|
|
3129
|
-
- 对alpha参数敏感
|
|
3130
|
-
- 需要数据标准化
|
|
3131
|
-
|
|
3132
|
-
Args:
|
|
3133
|
-
y_data: 因变量数据
|
|
3134
|
-
x_data: 自变量数据
|
|
3135
|
-
feature_names: 特征名称
|
|
3136
|
-
alpha: 正则化强度
|
|
3137
|
-
ctx: MCP上下文对象
|
|
3138
|
-
"""
|
|
3139
|
-
await ctx.info(f"开始Ridge回归分析,样本大小: {len(y_data)},特征数量: {len(x_data[0]) if x_data else 0}")
|
|
3140
|
-
|
|
3141
|
-
try:
|
|
3142
|
-
# 执行Ridge回归
|
|
3143
|
-
result = ridge_regression(y_data, x_data, feature_names, alpha)
|
|
3144
|
-
|
|
3145
|
-
await ctx.info("Ridge回归分析完成")
|
|
3146
|
-
|
|
3147
|
-
return CallToolResult(
|
|
3148
|
-
content=[
|
|
3149
|
-
TextContent(
|
|
3150
|
-
type="text",
|
|
3151
|
-
text=f"Ridge回归分析结果:\n"
|
|
3152
|
-
f"R² = {result.r2_score:.4f}\n"
|
|
3153
|
-
f"均方误差 = {result.mse:.4f}\n"
|
|
3154
|
-
f"平均绝对误差 = {result.mae:.4f}\n"
|
|
3155
|
-
f"正则化强度 = {result.alpha}\n\n"
|
|
3156
|
-
f"回归系数:\n" + "\n".join([
|
|
3157
|
-
f" {feature}: {coef:.4f}"
|
|
3158
|
-
for feature, coef in result.coefficients.items()
|
|
3159
|
-
])
|
|
3160
|
-
)
|
|
3161
|
-
],
|
|
3162
|
-
structuredContent=result.model_dump()
|
|
3163
|
-
)
|
|
3164
|
-
|
|
3165
|
-
except Exception as e:
|
|
3166
|
-
await ctx.error(f"Ridge回归分析出错: {str(e)}")
|
|
3167
|
-
return CallToolResult(
|
|
3168
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
3169
|
-
isError=True
|
|
3170
|
-
)
|
|
411
|
+
"""Ridge回归 - 支持文件输入"""
|
|
412
|
+
return await handle_ridge_regression(ctx, y_data, x_data, feature_names, alpha)
|
|
3171
413
|
|
|
3172
414
|
|
|
3173
415
|
@mcp.tool()
|
|
416
|
+
@econometric_tool('regression')
|
|
3174
417
|
async def cross_validation_analysis(
|
|
3175
418
|
ctx: Context[ServerSession, AppContext],
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
- 长度必须与自变量观测数量一致
|
|
3186
|
-
- 不能包含缺失值(NaN)
|
|
3187
|
-
- 建议样本量 >= 30"""
|
|
3188
|
-
)
|
|
3189
|
-
],
|
|
3190
|
-
x_data: Annotated[
|
|
3191
|
-
List[List[float]],
|
|
3192
|
-
Field(
|
|
3193
|
-
description="""自变量数据(解释变量),二维列表格式
|
|
3194
|
-
|
|
3195
|
-
示例格式(4个观测,2个自变量):
|
|
3196
|
-
[
|
|
3197
|
-
[5, 100], # 第1个观测的自变量值
|
|
3198
|
-
[6, 98], # 第2个观测的自变量值
|
|
3199
|
-
[7.5, 95], # 第3个观测的自变量值
|
|
3200
|
-
[6.5, 97] # 第4个观测的自变量值
|
|
3201
|
-
]
|
|
3202
|
-
|
|
3203
|
-
要求:
|
|
3204
|
-
- 外层列表:每个元素代表一个观测
|
|
3205
|
-
- 内层列表:该观测的所有自变量值
|
|
3206
|
-
- 所有观测的自变量数量必须相同
|
|
3207
|
-
- 观测数量必须与y_data长度一致"""
|
|
3208
|
-
)
|
|
3209
|
-
],
|
|
3210
|
-
model_type: Annotated[
|
|
3211
|
-
str,
|
|
3212
|
-
Field(
|
|
3213
|
-
default="random_forest",
|
|
3214
|
-
description="""模型类型
|
|
3215
|
-
|
|
3216
|
-
可选值:
|
|
3217
|
-
- "random_forest": 随机森林
|
|
3218
|
-
- "gradient_boosting": 梯度提升树
|
|
3219
|
-
- "lasso": Lasso回归
|
|
3220
|
-
- "ridge": Ridge回归
|
|
3221
|
-
|
|
3222
|
-
选择建议:
|
|
3223
|
-
- 非线性关系 → random_forest, gradient_boosting
|
|
3224
|
-
- 特征选择 → lasso
|
|
3225
|
-
- 稳定性 → ridge"""
|
|
3226
|
-
)
|
|
3227
|
-
] = "random_forest",
|
|
3228
|
-
cv_folds: Annotated[
|
|
3229
|
-
int,
|
|
3230
|
-
Field(
|
|
3231
|
-
default=5,
|
|
3232
|
-
description="""交叉验证折数
|
|
3233
|
-
|
|
3234
|
-
说明:
|
|
3235
|
-
- 将数据分为多少份进行交叉验证
|
|
3236
|
-
- 默认值:5
|
|
3237
|
-
- 建议范围:3-10
|
|
3238
|
-
- 折数越多,评估越稳定但计算成本越高"""
|
|
3239
|
-
)
|
|
3240
|
-
] = 5,
|
|
3241
|
-
scoring: Annotated[
|
|
3242
|
-
str,
|
|
3243
|
-
Field(
|
|
3244
|
-
default="r2",
|
|
3245
|
-
description="""评分指标
|
|
3246
|
-
|
|
3247
|
-
可选值:
|
|
3248
|
-
- "r2": R²得分
|
|
3249
|
-
- "neg_mean_squared_error": 负均方误差
|
|
3250
|
-
- "neg_mean_absolute_error": 负平均绝对误差
|
|
3251
|
-
|
|
3252
|
-
说明:
|
|
3253
|
-
- 使用负值指标时,得分越高表示模型越好"""
|
|
3254
|
-
)
|
|
3255
|
-
] = "r2"
|
|
419
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
420
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
421
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
422
|
+
y_data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
423
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None)] = None,
|
|
424
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
425
|
+
model_type: Annotated[str, Field(default="random_forest")] = "random_forest",
|
|
426
|
+
cv_folds: Annotated[int, Field(default=5)] = 5,
|
|
427
|
+
scoring: Annotated[str, Field(default="r2")] = "r2"
|
|
3256
428
|
) -> CallToolResult:
|
|
3257
|
-
"""
|
|
3258
|
-
|
|
3259
|
-
📊 功能说明:
|
|
3260
|
-
通过交叉验证评估模型的泛化能力和稳定性。
|
|
3261
|
-
|
|
3262
|
-
📈 验证方法:
|
|
3263
|
-
- K折交叉验证:将数据分为K份,轮流使用K-1份训练,1份测试
|
|
3264
|
-
- 稳定性评估:通过多次验证评估模型稳定性
|
|
3265
|
-
- 泛化能力:评估模型在未见数据上的表现
|
|
3266
|
-
|
|
3267
|
-
💡 使用场景:
|
|
3268
|
-
- 模型选择和比较
|
|
3269
|
-
- 超参数调优
|
|
3270
|
-
- 评估模型稳定性
|
|
3271
|
-
- 防止过拟合
|
|
3272
|
-
|
|
3273
|
-
⚠️ 注意事项:
|
|
3274
|
-
- 计算成本较高
|
|
3275
|
-
- 需要足够的数据量
|
|
3276
|
-
- 折数选择影响结果稳定性
|
|
3277
|
-
|
|
3278
|
-
Args:
|
|
3279
|
-
y_data: 因变量数据
|
|
3280
|
-
x_data: 自变量数据
|
|
3281
|
-
model_type: 模型类型
|
|
3282
|
-
cv_folds: 交叉验证折数
|
|
3283
|
-
scoring: 评分指标
|
|
3284
|
-
ctx: MCP上下文对象
|
|
3285
|
-
"""
|
|
3286
|
-
await ctx.info(f"开始交叉验证分析,模型类型: {model_type},折数: {cv_folds}")
|
|
3287
|
-
|
|
3288
|
-
try:
|
|
3289
|
-
# 执行交叉验证
|
|
3290
|
-
result = cross_validation(
|
|
3291
|
-
y_data, x_data, model_type, cv_folds, scoring
|
|
3292
|
-
)
|
|
3293
|
-
|
|
3294
|
-
await ctx.info("交叉验证分析完成")
|
|
3295
|
-
|
|
3296
|
-
return CallToolResult(
|
|
3297
|
-
content=[
|
|
3298
|
-
TextContent(
|
|
3299
|
-
type="text",
|
|
3300
|
-
text=f"交叉验证分析结果:\n"
|
|
3301
|
-
f"模型类型 = {result.model_type}\n"
|
|
3302
|
-
f"交叉验证折数 = {result.n_splits}\n"
|
|
3303
|
-
f"平均得分 = {result.mean_score:.4f}\n"
|
|
3304
|
-
f"标准差 = {result.std_score:.4f}\n"
|
|
3305
|
-
f"各折得分 = {[f'{score:.4f}' for score in result.cv_scores]}"
|
|
3306
|
-
)
|
|
3307
|
-
],
|
|
3308
|
-
structuredContent=result.model_dump()
|
|
3309
|
-
)
|
|
3310
|
-
|
|
3311
|
-
except Exception as e:
|
|
3312
|
-
await ctx.error(f"交叉验证分析出错: {str(e)}")
|
|
3313
|
-
return CallToolResult(
|
|
3314
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
3315
|
-
isError=True
|
|
3316
|
-
)
|
|
429
|
+
"""交叉验证 - 支持文件输入"""
|
|
430
|
+
return await handle_cross_validation(ctx, y_data, x_data, model_type, cv_folds, scoring)
|
|
3317
431
|
|
|
3318
432
|
|
|
3319
433
|
@mcp.tool()
|
|
434
|
+
@econometric_tool('regression')
|
|
3320
435
|
async def feature_importance_analysis_tool(
|
|
3321
436
|
ctx: Context[ServerSession, AppContext],
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
- 必须为数值列表
|
|
3331
|
-
- 长度必须与自变量观测数量一致
|
|
3332
|
-
- 不能包含缺失值(NaN)
|
|
3333
|
-
- 建议样本量 >= 30"""
|
|
3334
|
-
)
|
|
3335
|
-
],
|
|
3336
|
-
x_data: Annotated[
|
|
3337
|
-
List[List[float]],
|
|
3338
|
-
Field(
|
|
3339
|
-
description="""自变量数据(解释变量),二维列表格式
|
|
3340
|
-
|
|
3341
|
-
示例格式(4个观测,2个自变量):
|
|
3342
|
-
[
|
|
3343
|
-
[5, 100], # 第1个观测的自变量值
|
|
3344
|
-
[6, 98], # 第2个观测的自变量值
|
|
3345
|
-
[7.5, 95], # 第3个观测的自变量值
|
|
3346
|
-
[6.5, 97] # 第4个观测的自变量值
|
|
3347
|
-
]
|
|
3348
|
-
|
|
3349
|
-
要求:
|
|
3350
|
-
- 外层列表:每个元素代表一个观测
|
|
3351
|
-
- 内层列表:该观测的所有自变量值
|
|
3352
|
-
- 所有观测的自变量数量必须相同
|
|
3353
|
-
- 观测数量必须与y_data长度一致"""
|
|
3354
|
-
)
|
|
3355
|
-
],
|
|
3356
|
-
feature_names: Annotated[
|
|
3357
|
-
Optional[List[str]],
|
|
3358
|
-
Field(
|
|
3359
|
-
default=None,
|
|
3360
|
-
description="""特征名称列表(可选)
|
|
3361
|
-
|
|
3362
|
-
示例:["广告支出", "价格"]
|
|
3363
|
-
|
|
3364
|
-
说明:
|
|
3365
|
-
- 如果不提供,将自动命名为 x1, x2, x3...
|
|
3366
|
-
- 名称数量必须与自变量数量一致
|
|
3367
|
-
- 建议使用有意义的名称以便解释结果"""
|
|
3368
|
-
)
|
|
3369
|
-
] = None,
|
|
3370
|
-
method: Annotated[
|
|
3371
|
-
str,
|
|
3372
|
-
Field(
|
|
3373
|
-
default="random_forest",
|
|
3374
|
-
description="""分析方法
|
|
3375
|
-
|
|
3376
|
-
可选值:
|
|
3377
|
-
- "random_forest": 基于随机森林
|
|
3378
|
-
- "gradient_boosting": 基于梯度提升树
|
|
3379
|
-
|
|
3380
|
-
选择建议:
|
|
3381
|
-
- 一般情况 → random_forest
|
|
3382
|
-
- 高精度需求 → gradient_boosting"""
|
|
3383
|
-
)
|
|
3384
|
-
] = "random_forest",
|
|
3385
|
-
top_k: Annotated[
|
|
3386
|
-
int,
|
|
3387
|
-
Field(
|
|
3388
|
-
default=5,
|
|
3389
|
-
description="""最重要的特征数量
|
|
3390
|
-
|
|
3391
|
-
说明:
|
|
3392
|
-
- 返回重要性排名前k的特征
|
|
3393
|
-
- 默认值:5
|
|
3394
|
-
- 建议范围:3-10
|
|
3395
|
-
- 根据实际需求调整"""
|
|
3396
|
-
)
|
|
3397
|
-
] = 5
|
|
437
|
+
file_path: Annotated[Optional[str], Field(default=None, description="文件路径")] = None,
|
|
438
|
+
file_content: Annotated[Optional[str], Field(default=None)] = None,
|
|
439
|
+
file_format: Annotated[str, Field(default="auto")] = "auto",
|
|
440
|
+
y_data: Annotated[Optional[List[float]], Field(default=None)] = None,
|
|
441
|
+
x_data: Annotated[Optional[List[List[float]]], Field(default=None)] = None,
|
|
442
|
+
feature_names: Annotated[Optional[List[str]], Field(default=None)] = None,
|
|
443
|
+
method: Annotated[str, Field(default="random_forest")] = "random_forest",
|
|
444
|
+
top_k: Annotated[int, Field(default=5)] = 5
|
|
3398
445
|
) -> CallToolResult:
|
|
3399
|
-
"""特征重要性分析
|
|
3400
|
-
|
|
3401
|
-
📊 功能说明:
|
|
3402
|
-
分析各个特征对预测目标的重要性,帮助理解数据中的关键因素。
|
|
3403
|
-
|
|
3404
|
-
📈 分析方法:
|
|
3405
|
-
- 基于模型:使用机器学习模型计算特征重要性
|
|
3406
|
-
- 排序分析:按重要性对特征进行排序
|
|
3407
|
-
- 关键特征识别:识别最重要的top-k个特征
|
|
3408
|
-
|
|
3409
|
-
💡 使用场景:
|
|
3410
|
-
- 特征选择和降维
|
|
3411
|
-
- 模型可解释性分析
|
|
3412
|
-
- 业务洞察提取
|
|
3413
|
-
- 数据理解增强
|
|
3414
|
-
|
|
3415
|
-
⚠️ 注意事项:
|
|
3416
|
-
- 不同方法可能给出不同的重要性排序
|
|
3417
|
-
- 重要性分数是相对的,不是绝对的
|
|
3418
|
-
- 需要结合业务知识解释结果
|
|
446
|
+
"""特征重要性分析 - 支持文件输入"""
|
|
447
|
+
return await handle_feature_importance(ctx, y_data, x_data, feature_names, method, top_k)
|
|
3419
448
|
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
method: 分析方法
|
|
3425
|
-
top_k: 最重要的特征数量
|
|
3426
|
-
ctx: MCP上下文对象
|
|
3427
|
-
"""
|
|
3428
|
-
await ctx.info(f"开始特征重要性分析,分析方法: {method},top_k: {top_k}")
|
|
3429
|
-
|
|
3430
|
-
try:
|
|
3431
|
-
# 执行特征重要性分析
|
|
3432
|
-
result = feature_importance_analysis(
|
|
3433
|
-
y_data, x_data, feature_names, method, top_k
|
|
3434
|
-
)
|
|
3435
|
-
|
|
3436
|
-
await ctx.info("特征重要性分析完成")
|
|
3437
|
-
|
|
3438
|
-
return CallToolResult(
|
|
3439
|
-
content=[
|
|
3440
|
-
TextContent(
|
|
3441
|
-
type="text",
|
|
3442
|
-
text=f"特征重要性分析结果:\n"
|
|
3443
|
-
f"分析方法 = {method}\n"
|
|
3444
|
-
f"最重要的{top_k}个特征 = {result.top_features}\n\n"
|
|
3445
|
-
f"特征重要性排序:\n" + "\n".join([
|
|
3446
|
-
f" {i+1}. {feature}: {importance:.4f}"
|
|
3447
|
-
for i, (feature, importance) in enumerate(result.sorted_features)
|
|
3448
|
-
])
|
|
3449
|
-
)
|
|
3450
|
-
],
|
|
3451
|
-
structuredContent=result.model_dump()
|
|
3452
|
-
)
|
|
3453
|
-
|
|
3454
|
-
except Exception as e:
|
|
3455
|
-
await ctx.error(f"特征重要性分析出错: {str(e)}")
|
|
3456
|
-
return CallToolResult(
|
|
3457
|
-
content=[TextContent(type="text", text=f"错误: {str(e)}")],
|
|
3458
|
-
isError=True
|
|
3459
|
-
)
|
|
449
|
+
|
|
450
|
+
def create_mcp_server() -> FastMCP:
|
|
451
|
+
"""创建并返回MCP服务器实例"""
|
|
452
|
+
return mcp
|