Coverage for src\time_series_analyzer\api.py: 94%
64 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-23 11:57 +0800
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-23 11:57 +0800
1"""
2Python库API接口
4提供简洁易用的Python API,方便其他项目集成使用。
5"""
7from typing import Dict, Any, Optional, Union, List, Tuple
8from pathlib import Path
10from .models import ARIMAModel, SeasonalARIMAModel
11from .transfer_function import TransferFunction, TransferFunctionDeriver
12from .parsers import ModelParser
13from .formatters import OutputFormatter
16class TimeSeriesAnalyzer:
17 """
18 时间序列模型分析器主类
20 提供统一的API接口用于ARIMA/SARIMA模型的传递函数分析。
21 """
23 def __init__(self, precision: int = 4):
24 """
25 初始化分析器
27 Args:
28 precision: 数值精度
29 """
30 self.precision = precision
31 self.deriver = TransferFunctionDeriver()
32 self.formatter = OutputFormatter(precision=precision)
34 def create_arima_model(self, p: int, d: int, q: int,
35 ar_params: Optional[List[float]] = None,
36 ma_params: Optional[List[float]] = None,
37 constant: float = 0.0,
38 name: Optional[str] = None) -> ARIMAModel:
39 """
40 创建ARIMA模型
42 Args:
43 p: 自回归阶数
44 d: 差分阶数
45 q: 移动平均阶数
46 ar_params: 自回归参数
47 ma_params: 移动平均参数
48 constant: 常数项
49 name: 模型名称
51 Returns:
52 ARIMA模型对象
53 """
54 return ARIMAModel(
55 p=p, d=d, q=q,
56 ar_params=ar_params,
57 ma_params=ma_params,
58 constant=constant,
59 name=name
60 )
62 def create_sarima_model(self, p: int, d: int, q: int,
63 P: int, D: int, Q: int, m: int,
64 ar_params: Optional[List[float]] = None,
65 ma_params: Optional[List[float]] = None,
66 seasonal_ar_params: Optional[List[float]] = None,
67 seasonal_ma_params: Optional[List[float]] = None,
68 constant: float = 0.0,
69 name: Optional[str] = None) -> SeasonalARIMAModel:
70 """
71 创建SARIMA模型
73 Args:
74 p, d, q: 非季节性参数
75 P, D, Q, m: 季节性参数
76 ar_params: 自回归参数
77 ma_params: 移动平均参数
78 seasonal_ar_params: 季节性自回归参数
79 seasonal_ma_params: 季节性移动平均参数
80 constant: 常数项
81 name: 模型名称
83 Returns:
84 SARIMA模型对象
85 """
86 return SeasonalARIMAModel(
87 p=p, d=d, q=q,
88 P=P, D=D, Q=Q, m=m,
89 ar_params=ar_params,
90 ma_params=ma_params,
91 seasonal_ar_params=seasonal_ar_params,
92 seasonal_ma_params=seasonal_ma_params,
93 constant=constant,
94 name=name
95 )
97 def parse_model_string(self, model_str: str) -> Union[ARIMAModel, SeasonalARIMAModel]:
98 """
99 从字符串解析模型
101 Args:
102 model_str: 模型字符串,如 "ARIMA(2,1,1)" 或 "SARIMA(2,1,1)(1,1,1,12)"
104 Returns:
105 模型对象
106 """
107 return ModelParser.parse_from_string(model_str)
109 def load_model_from_file(self, file_path: Union[str, Path]) -> Union[ARIMAModel, SeasonalARIMAModel]:
110 """
111 从文件加载模型
113 Args:
114 file_path: 配置文件路径 (JSON/YAML)
116 Returns:
117 模型对象
118 """
119 return ModelParser.parse_from_file(file_path)
121 def derive_transfer_function(self, model: Union[ARIMAModel, SeasonalARIMAModel]) -> TransferFunction:
122 """
123 推导传递函数
125 Args:
126 model: 时间序列模型
128 Returns:
129 传递函数对象
130 """
131 return self.deriver.derive_transfer_function(model)
133 def analyze_stability(self, model: Union[ARIMAModel, SeasonalARIMAModel]) -> Dict[str, Any]:
134 """
135 分析模型稳定性
137 Args:
138 model: 时间序列模型
140 Returns:
141 稳定性分析结果
142 """
143 return self.deriver.analyze_stability(model)
145 def compute_impulse_response(self, model: Union[ARIMAModel, SeasonalARIMAModel],
146 max_lag: int = 20) -> Dict[int, Any]:
147 """
148 计算脉冲响应函数
150 Args:
151 model: 时间序列模型
152 max_lag: 最大滞后阶数
154 Returns:
155 脉冲响应系数字典
156 """
157 return self.deriver.derive_impulse_response(model, max_lag)
159 def compute_frequency_response(self, model: Union[ARIMAModel, SeasonalARIMAModel],
160 frequencies: List[float]) -> Dict[str, List]:
161 """
162 计算频率响应
164 Args:
165 model: 时间序列模型
166 frequencies: 频率列表
168 Returns:
169 频率响应数据
170 """
171 return self.deriver.get_frequency_response(model, frequencies)
173 def generate_report(self, model: Union[ARIMAModel, SeasonalARIMAModel],
174 format: str = 'text',
175 include_analysis: bool = True,
176 output_file: Optional[Union[str, Path]] = None) -> str:
177 """
178 生成分析报告
180 Args:
181 model: 时间序列模型
182 format: 输出格式 ('text', 'latex', 'json')
183 include_analysis: 是否包含稳定性分析
184 output_file: 输出文件路径
186 Returns:
187 报告内容
188 """
189 if format.lower() == 'latex':
190 content = self.formatter.format_latex(
191 model,
192 include_transfer_function=True,
193 include_analysis=include_analysis
194 )
195 elif format.lower() == 'json':
196 content = self.formatter.format_json(
197 model,
198 include_transfer_function=True,
199 include_analysis=include_analysis
200 )
201 else: # text
202 content = self.formatter.format_plain_text(
203 model,
204 include_transfer_function=True,
205 include_analysis=include_analysis
206 )
208 if output_file:
209 with open(output_file, 'w', encoding='utf-8') as f:
210 f.write(content)
212 return content
214 def quick_analyze(self, model_str: str,
215 include_stability: bool = True,
216 include_impulse: bool = False,
217 include_frequency: bool = False,
218 max_lag: int = 20,
219 frequencies: Optional[List[float]] = None) -> Dict[str, Any]:
220 """
221 快速分析接口
223 Args:
224 model_str: 模型字符串
225 include_stability: 是否包含稳定性分析
226 include_impulse: 是否包含脉冲响应
227 include_frequency: 是否包含频率响应
228 max_lag: 脉冲响应最大滞后
229 frequencies: 频率列表
231 Returns:
232 完整分析结果
233 """
234 # 解析模型
235 model = self.parse_model_string(model_str)
237 # 推导传递函数
238 transfer_func = self.derive_transfer_function(model)
240 result = {
241 "model": model.to_dict(),
242 "transfer_function": {
243 "numerator": str(transfer_func.numerator.as_expr()),
244 "denominator": str(transfer_func.denominator.as_expr()),
245 "poles": [{"real": pole.real, "imag": pole.imag} for pole in transfer_func.get_poles()],
246 "zeros": [{"real": zero.real, "imag": zero.imag} for zero in transfer_func.get_zeros()]
247 }
248 }
250 # 稳定性分析
251 if include_stability:
252 stability = self.analyze_stability(model)
253 result["stability"] = {
254 "is_stable": stability["is_stable"],
255 "max_pole_magnitude": stability["max_pole_magnitude"],
256 "stability_margin": stability["stability_margin"]
257 }
259 # 脉冲响应
260 if include_impulse:
261 impulse_response = self.compute_impulse_response(model, max_lag)
262 result["impulse_response"] = {str(k): str(v) for k, v in impulse_response.items()}
264 # 频率响应
265 if include_frequency:
266 if frequencies is None:
267 frequencies = [i * 0.1 for i in range(6)] # 0, 0.1, 0.2, 0.3, 0.4, 0.5
269 freq_response = self.compute_frequency_response(model, frequencies)
270 result["frequency_response"] = {
271 "frequencies": freq_response["frequencies"],
272 "magnitudes": [float(m) for m in freq_response["magnitudes"]],
273 "phases": [float(p) for p in freq_response["phases"]]
274 }
276 return result
279# 便捷函数
280def analyze_arima(p: int, d: int, q: int,
281 ar_params: Optional[List[float]] = None,
282 ma_params: Optional[List[float]] = None,
283 **kwargs) -> Dict[str, Any]:
284 """
285 快速分析ARIMA模型的便捷函数
287 Args:
288 p, d, q: ARIMA参数
289 ar_params: 自回归参数
290 ma_params: 移动平均参数
291 **kwargs: 其他分析选项
293 Returns:
294 分析结果
295 """
296 analyzer = TimeSeriesAnalyzer()
297 model = analyzer.create_arima_model(p, d, q, ar_params, ma_params)
299 return analyzer.quick_analyze(
300 str(model).split(':')[0], # 提取模型字符串
301 **kwargs
302 )
305def analyze_sarima(p: int, d: int, q: int, P: int, D: int, Q: int, m: int,
306 ar_params: Optional[List[float]] = None,
307 ma_params: Optional[List[float]] = None,
308 seasonal_ar_params: Optional[List[float]] = None,
309 seasonal_ma_params: Optional[List[float]] = None,
310 **kwargs) -> Dict[str, Any]:
311 """
312 快速分析SARIMA模型的便捷函数
314 Args:
315 p, d, q, P, D, Q, m: SARIMA参数
316 ar_params: 自回归参数
317 ma_params: 移动平均参数
318 seasonal_ar_params: 季节性自回归参数
319 seasonal_ma_params: 季节性移动平均参数
320 **kwargs: 其他分析选项
322 Returns:
323 分析结果
324 """
325 analyzer = TimeSeriesAnalyzer()
326 model = analyzer.create_sarima_model(
327 p, d, q, P, D, Q, m,
328 ar_params, ma_params,
329 seasonal_ar_params, seasonal_ma_params
330 )
332 return analyzer.quick_analyze(
333 str(model).split(':')[0], # 提取模型字符串
334 **kwargs
335 )
338def parse_and_analyze(model_str: str, **kwargs) -> Dict[str, Any]:
339 """
340 解析模型字符串并分析的便捷函数
342 Args:
343 model_str: 模型字符串
344 **kwargs: 分析选项
346 Returns:
347 分析结果
348 """
349 analyzer = TimeSeriesAnalyzer()
350 return analyzer.quick_analyze(model_str, **kwargs)