aigroup-econ-mcp 0.4.0__py3-none-any.whl → 1.3.3__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.
@@ -1,1250 +0,0 @@
1
-
2
- """
3
- AIGroup 计量经济学 MCP 服务器
4
- 使用最新的MCP特性提供专业计量经济学分析工具
5
- """
6
-
7
- from typing import List, Dict, Any, Optional, Annotated
8
- from collections.abc import AsyncIterator
9
- from contextlib import asynccontextmanager
10
- from dataclasses import dataclass
11
-
12
- import pandas as pd
13
- import numpy as np
14
- import statsmodels.api as sm
15
- from statsmodels.tsa import stattools
16
- from scipy import stats
17
- from pydantic import BaseModel, Field
18
-
19
- from mcp.server.fastmcp import FastMCP, Context
20
- from mcp.server.session import ServerSession
21
- from mcp.types import CallToolResult, TextContent
22
-
23
-
24
- # 数据模型定义 - 使用Pydantic实现结构化输出
25
- class DescriptiveStatsResult(BaseModel):
26
- """描述性统计结果"""
27
- count: int = Field(description="样本数量")
28
- mean: float = Field(description="均值")
29
- std: float = Field(description="标准差")
30
- min: float = Field(description="最小值")
31
- max: float = Field(description="最大值")
32
- median: float = Field(description="中位数")
33
- skewness: float = Field(description="偏度")
34
- kurtosis: float = Field(description="峰度")
35
-
36
-
37
- class OLSRegressionResult(BaseModel):
38
- """OLS回归分析结果"""
39
- rsquared: float = Field(description="R²")
40
- rsquared_adj: float = Field(description="调整R²")
41
- f_statistic: float = Field(description="F统计量")
42
- f_pvalue: float = Field(description="F检验p值")
43
- aic: float = Field(description="AIC信息准则")
44
- bic: float = Field(description="BIC信息准则")
45
- coefficients: Dict[str, Dict[str, float]] = Field(description="回归系数详情")
46
-
47
-
48
- class HypothesisTestResult(BaseModel):
49
- """假设检验结果"""
50
- test_type: str = Field(description="检验类型")
51
- statistic: float = Field(description="检验统计量")
52
- p_value: float = Field(description="p值")
53
- significant: bool = Field(description="是否显著(5%水平)")
54
- confidence_interval: Optional[List[float]] = Field(default=None, description="置信区间")
55
-
56
-
57
- class TimeSeriesStatsResult(BaseModel):
58
- """时间序列统计结果"""
59
- adf_statistic: float = Field(description="ADF检验统计量")
60
- adf_pvalue: float = Field(description="ADF检验p值")
61
- stationary: bool = Field(description="是否平稳")
62
- acf: List[float] = Field(description="自相关函数")
63
- pacf: List[float] = Field(description="偏自相关函数")
64
-
65
-
66
- # 应用上下文
67
- @dataclass
68
- class AppContext:
69
- """应用上下文,包含共享资源"""
70
- config: Dict[str, Any]
71
- version: str = "0.1.0"
72
-
73
-
74
- # 服务器图标(已移除,因为MCP库不再支持Icon类)
75
-
76
-
77
- @asynccontextmanager
78
- async def lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
79
- """服务器生命周期管理"""
80
- # 启动时初始化资源
81
- config = {
82
- "max_sample_size": 10000,
83
- "default_significance_level": 0.05,
84
- "supported_tests": ["t_test", "f_test", "chi_square", "adf"],
85
- "data_types": ["cross_section", "time_series", "panel"]
86
- }
87
-
88
- try:
89
- yield AppContext(config=config, version="0.1.0")
90
- finally:
91
- # 清理资源
92
- pass
93
-
94
-
95
- # 创建MCP服务器实例
96
- mcp = FastMCP(
97
- name="aigroup-econ-mcp",
98
- instructions="Econometrics MCP Server - Provides data analysis, regression analysis, hypothesis testing and more",
99
- lifespan=lifespan
100
- )
101
-
102
-
103
- @mcp.resource("dataset://sample/{dataset_name}")
104
- def get_sample_dataset(dataset_name: str) -> str:
105
- """Get sample dataset"""
106
- datasets = {
107
- "economic_growth": """
108
- GDP Growth,Inflation Rate,Unemployment Rate,Investment Rate
109
- 3.2,2.1,4.5,15.2
110
- 2.8,2.3,4.2,14.8
111
- 3.5,1.9,4.0,16.1
112
- 2.9,2.4,4.3,15.5
113
- """,
114
- "stock_returns": """
115
- Stock A,Stock B,Stock C
116
- 0.02,-0.01,0.015
117
- -0.015,0.025,-0.008
118
- 0.018,-0.005,0.012
119
- """,
120
- "time_series": """
121
- Date,Sales,Advertising Expense
122
- 2023-01,12000,800
123
- 2023-02,13500,900
124
- 2023-03,11800,750
125
- 2023-04,14200,1000
126
- """
127
- }
128
-
129
- if dataset_name not in datasets:
130
- return f"Available datasets: {', '.join(datasets.keys())}"
131
-
132
- return datasets[dataset_name]
133
-
134
-
135
- @mcp.prompt(title="Economic Data Analysis")
136
- def economic_analysis_prompt(data_description: str, analysis_type: str = "descriptive") -> str:
137
- """Economic data analysis prompt template"""
138
- prompts = {
139
- "descriptive": "Please perform descriptive statistical analysis on the following economic data:",
140
- "regression": "Please perform regression analysis on the following economic data to identify key factors:",
141
- "hypothesis": "Please perform hypothesis testing on the following economic data to verify research assumptions:",
142
- "time_series": "Please analyze the following time series data to check stationarity and correlation:"
143
- }
144
-
145
- return f"{prompts.get(analysis_type, prompts['descriptive'])}\n\nData description: {data_description}"
146
-
147
-
148
- @mcp.tool()
149
- async def descriptive_statistics(
150
- ctx: Context[ServerSession, AppContext],
151
- data: Annotated[
152
- Dict[str, List[float]],
153
- Field(
154
- description="""数据字典,格式为 {变量名: [数值列表]}
155
-
156
- 示例格式:
157
- {
158
- "GDP增长率": [3.2, 2.8, 3.5, 2.9],
159
- "通货膨胀率": [2.1, 2.3, 1.9, 2.4],
160
- "失业率": [4.5, 4.2, 4.0, 4.3]
161
- }
162
-
163
- 要求:
164
- - 至少包含一个变量
165
- - 每个变量的数据点数量应相同
166
- - 数值必须为浮点数或整数
167
- - 建议样本量 >= 30 以获得可靠的统计推断"""
168
- )
169
- ]
170
- ) -> CallToolResult:
171
- """计算描述性统计量
172
-
173
- 📊 功能说明:
174
- 对输入数据进行全面的描述性统计分析,包括集中趋势、离散程度、分布形状等指标。
175
-
176
- 📈 输出指标:
177
- - 样本数量 (count)
178
- - 均值 (mean):数据的平均水平
179
- - 标准差 (std):数据的离散程度
180
- - 最小值/最大值 (min/max):数据的取值范围
181
- - 中位数 (median):数据的中间值,对异常值不敏感
182
- - 偏度 (skewness):分布的对称性,0表示对称,>0右偏,<0左偏
183
- - 峰度 (kurtosis):分布的尖峭程度,0表示正态分布
184
- - 相关系数矩阵:变量间的线性相关关系
185
-
186
- 💡 使用场景:
187
- - 初步了解数据的分布特征
188
- - 检查数据质量和异常值
189
- - 为后续建模提供基础信息
190
- - 比较不同变量的统计特征
191
-
192
- ⚠️ 注意事项:
193
- - 偏度绝对值 > 1 表示数据明显偏斜,可能需要转换
194
- - 峰度绝对值 > 3 表示尖峭或扁平分布
195
- - 相关系数 > 0.8 表示强相关,可能存在多重共线性
196
-
197
- Args:
198
- data: 数据字典,键为变量名,值为数值列表
199
- ctx: MCP上下文对象
200
- """
201
- await ctx.info(f"开始计算描述性统计,处理 {len(data)} 个变量")
202
-
203
- try:
204
- # 数据验证
205
- if not data:
206
- raise ValueError("数据不能为空")
207
-
208
- df = pd.DataFrame(data)
209
-
210
- # 检查数据一致性
211
- if len(df.columns) == 0:
212
- raise ValueError("至少需要一个变量")
213
-
214
- # 基础统计量 - 修复:返回所有变量的综合统计
215
- result = DescriptiveStatsResult(
216
- count=len(df),
217
- mean=df.mean().mean(), # 所有变量的均值
218
- std=df.std().mean(), # 所有变量的标准差均值
219
- min=df.min().min(), # 所有变量的最小值
220
- max=df.max().max(), # 所有变量的最大值
221
- median=df.median().mean(), # 所有变量的中位数均值
222
- skewness=df.skew().mean(), # 所有变量的偏度均值
223
- kurtosis=df.kurtosis().mean() # 所有变量的峰度均值
224
- )
225
-
226
- # 计算相关系数矩阵
227
- correlation_matrix = df.corr().round(4)
228
-
229
- await ctx.info(f"描述性统计计算完成,样本大小: {len(df)}")
230
-
231
- return CallToolResult(
232
- content=[
233
- TextContent(
234
- type="text",
235
- text=f"描述性统计结果:\n"
236
- f"均值: {result.mean:.4f}\n"
237
- f"标准差: {result.std:.4f}\n"
238
- f"最小值: {result.min:.4f}\n"
239
- f"最大值: {result.max:.4f}\n"
240
- f"中位数: {result.median:.4f}\n"
241
- f"偏度: {result.skewness:.4f}\n"
242
- f"峰度: {result.kurtosis:.4f}\n\n"
243
- f"相关系数矩阵:\n{correlation_matrix.to_string()}"
244
- )
245
- ],
246
- structuredContent=result.model_dump()
247
- )
248
-
249
- except Exception as e:
250
- await ctx.error(f"计算描述性统计时出错: {str(e)}")
251
- return CallToolResult(
252
- content=[TextContent(type="text", text=f"错误: {str(e)}")],
253
- isError=True
254
- )
255
-
256
-
257
- @mcp.tool()
258
- async def ols_regression(
259
- ctx: Context[ServerSession, AppContext],
260
- y_data: Annotated[
261
- List[float],
262
- Field(
263
- description="""因变量数据(被解释变量/响应变量)
264
-
265
- 示例:[12000, 13500, 11800, 14200, 15100]
266
-
267
- 要求:
268
- - 必须为数值列表
269
- - 长度必须与自变量观测数量一致
270
- - 不能包含缺失值(NaN)
271
- - 建议样本量 >= 30"""
272
- )
273
- ],
274
- x_data: Annotated[
275
- List[List[float]],
276
- Field(
277
- description="""自变量数据(解释变量/预测变量),二维列表格式
278
-
279
- 示例格式(3个观测,2个自变量):
280
- [
281
- [800, 5.2], # 第1个观测的自变量值
282
- [900, 5.8], # 第2个观测的自变量值
283
- [750, 4.9] # 第3个观测的自变量值
284
- ]
285
-
286
- 要求:
287
- - 外层列表:每个元素代表一个观测
288
- - 内层列表:该观测的所有自变量值
289
- - 所有观测的自变量数量必须相同
290
- - 观测数量必须与y_data长度一致
291
- - 自变量数量建议 < 观测数量/10(避免过拟合)"""
292
- )
293
- ],
294
- feature_names: Annotated[
295
- Optional[List[str]],
296
- Field(
297
- default=None,
298
- description="""自变量名称列表(可选)
299
-
300
- 示例:["广告支出", "价格指数"]
301
-
302
- 说明:
303
- - 如果不提供,将自动命名为 x1, x2, x3...
304
- - 名称数量必须与自变量数量一致
305
- - 建议使用有意义的名称以便解释结果"""
306
- )
307
- ] = None
308
- ) -> CallToolResult:
309
- """执行普通最小二乘法(OLS)回归分析
310
-
311
- 📊 功能说明:
312
- 使用最小二乘法估计线性回归模型,分析因变量与自变量之间的线性关系。
313
- 模型形式:Y = β₀ + β₁X₁ + β₂X₂ + ... + βₖXₖ + ε
314
-
315
- 📈 输出指标:
316
- - R²:决定系数,取值0-1,衡量模型拟合优度
317
- - 调整R²:考虑自变量数量的修正R²
318
- - F统计量及p值:检验模型整体显著性
319
- - AIC/BIC:信息准则,用于模型比较,越小越好
320
- - 回归系数:每个自变量的估计值、标准误、t统计量、p值、置信区间
321
-
322
- 💡 使用场景:
323
- - 因果关系分析(如广告支出对销售额的影响)
324
- - 预测建模(如根据经济指标预测GDP)
325
- - 控制变量分析(如研究教育回报率时控制工作经验)
326
- - 假设检验(如检验某变量是否对结果有显著影响)
327
-
328
- ⚠️ 注意事项:
329
- - R² > 0.7 表示拟合良好,但需警惕过拟合
330
- - p值 < 0.05 表示该系数在5%水平显著
331
- - 需检查残差的正态性、同方差性和独立性假设
332
- - 自变量间高度相关(相关系数>0.8)可能导致多重共线性问题
333
- - 样本量过小可能导致不可靠的估计结果
334
-
335
- Args:
336
- y_data: 因变量数据
337
- x_data: 自变量数据,每行一个观测
338
- feature_names: 自变量名称(可选)
339
- ctx: MCP上下文对象
340
- """
341
- await ctx.info(f"开始OLS回归分析,样本大小: {len(y_data)},自变量数量: {len(x_data[0]) if x_data else 0}")
342
-
343
- try:
344
- # 数据验证
345
- if not y_data:
346
- raise ValueError("因变量数据不能为空")
347
- if not x_data:
348
- raise ValueError("自变量数据不能为空")
349
- if len(y_data) != len(x_data):
350
- raise ValueError(f"因变量和自变量的观测数量不一致: y_data={len(y_data)}, x_data={len(x_data)}")
351
-
352
- # 准备数据
353
- X = np.array(x_data)
354
- y = np.array(y_data)
355
-
356
- # 添加常数项
357
- X_with_const = sm.add_constant(X)
358
-
359
- # 拟合模型
360
- model = sm.OLS(y, X_with_const).fit()
361
-
362
- # 构建系数字典
363
- conf_int = model.conf_int()
364
- coefficients = {}
365
-
366
- # 修复:正确处理feature_names为None的情况
367
- if feature_names is None:
368
- feature_names = [f"x{i+1}" for i in range(X.shape[1])]
369
- elif len(feature_names) != X.shape[1]:
370
- await ctx.warning(f"提供的feature_names数量({len(feature_names)})与自变量数量({X.shape[1]})不匹配,使用默认命名")
371
- feature_names = [f"x{i+1}" for i in range(X.shape[1])]
372
-
373
- for i, coef in enumerate(model.params):
374
- if i == 0:
375
- var_name = "const"
376
- else:
377
- var_name = feature_names[i-1]
378
-
379
- coefficients[var_name] = {
380
- "coef": float(coef), # 转换numpy.float64为float
381
- "std_err": float(model.bse[i]),
382
- "t_value": float(model.tvalues[i]),
383
- "p_value": float(model.pvalues[i]),
384
- "ci_lower": float(conf_int[i][0]),
385
- "ci_upper": float(conf_int[i][1])
386
- }
387
-
388
- # 构建结果
389
- result = OLSRegressionResult(
390
- rsquared=float(model.rsquared),
391
- rsquared_adj=float(model.rsquared_adj),
392
- f_statistic=float(model.fvalue),
393
- f_pvalue=float(model.f_pvalue),
394
- aic=float(model.aic),
395
- bic=float(model.bic),
396
- coefficients=coefficients
397
- )
398
-
399
- await ctx.info("OLS回归分析完成")
400
-
401
- return CallToolResult(
402
- content=[
403
- TextContent(
404
- type="text",
405
- text=f"OLS回归分析结果:\n"
406
- f"R² = {result.rsquared:.4f}\n"
407
- f"调整R² = {result.rsquared_adj:.4f}\n"
408
- f"F统计量 = {result.f_statistic:.4f} (p = {result.f_pvalue:.4f})\n"
409
- f"AIC = {result.aic:.2f}, BIC = {result.bic:.2f}\n\n"
410
- f"回归系数:\n{model.summary().tables[1]}"
411
- )
412
- ],
413
- structuredContent=result.model_dump()
414
- )
415
-
416
- except Exception as e:
417
- await ctx.error(f"OLS回归分析出错: {str(e)}")
418
- return CallToolResult(
419
- content=[TextContent(type="text", text=f"错误: {str(e)}")],
420
- isError=True
421
- )
422
-
423
-
424
- @mcp.tool()
425
- async def hypothesis_testing(
426
- ctx: Context[ServerSession, AppContext],
427
- data1: Annotated[
428
- List[float],
429
- Field(
430
- description="""第一组数据或单一样本数据
431
-
432
- 示例:[3.2, 2.8, 3.5, 2.9, 3.1, 2.7, 3.3]
433
-
434
- 要求:
435
- - 必须为数值列表
436
- - 不能包含缺失值
437
- - 建议样本量 >= 30(大样本)
438
- - t检验要求数据近似正态分布"""
439
- )
440
- ],
441
- data2: Annotated[
442
- Optional[List[float]],
443
- Field(
444
- default=None,
445
- description="""第二组数据(可选,用于双样本检验)
446
-
447
- 示例:[2.5, 2.9, 2.3, 2.6, 2.8]
448
-
449
- 说明:
450
- - 仅在双样本t检验时需要提供
451
- - 单样本t检验时保持为None
452
- - 两组数据可以
453
- 有不同的样本量
454
- - ADF检验不需要第二组数据"""
455
- )
456
- ] = None,
457
- test_type: Annotated[
458
- str,
459
- Field(
460
- default="t_test",
461
- description="""假设检验类型
462
-
463
- 可选值:
464
- - "t_test": t检验(默认)
465
- * 单样本t检验:检验样本均值是否等于0(data2=None)
466
- * 双样本t检验:检验两组样本均值是否相等(提供data2)
467
-
468
- - "adf": 增强迪基-富勒检验(Augmented Dickey-Fuller Test)
469
- * 用于检验时间序列的平稳性
470
- * 原假设:存在单位根(非平稳)
471
- * p<0.05 拒绝原假设,序列平稳
472
-
473
- 使用建议:
474
- - 比较均值差异 → 使用 t_test
475
- - 检验时间序列平稳性 → 使用 adf"""
476
- )
477
- ] = "t_test"
478
- ) -> CallToolResult:
479
- """执行统计假设检验
480
-
481
- 📊 功能说明:
482
- 对数据进行统计假设检验,判断样本是否支持某个统计假设。
483
-
484
- 📈 检验类型详解:
485
-
486
- 1️⃣ t检验 (t_test):
487
- - 单样本:H₀: μ = 0 vs H₁: μ ≠ 0
488
- - 双样本:H₀: μ₁ = μ₂ vs H₁: μ₁ ≠ μ₂
489
- - 适用于小样本(n<30)且数据近似正态分布
490
-
491
- 2️⃣ ADF检验 (adf):
492
- - H₀: 序列存在单位根(非平稳)
493
- - H₁: 序列不存在单位根(平稳)
494
- - 用于时间序列分析前的平稳性检验
495
-
496
- 📊 输出指标:
497
- - 检验统计量:用于判断是否拒绝原假设
498
- - p值:显著性水平,<0.05表示在5%水平显著
499
- - 是否显著:基于5%显著性水平的判断
500
- - 置信区间:参数的可能取值范围(仅t检验)
501
-
502
- 💡 使用场景:
503
- - 检验新药是否有效(单样本t检验)
504
- - 比较两种教学方法的效果差异(双样本t检验)
505
- - 检验股价序列是否平稳(ADF检验)
506
- - 验证经济理论假说(如购买力平价理论)
507
-
508
- ⚠️ 注意事项:
509
- - p值 < 0.05:拒绝原假设(结果显著)
510
- - p值 >= 0.05:不能拒绝原假设(结果不显著)
511
- - t检验要求数据近似正态分布
512
- - 小样本(<30)时t检验结果可能不可靠
513
- - ADF检验中p<0.05表示序列平稳(拒绝非平稳假设)
514
-
515
- Args:
516
- data1: 第一组数据
517
- data2: 第二组数据(可选,用于双样本检验)
518
- test_type: 检验类型(t_test或adf)
519
- ctx: MCP上下文对象
520
- """
521
- await ctx.info(f"开始假设检验: {test_type}")
522
-
523
- try:
524
- if test_type == "t_test":
525
- if data2 is None:
526
- # 单样本t检验
527
- result = stats.ttest_1samp(data1, 0)
528
- ci = stats.t.interval(0.95, len(data1)-1, loc=np.mean(data1), scale=stats.sem(data1))
529
- else:
530
- # 双样本t检验
531
- result = stats.ttest_ind(data1, data2)
532
- ci = None # 双样本t检验不计算置信区间
533
-
534
- test_result = HypothesisTestResult(
535
- test_type=test_type,
536
- statistic=result.statistic,
537
- p_value=result.pvalue,
538
- significant=result.pvalue < 0.05,
539
- confidence_interval=list(ci) if ci else None
540
- )
541
-
542
- elif test_type == "adf":
543
- # ADF单位根检验
544
- result = stattools.adfuller(data1)
545
- test_result = HypothesisTestResult(
546
- test_type="adf",
547
- statistic=result[0],
548
- p_value=result[1],
549
- significant=result[1] < 0.05,
550
- confidence_interval=None
551
- )
552
- else:
553
- raise ValueError(f"不支持的检验类型: {test_type}")
554
-
555
- await ctx.info(f"假设检验完成: {test_type}")
556
-
557
- return CallToolResult(
558
- content=[
559
- TextContent(
560
- type="text",
561
- text=f"{test_type.upper()}检验结果:\n"
562
- f"检验统计量 = {test_result.statistic:.4f}\n"
563
- f"p值 = {test_result.p_value:.4f}\n"
564
- f"{'显著' if test_result.significant else '不显著'} (5%水平)\n"
565
- f"{f'95%置信区间: [{test_result.confidence_interval[0]:.4f}, {test_result.confidence_interval[1]:.4f}]' if test_result.confidence_interval else ''}"
566
- )
567
- ],
568
- structuredContent=test_result.model_dump()
569
- )
570
-
571
- except Exception as e:
572
- await ctx.error(f"假设检验出错: {str(e)}")
573
- return CallToolResult(
574
- content=[TextContent(type="text", text=f"错误: {str(e)}")],
575
- isError=True
576
- )
577
-
578
-
579
- @mcp.tool()
580
- async def time_series_analysis(
581
- ctx: Context[ServerSession, AppContext],
582
- data: Annotated[
583
- List[float],
584
- Field(
585
- description="""时间序列数据(按时间顺序排列)
586
-
587
- 示例格式:
588
- [12000, 13500, 11800, 14200, 15100, 14800, 16200, 15900]
589
- # 表示连续8期的观测值,如月度销售额
590
-
591
- 要求:
592
- - 必须按时间顺序排列(从早到晚)
593
- - 建议至少30个观测点以获得可靠结果
594
- - 数据应等间隔采样(如日度、月度、季度)
595
- - 不能包含缺失值
596
- - 数据量越大,ACF/PACF分析越准确
597
-
598
- 应用示例:
599
- - 股票价格序列
600
- - GDP季度数据
601
- - 月度销售额
602
- - 日均气温数据"""
603
- )
604
- ]
605
- ) -> CallToolResult:
606
- """时间序列统计分析
607
-
608
- 📊 功能说明:
609
- 对时间序列数据进行全面的统计分析,包括平稳性检验和自相关分析。
610
-
611
- 📈 分析内容:
612
-
613
- 1️⃣ ADF单位根检验(Augmented Dickey-Fuller Test):
614
- - 检验序列是否平稳
615
- - H₀: 存在单位根(序列非平稳)
616
- - p < 0.05:拒绝原假设,序列平稳
617
- - 平稳性是时间序列建模的基础
618
-
619
- 2️⃣ 自相关函数(ACF):
620
- - 衡量序列与其滞后值之间的相关性
621
- - 用于识别MA模型的阶数
622
- - 指数衰减→AR过程;q阶截尾→MA(q)过程
623
-
624
- 3️⃣ 偏自相关函数(PACF):
625
- - 剔除中间滞后项影响后的相关性
626
- - 用于识别AR模型的阶数
627
- - p阶截尾→AR(p)过程
628
-
629
- 📊 输出指标:
630
- - ADF统计量:越负越可能平稳
631
- - ADF p值:<0.05表示序列平稳
632
- - 平稳性判断:基于5%显著性水平
633
- - ACF值:前20阶(或更少)的自相关系数
634
- - PACF值:前20阶(或更少)的偏自相关系数
635
-
636
- 💡 使用场景:
637
- - ARIMA建模前的平稳性检验
638
- - 识别合适的时间序列模型(AR、MA、ARMA)
639
- - 检测季节性和趋势
640
- - 评估序列的记忆性和持续性
641
-
642
- ⚠️ 注意事项:
643
- - 非平稳序列需要差分或变换后才能建模
644
- - ACF和PACF应结合使用以识别模型类型
645
- - 数据点太少(<30)可能导致不可靠的结果
646
- - 强烈的季节性可能影响ACF/PACF的解读
647
- - 建议同时观察ACF/PACF图形以获得更好的直观理解
648
-
649
- 📖 结果解读:
650
- - ADF p值 < 0.05 + ACF快速衰减 → 平稳序列,可直接建模
651
- - ADF p值 >= 0.05 → 非平稳序列,需要差分处理
652
- - PACF在p阶截尾 → 考虑AR(p)模型
653
- - ACF在q阶截尾 → 考虑MA(q)模型
654
- - ACF和PACF都衰减 → 考虑ARMA模型
655
-
656
- Args:
657
- data: 时间序列数据(按时间顺序)
658
- ctx: MCP上下文对象
659
- """
660
- await ctx.info(f"开始时间序列分析,数据点数量: {len(data)}")
661
-
662
- try:
663
- # 数据验证
664
- if not data:
665
- raise ValueError("时间序列数据不能为空")
666
- if len(data) < 5:
667
- raise ValueError("时间序列数据至少需要5个观测点")
668
-
669
- # ADF单位根检验
670
- adf_result = stattools.adfuller(data)
671
-
672
- # 自相关和偏自相关函数
673
- # 修复:安全计算nlags,避免PACF计算失败
674
- max_nlags = min(20, len(data) - 1, len(data) // 2)
675
- if max_nlags < 1:
676
- max_nlags = 1 # 确保至少计算1阶
677
-
678
- # 修复:使用try-except处理ACF/PACF计算可能失败的情况
679
- try:
680
- acf_values = stattools.acf(data, nlags=max_nlags)
681
- pacf_values = stattools.pacf(data, nlags=max_nlags)
682
- except Exception as acf_error:
683
- await ctx.warning(f"ACF/PACF计算遇到问题: {str(acf_error)},使用简化计算")
684
- # 使用更简单的计算方法
685
- acf_values = np.zeros(max_nlags + 1)
686
- pacf_values = np.zeros(max_nlags + 1)
687
- acf_values[0] = 1.0 # 0阶自相关总是1
688
- pacf_values[0] = 1.0 # 0阶偏自相关总是1
689
-
690
- # 转换numpy类型为Python原生类型
691
- result = TimeSeriesStatsResult(
692
- adf_statistic=float(adf_result[0]),
693
- adf_pvalue=float(adf_result[1]),
694
- stationary=bool(adf_result[1] < 0.05),
695
- acf=[float(x) for x in acf_values.tolist()],
696
- pacf=[float(x) for x in pacf_values.tolist()]
697
- )
698
-
699
- await ctx.info("时间序列分析完成")
700
-
701
- return CallToolResult(
702
- content=[
703
- TextContent(
704
- type="text",
705
- text=f"时间序列分析结果:\n"
706
- f"ADF检验统计量 = {result.adf_statistic:.4f}\n"
707
- f"ADF检验p值 = {result.adf_pvalue:.4f}\n"
708
- f"{'平稳' if result.stationary else '非平稳'}序列\n"
709
- f"ACF前5阶: {result.acf[:5]}\n"
710
- f"PACF前5阶: {result.pacf[:5]}"
711
- )
712
- ],
713
- structuredContent=result.model_dump()
714
- )
715
-
716
- except Exception as e:
717
- await ctx.error(f"时间序列分析出错: {str(e)}")
718
- return CallToolResult(
719
- content=[TextContent(type="text", text=f"错误: {str(e)}")],
720
- isError=True
721
- )
722
-
723
-
724
- @mcp.tool()
725
- async def correlation_analysis(
726
- ctx: Context[ServerSession, AppContext],
727
- data: Annotated[
728
- Dict[str, List[float]],
729
- Field(
730
- description="""多变量数据字典
731
-
732
- 示例格式:
733
- {
734
- "销售额": [12000, 13500, 11800, 14200],
735
- "广告支出": [800, 900, 750, 1000],
736
- "价格": [99, 95, 102, 98],
737
- "竞争对手数量": [3, 3, 4, 3]
738
- }
739
-
740
- 要求:
741
- - 至少包含2个变量
742
- - 所有变量的数据点数量必须相同
743
- - 建议样本量 >= 30
744
- - 数值不能包含缺失值
745
-
746
- 应用:
747
- - 探索变量间的关联关系
748
- - 识别潜在的多重共线性
749
- - 为回归分析筛选变量"""
750
- )
751
- ],
752
- method: Annotated[
753
- str,
754
- Field(
755
- default="pearson",
756
- description="""相关系数计算方法
757
-
758
- 可选值:
759
- - "pearson": 皮尔逊相关系数(默认)
760
- * 衡量线性相关关系
761
- * 取值范围:-1到1
762
- * 要求:数据近似正态分布
763
- * 对异常值敏感
764
-
765
- - "spearman": 斯皮尔曼秩相关系数
766
- * 衡量单调相关关系(不要求线性)
767
- * 基于数据的秩次
768
- * 对异常值不敏感
769
- * 适用于非正态分布
770
-
771
- - "kendall": 肯德尔τ相关系数
772
- * 衡量一致性程度
773
- * 更稳健但计算较慢
774
- * 适用于小样本和有序数据
775
-
776
- 选择建议:
777
- - 数据正态分布 + 关注线性关系 → pearson
778
- - 数据有异常值或非正态 → spearman
779
- - 有序分类数据 → kendall"""
780
- )
781
- ] = "pearson"
782
- ) -> CallToolResult:
783
- """变量间相关性分析
784
-
785
- 📊 功能说明:
786
- 计算多个变量之间的相关系数矩阵,揭示变量间的关联关系强度和方向。
787
-
788
- 📈 相关系数解读:
789
- - 相关系数范围:-1 到 +1
790
- - |r| = 0.0-0.3:弱相关或无相关
791
- - |r| = 0.3-0.7:中等程度相关
792
- - |r| = 0.7-1.0:强相关
793
- - r > 0:正相关(同向变化)
794
- - r < 0:负相关(反向变化)
795
- - r = 0:无线性相关
796
-
797
- 💡 使用场景:
798
- - 探索性数据分析(EDA)
799
- - 回归分析前的变量筛选
800
- - 识别多重共线性问题
801
- - 构建投资组合(寻找低相关资产)
802
- - 因子分析和主成分分析的前置步骤
803
-
804
- ⚠️ 注意事项:
805
- - 相关≠因果:高相关不代表因果关系
806
- - 皮尔逊相关仅衡量线性关系,可能错过非线性关系
807
- - 异常值会显著影响皮尔逊相关系数
808
- - 回归分析中,自变量间相关系数>0.8可能导致多重共线性
809
- - 小样本(<30)的相关系数可能不稳定
810
-
811
- 📖 实际应用示例:
812
- - 营销分析:广告支出与销售额的相关性
813
- - 金融分析:不同股票收益率之间的相关性
814
- - 经济研究:GDP增长与失业率的关系
815
- - 多重共线性检测:回归模型中自变量间的相关性
816
-
817
- Args:
818
- data: 变量数据字典
819
- method: 相关系数类型(pearson/spearman/kendall)
820
- ctx: MCP上下文对象
821
- """
822
- await ctx.info(f"开始相关性分析: {method}")
823
-
824
- try:
825
- # 数据验证
826
- if not data:
827
- raise ValueError("数据不能为空")
828
- if len(data) < 2:
829
- raise ValueError("至少需要2个变量进行相关性分析")
830
-
831
- df = pd.DataFrame(data)
832
- correlation_matrix = df.corr(method=method)
833
-
834
- await ctx.info("相关性分析完成")
835
-
836
- # 修复:返回正确的CallToolResult类型
837
- return CallToolResult(
838
- content=[
839
- TextContent(
840
- type="text",
841
- text=f"{method.title()}相关系数矩阵:\n{correlation_matrix.round(4).to_string()}"
842
- )
843
- ]
844
- )
845
-
846
- except Exception as e:
847
- await ctx.error(f"相关性分析出错: {str(e)}")
848
- return CallToolResult(
849
- content=[TextContent(type="text", text=f"错误: {str(e)}")],
850
- isError=True
851
- )
852
-
853
- # 导入面板数据分析工具
854
- from .tools.panel_data import (
855
- FixedEffectsResult,
856
- RandomEffectsResult,
857
- HausmanTestResult,
858
- PanelUnitRootResult,
859
- fixed_effects_model,
860
- random_effects_model,
861
- hausman_test,
862
- panel_unit_root_test as panel_unit_root_test_impl
863
- )
864
-
865
- # 导入高级时间序列分析工具
866
- from .tools.time_series import (
867
- VARModelResult,
868
- VECMModelResult,
869
- GARCHModelResult,
870
- StateSpaceModelResult,
871
- var_model,
872
- vecm_model,
873
- garch_model,
874
- state_space_model,
875
- variance_decomposition
876
- )
877
-
878
- # 导入机器学习工具
879
- from .tools.machine_learning import (
880
- RandomForestResult,
881
- GradientBoostingResult,
882
- RegularizedRegressionResult,
883
- CrossValidationResult,
884
- FeatureImportanceResult,
885
- random_forest_regression,
886
- gradient_boosting_regression,
887
- lasso_regression,
888
- ridge_regression,
889
- cross_validation,
890
- feature_importance_analysis
891
- )
892
-
893
-
894
- # ============================================================================
895
- # 面板数据分析工具
896
- # ============================================================================
897
-
898
- @mcp.tool()
899
- async def panel_fixed_effects(
900
- ctx: Context[ServerSession, AppContext],
901
- y_data: Annotated[List[float], Field(description="因变量数据")],
902
- x_data: Annotated[List[List[float]], Field(description="自变量数据")],
903
- entity_ids: Annotated[List[str], Field(description="个体标识符")],
904
- time_periods: Annotated[List[str], Field(description="时间标识符")],
905
- feature_names: Annotated[Optional[List[str]], Field(default=None, description="自变量名称")] = None,
906
- entity_effects: Annotated[bool, Field(default=True, description="是否包含个体效应")] = True,
907
- time_effects: Annotated[bool, Field(default=False, description="是否包含时间效应")] = False
908
- ) -> CallToolResult:
909
- """固定效应模型分析"""
910
- await ctx.info(f"开始固定效应模型分析,样本大小: {len(y_data)}")
911
- try:
912
- result = fixed_effects_model(y_data, x_data, entity_ids, time_periods, feature_names, entity_effects, time_effects)
913
- await ctx.info("固定效应模型分析完成")
914
- return CallToolResult(
915
- content=[TextContent(type="text", text=f"固定效应模型: R²={result.rsquared:.4f}")],
916
- structuredContent=result.model_dump()
917
- )
918
- except Exception as e:
919
- await ctx.error(f"固定效应模型分析出错: {str(e)}")
920
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
921
-
922
-
923
- @mcp.tool()
924
- async def panel_random_effects(
925
- ctx: Context[ServerSession, AppContext],
926
- y_data: Annotated[List[float], Field(description="因变量数据")],
927
- x_data: Annotated[List[List[float]], Field(description="自变量数据")],
928
- entity_ids: Annotated[List[str], Field(description="个体标识符")],
929
- time_periods: Annotated[List[str], Field(description="时间标识符")],
930
- feature_names: Annotated[Optional[List[str]], Field(default=None, description="自变量名称")] = None,
931
- entity_effects: Annotated[bool, Field(default=True, description="是否包含个体效应")] = True,
932
- time_effects: Annotated[bool, Field(default=False, description="是否包含时间效应")] = False
933
- ) -> CallToolResult:
934
- """随机效应模型分析"""
935
- await ctx.info(f"开始随机效应模型分析,样本大小: {len(y_data)}")
936
- try:
937
- result = random_effects_model(y_data, x_data, entity_ids, time_periods, feature_names, entity_effects, time_effects)
938
- await ctx.info("随机效应模型分析完成")
939
- return CallToolResult(
940
- content=[TextContent(type="text", text=f"随机效应模型: R²={result.rsquared:.4f}")],
941
- structuredContent=result.model_dump()
942
- )
943
- except Exception as e:
944
- await ctx.error(f"随机效应模型分析出错: {str(e)}")
945
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
946
-
947
-
948
- @mcp.tool()
949
- async def panel_hausman_test(
950
- ctx: Context[ServerSession, AppContext],
951
- y_data: Annotated[List[float], Field(description="因变量数据")],
952
- x_data: Annotated[List[List[float]], Field(description="自变量数据")],
953
- entity_ids: Annotated[List[str], Field(description="个体标识符")],
954
- time_periods: Annotated[List[str], Field(description="时间标识符")],
955
- feature_names: Annotated[Optional[List[str]], Field(default=None, description="自变量名称")] = None
956
- ) -> CallToolResult:
957
- """Hausman检验"""
958
- await ctx.info(f"开始Hausman检验,样本大小: {len(y_data)}")
959
- try:
960
- result = hausman_test(y_data, x_data, entity_ids, time_periods, feature_names)
961
- await ctx.info("Hausman检验完成")
962
- return CallToolResult(
963
- content=[TextContent(type="text", text=f"Hausman检验: p={result.p_value:.4f}, 建议={result.recommendation}")],
964
- structuredContent=result.model_dump()
965
- )
966
- except Exception as e:
967
- await ctx.error(f"Hausman检验出错: {str(e)}")
968
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
969
-
970
-
971
- @mcp.tool()
972
- async def panel_unit_root_test(
973
- ctx: Context[ServerSession, AppContext],
974
- data: Annotated[List[float], Field(description="面板数据序列")],
975
- entity_ids: Annotated[List[str], Field(description="个体标识符")],
976
- time_periods: Annotated[List[str], Field(description="时间标识符")],
977
- test_type: Annotated[str, Field(default="levinlin", description="检验类型")] = "levinlin"
978
- ) -> CallToolResult:
979
- """面板单位根检验"""
980
- await ctx.info(f"开始面板单位根检验: {test_type}")
981
- try:
982
- result = panel_unit_root_test_impl(data, entity_ids, time_periods, test_type)
983
- await ctx.info("面板单位根检验完成")
984
- return CallToolResult(
985
- content=[TextContent(type="text", text=f"面板单位根检验: {'平稳' if result.stationary else '非平稳'}")],
986
- structuredContent=result.model_dump()
987
- )
988
- except Exception as e:
989
- await ctx.error(f"面板单位根检验出错: {str(e)}")
990
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
991
-
992
-
993
- # ============================================================================
994
- # 高级时间序列分析工具
995
- # ============================================================================
996
-
997
- @mcp.tool()
998
- async def var_model_analysis(
999
- ctx: Context[ServerSession, AppContext],
1000
- data: Annotated[Dict[str, List[float]], Field(description="多变量时间序列数据")],
1001
- max_lags: Annotated[int, Field(default=5, description="最大滞后阶数")] = 5,
1002
- ic: Annotated[str, Field(default="aic", description="信息准则")] = "aic"
1003
- ) -> CallToolResult:
1004
- """VAR模型分析"""
1005
- await ctx.info(f"开始VAR模型分析,变量数量: {len(data)}")
1006
- try:
1007
- result = var_model(data, max_lags=max_lags, ic=ic)
1008
- await ctx.info("VAR模型分析完成")
1009
- return CallToolResult(
1010
- content=[TextContent(type="text", text=f"VAR模型: 滞后阶数={result.order}, AIC={result.aic:.2f}")],
1011
- structuredContent=result.model_dump()
1012
- )
1013
- except Exception as e:
1014
- await ctx.error(f"VAR模型分析出错: {str(e)}")
1015
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1016
-
1017
-
1018
- @mcp.tool()
1019
- async def vecm_model_analysis(
1020
- ctx: Context[ServerSession, AppContext],
1021
- data: Annotated[Dict[str, List[float]], Field(description="多变量时间序列数据")],
1022
- coint_rank: Annotated[int, Field(default=1, description="协整秩")] = 1,
1023
- deterministic: Annotated[str, Field(default="co", description="确定性项")] = "co",
1024
- max_lags: Annotated[int, Field(default=5, description="最大滞后阶数")] = 5
1025
- ) -> CallToolResult:
1026
- """VECM模型分析"""
1027
- await ctx.info(f"开始VECM模型分析,变量数量: {len(data)}")
1028
- try:
1029
- result = vecm_model(data, coint_rank=coint_rank, deterministic=deterministic, max_lags=max_lags)
1030
- await ctx.info("VECM模型分析完成")
1031
- return CallToolResult(
1032
- content=[TextContent(type="text", text=f"VECM模型: 协整秩={result.coint_rank}, AIC={result.aic:.2f}")],
1033
- structuredContent=result.model_dump()
1034
- )
1035
- except Exception as e:
1036
- await ctx.error(f"VECM模型分析出错: {str(e)}")
1037
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1038
-
1039
-
1040
- @mcp.tool()
1041
- async def garch_model_analysis(
1042
- ctx: Context[ServerSession, AppContext],
1043
- data: Annotated[List[float], Field(description="时间序列数据(通常是收益率)")],
1044
- order: Annotated[tuple, Field(default=(1, 1), description="GARCH阶数(p,q)")] = (1, 1),
1045
- dist: Annotated[str, Field(default="normal", description="误差分布")] = "normal"
1046
- ) -> CallToolResult:
1047
- """GARCH模型分析"""
1048
- await ctx.info(f"开始GARCH模型分析,样本大小: {len(data)}")
1049
- try:
1050
- result = garch_model(data, order=order, dist=dist)
1051
- await ctx.info("GARCH模型分析完成")
1052
- return CallToolResult(
1053
- content=[TextContent(type="text", text=f"GARCH模型: 持久性={result.persistence:.4f}")],
1054
- structuredContent=result.model_dump()
1055
- )
1056
- except Exception as e:
1057
- await ctx.error(f"GARCH模型分析出错: {str(e)}")
1058
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1059
-
1060
-
1061
- @mcp.tool()
1062
- async def state_space_model_analysis(
1063
- ctx: Context[ServerSession, AppContext],
1064
- data: Annotated[List[float], Field(description="时间序列数据")],
1065
- state_dim: Annotated[int, Field(default=1, description="状态维度")] = 1,
1066
- observation_dim: Annotated[int, Field(default=1, description="观测维度")] = 1,
1067
- trend: Annotated[bool, Field(default=True, description="是否包含趋势项")] = True,
1068
- seasonal: Annotated[bool, Field(default=False, description="是否包含季节项")] = False,
1069
- period: Annotated[int, Field(default=12, description="季节周期")] = 12
1070
- ) -> CallToolResult:
1071
- """状态空间模型分析"""
1072
- await ctx.info(f"开始状态空间模型分析,样本大小: {len(data)}")
1073
- try:
1074
- result = state_space_model(data, state_dim, observation_dim, trend, seasonal, period)
1075
- await ctx.info("状态空间模型分析完成")
1076
- return CallToolResult(
1077
- content=[TextContent(type="text", text=f"状态空间模型: AIC={result.aic:.2f}")],
1078
- structuredContent=result.model_dump()
1079
- )
1080
- except Exception as e:
1081
- await ctx.error(f"状态空间模型分析出错: {str(e)}")
1082
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1083
-
1084
-
1085
- @mcp.tool()
1086
- async def variance_decomposition_analysis(
1087
- ctx: Context[ServerSession, AppContext],
1088
- data: Annotated[Dict[str, List[float]], Field(description="多变量时间序列数据")],
1089
- periods: Annotated[int, Field(default=10, description="分解期数")] = 10,
1090
- max_lags: Annotated[int, Field(default=5, description="最大滞后阶数")] = 5
1091
- ) -> CallToolResult:
1092
- """方差分解分析"""
1093
- await ctx.info(f"开始方差分解分析,变量数量: {len(data)}")
1094
- try:
1095
- result = variance_decomposition(data, periods=periods, max_lags=max_lags)
1096
- await ctx.info("方差分解分析完成")
1097
- return CallToolResult(
1098
- content=[TextContent(type="text", text=f"方差分解: {periods}期")],
1099
- structuredContent=result
1100
- )
1101
- except Exception as e:
1102
- await ctx.error(f"方差分解分析出错: {str(e)}")
1103
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1104
-
1105
-
1106
- # ============================================================================
1107
- # 机器学习工具
1108
- # ============================================================================
1109
-
1110
- @mcp.tool()
1111
- async def random_forest_regression_analysis(
1112
- ctx: Context[ServerSession, AppContext],
1113
- y_data: Annotated[List[float], Field(description="因变量数据")],
1114
- x_data: Annotated[List[List[float]], Field(description="自变量数据")],
1115
- feature_names: Annotated[Optional[List[str]], Field(default=None, description="特征名称")] = None,
1116
- n_estimators: Annotated[int, Field(default=100, description="树的数量")] = 100,
1117
- max_depth: Annotated[Optional[int], Field(default=None, description="最大深度")] = None
1118
- ) -> CallToolResult:
1119
- """随机森林回归分析"""
1120
- await ctx.info(f"开始随机森林回归分析,样本大小: {len(y_data)}")
1121
- try:
1122
- result = random_forest_regression(y_data, x_data, feature_names, n_estimators, max_depth)
1123
- await ctx.info("随机森林回归分析完成")
1124
- return CallToolResult(
1125
- content=[TextContent(type="text", text=f"随机森林: R²={result.r2_score:.4f}")],
1126
- structuredContent=result.model_dump()
1127
- )
1128
- except Exception as e:
1129
- await ctx.error(f"随机森林回归分析出错: {str(e)}")
1130
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1131
-
1132
-
1133
- @mcp.tool()
1134
- async def gradient_boosting_regression_analysis(
1135
- ctx: Context[ServerSession, AppContext],
1136
- y_data: Annotated[List[float], Field(description="因变量数据")],
1137
- x_data: Annotated[List[List[float]], Field(description="自变量数据")],
1138
- feature_names: Annotated[Optional[List[str]], Field(default=None, description="特征名称")] = None,
1139
- n_estimators: Annotated[int, Field(default=100, description="树的数量")] = 100,
1140
- learning_rate: Annotated[float, Field(default=0.1, description="学习率")] = 0.1,
1141
- max_depth: Annotated[int, Field(default=3, description="最大深度")] = 3
1142
- ) -> CallToolResult:
1143
- """梯度提升树回归分析"""
1144
- await ctx.info(f"开始梯度提升树回归分析,样本大小: {len(y_data)}")
1145
- try:
1146
- result = gradient_boosting_regression(y_data, x_data, feature_names, n_estimators, learning_rate, max_depth)
1147
- await ctx.info("梯度提升树回归分析完成")
1148
- return CallToolResult(
1149
- content=[TextContent(type="text", text=f"梯度提升树: R²={result.r2_score:.4f}")],
1150
- structuredContent=result.model_dump()
1151
- )
1152
- except Exception as e:
1153
- await ctx.error(f"梯度提升树回归分析出错: {str(e)}")
1154
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1155
-
1156
-
1157
- @mcp.tool()
1158
- async def lasso_regression_analysis(
1159
- ctx: Context[ServerSession, AppContext],
1160
- y_data: Annotated[List[float], Field(description="因变量数据")],
1161
- x_data: Annotated[List[List[float]], Field(description="自变量数据")],
1162
- feature_names: Annotated[Optional[List[str]], Field(default=None, description="特征名称")] = None,
1163
- alpha: Annotated[float, Field(default=1.0, description="正则化强度")] = 1.0
1164
- ) -> CallToolResult:
1165
- """Lasso回归分析"""
1166
- await ctx.info(f"开始Lasso回归分析,样本大小: {len(y_data)}")
1167
- try:
1168
- result = lasso_regression(y_data, x_data, feature_names, alpha)
1169
- await ctx.info("Lasso回归分析完成")
1170
- return CallToolResult(
1171
- content=[TextContent(type="text", text=f"Lasso回归: R²={result.r2_score:.4f}")],
1172
- structuredContent=result.model_dump()
1173
- )
1174
- except Exception as e:
1175
- await ctx.error(f"Lasso回归分析出错: {str(e)}")
1176
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1177
-
1178
-
1179
- @mcp.tool()
1180
- async def ridge_regression_analysis(
1181
- ctx: Context[ServerSession, AppContext],
1182
- y_data: Annotated[List[float], Field(description="因变量数据")],
1183
- x_data: Annotated[List[List[float]], Field(description="自变量数据")],
1184
- feature_names: Annotated[Optional[List[str]], Field(default=None, description="特征名称")] = None,
1185
- alpha: Annotated[float, Field(default=1.0, description="正则化强度")] = 1.0
1186
- ) -> CallToolResult:
1187
- """Ridge回归分析"""
1188
- await ctx.info(f"开始Ridge回归分析,样本大小: {len(y_data)}")
1189
- try:
1190
- result = ridge_regression(y_data, x_data, feature_names, alpha)
1191
- await ctx.info("Ridge回归分析完成")
1192
- return CallToolResult(
1193
- content=[TextContent(type="text", text=f"Ridge回归: R²={result.r2_score:.4f}")],
1194
- structuredContent=result.model_dump()
1195
- )
1196
- except Exception as e:
1197
- await ctx.error(f"Ridge回归分析出错: {str(e)}")
1198
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1199
-
1200
-
1201
- @mcp.tool()
1202
- async def cross_validation_analysis(
1203
- ctx: Context[ServerSession, AppContext],
1204
- y_data: Annotated[List[float], Field(description="因变量数据")],
1205
- x_data: Annotated[List[List[float]], Field(description="自变量数据")],
1206
- model_type: Annotated[str, Field(default="random_forest", description="模型类型")] = "random_forest",
1207
- cv_folds: Annotated[int, Field(default=5, description="交叉验证折数")] = 5,
1208
- scoring: Annotated[str, Field(default="r2", description="评分指标")] = "r2"
1209
- ) -> CallToolResult:
1210
- """交叉验证分析"""
1211
- await ctx.info(f"开始交叉验证分析,模型类型: {model_type}")
1212
- try:
1213
- result = cross_validation(y_data, x_data, model_type, cv_folds, scoring)
1214
- await ctx.info("交叉验证分析完成")
1215
- return CallToolResult(
1216
- content=[TextContent(type="text", text=f"交叉验证: 平均得分={result.mean_score:.4f}")],
1217
- structuredContent=result.model_dump()
1218
- )
1219
- except Exception as e:
1220
- await ctx.error(f"交叉验证分析出错: {str(e)}")
1221
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1222
-
1223
-
1224
- @mcp.tool()
1225
- async def feature_importance_analysis_tool(
1226
- ctx: Context[ServerSession, AppContext],
1227
- y_data: Annotated[List[float], Field(description="因变量数据")],
1228
- x_data: Annotated[List[List[float]], Field(description="自变量数据")],
1229
- feature_names: Annotated[Optional[List[str]], Field(default=None, description="特征名称")] = None,
1230
- method: Annotated[str, Field(default="random_forest", description="分析方法")] = "random_forest",
1231
- top_k: Annotated[int, Field(default=5, description="最重要的特征数量")] = 5
1232
- ) -> CallToolResult:
1233
- """特征重要性分析"""
1234
- await ctx.info(f"开始特征重要性分析,方法: {method}")
1235
- try:
1236
- result = feature_importance_analysis(y_data, x_data, feature_names, method, top_k)
1237
- await ctx.info("特征重要性分析完成")
1238
- return CallToolResult(
1239
- content=[TextContent(type="text", text=f"特征重要性: Top特征={result.top_features}")],
1240
- structuredContent=result.model_dump()
1241
- )
1242
- except Exception as e:
1243
- await ctx.error(f"特征重要性分析出错: {str(e)}")
1244
- return CallToolResult(content=[TextContent(type="text", text=f"错误: {str(e)}")], isError=True)
1245
-
1246
-
1247
-
1248
- def create_mcp_server() -> FastMCP:
1249
- """创建并返回MCP服务器实例"""
1250
- return mcp