@nahisaho/satori 0.1.0
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.
- package/LICENCE +0 -0
- package/README.md +191 -0
- package/bin/satori.js +95 -0
- package/package.json +29 -0
- package/src/.github/skills/scientific-academic-writing/SKILL.md +361 -0
- package/src/.github/skills/scientific-academic-writing/assets/acs_article.md +199 -0
- package/src/.github/skills/scientific-academic-writing/assets/elsevier_article.md +244 -0
- package/src/.github/skills/scientific-academic-writing/assets/ieee_transactions.md +212 -0
- package/src/.github/skills/scientific-academic-writing/assets/imrad_standard.md +181 -0
- package/src/.github/skills/scientific-academic-writing/assets/nature_article.md +179 -0
- package/src/.github/skills/scientific-academic-writing/assets/qiita_technical_article.md +385 -0
- package/src/.github/skills/scientific-academic-writing/assets/science_research_article.md +169 -0
- package/src/.github/skills/scientific-bioinformatics/SKILL.md +220 -0
- package/src/.github/skills/scientific-biosignal-processing/SKILL.md +357 -0
- package/src/.github/skills/scientific-causal-inference/SKILL.md +347 -0
- package/src/.github/skills/scientific-cheminformatics/SKILL.md +196 -0
- package/src/.github/skills/scientific-data-preprocessing/SKILL.md +413 -0
- package/src/.github/skills/scientific-data-simulation/SKILL.md +244 -0
- package/src/.github/skills/scientific-doe/SKILL.md +360 -0
- package/src/.github/skills/scientific-eda-correlation/SKILL.md +141 -0
- package/src/.github/skills/scientific-feature-importance/SKILL.md +208 -0
- package/src/.github/skills/scientific-image-analysis/SKILL.md +310 -0
- package/src/.github/skills/scientific-materials-characterization/SKILL.md +368 -0
- package/src/.github/skills/scientific-meta-analysis/SKILL.md +352 -0
- package/src/.github/skills/scientific-metabolomics/SKILL.md +326 -0
- package/src/.github/skills/scientific-ml-classification/SKILL.md +265 -0
- package/src/.github/skills/scientific-ml-regression/SKILL.md +215 -0
- package/src/.github/skills/scientific-multi-omics/SKILL.md +303 -0
- package/src/.github/skills/scientific-network-analysis/SKILL.md +257 -0
- package/src/.github/skills/scientific-pca-tsne/SKILL.md +235 -0
- package/src/.github/skills/scientific-pipeline-scaffold/SKILL.md +331 -0
- package/src/.github/skills/scientific-process-optimization/SKILL.md +215 -0
- package/src/.github/skills/scientific-publication-figures/SKILL.md +208 -0
- package/src/.github/skills/scientific-sequence-analysis/SKILL.md +389 -0
- package/src/.github/skills/scientific-spectral-signal/SKILL.md +227 -0
- package/src/.github/skills/scientific-statistical-testing/SKILL.md +240 -0
- package/src/.github/skills/scientific-survival-clinical/SKILL.md +239 -0
- package/src/.github/skills/scientific-time-series/SKILL.md +291 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-time-series
|
|
3
|
+
description: |
|
|
4
|
+
時系列解析・予測スキル。ARIMA/SARIMA/Prophet モデリング、変化点検出(PELT/Bayesian)、
|
|
5
|
+
周期解析(FFT/ウェーブレット)、季節分解(STL)、異常検出、Granger 因果性検定の
|
|
6
|
+
テンプレートを提供。実験データのトレンド解析・予測モデリングに適用。
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Scientific Time Series Analysis
|
|
10
|
+
|
|
11
|
+
時系列データの分解・モデリング・予測・異常検出パイプライン。
|
|
12
|
+
プロセスモニタリング、環境測定、臨床バイタルサイン、実験時系列データなどに適用する。
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- 時系列トレンドの分解・可視化が必要なとき
|
|
17
|
+
- ARIMA / Prophet による将来予測モデルを構築するとき
|
|
18
|
+
- 変化点や異常値をデータから検出するとき
|
|
19
|
+
- 周期性(季節性)を解析するとき
|
|
20
|
+
- Granger 因果性など時系列間の関係を調べるとき
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
## 1. STL 季節分解
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import numpy as np
|
|
30
|
+
import pandas as pd
|
|
31
|
+
import matplotlib.pyplot as plt
|
|
32
|
+
from statsmodels.tsa.seasonal import STL
|
|
33
|
+
|
|
34
|
+
def stl_decomposition(series, period, robust=True, figsize=(12, 10)):
|
|
35
|
+
"""
|
|
36
|
+
STL (Seasonal and Trend decomposition using Loess) による分解。
|
|
37
|
+
|
|
38
|
+
Components:
|
|
39
|
+
- Trend: 長期トレンド
|
|
40
|
+
- Seasonal: 周期成分
|
|
41
|
+
- Residual: 残差
|
|
42
|
+
|
|
43
|
+
Parameters:
|
|
44
|
+
series: pd.Series with DatetimeIndex
|
|
45
|
+
period: 季節周期(データポイント数)
|
|
46
|
+
"""
|
|
47
|
+
stl = STL(series, period=period, robust=robust)
|
|
48
|
+
result = stl.fit()
|
|
49
|
+
|
|
50
|
+
fig, axes = plt.subplots(4, 1, figsize=figsize, sharex=True)
|
|
51
|
+
components = [("Observed", series), ("Trend", result.trend),
|
|
52
|
+
("Seasonal", result.seasonal), ("Residual", result.resid)]
|
|
53
|
+
|
|
54
|
+
for ax, (name, data) in zip(axes, components):
|
|
55
|
+
ax.plot(data, linewidth=1)
|
|
56
|
+
ax.set_ylabel(name)
|
|
57
|
+
ax.grid(alpha=0.3)
|
|
58
|
+
|
|
59
|
+
plt.suptitle("STL Decomposition", fontweight="bold", y=1.01)
|
|
60
|
+
plt.tight_layout()
|
|
61
|
+
plt.savefig("figures/stl_decomposition.png", dpi=300, bbox_inches="tight")
|
|
62
|
+
plt.close()
|
|
63
|
+
|
|
64
|
+
return result
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 2. ARIMA / SARIMA モデリング
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from statsmodels.tsa.statespace.sarimax import SARIMAX
|
|
71
|
+
from statsmodels.tsa.stattools import adfuller
|
|
72
|
+
|
|
73
|
+
def adf_stationarity_test(series, significance=0.05):
|
|
74
|
+
"""ADF 検定による定常性チェック。"""
|
|
75
|
+
result = adfuller(series.dropna())
|
|
76
|
+
return {
|
|
77
|
+
"adf_statistic": result[0],
|
|
78
|
+
"p_value": result[1],
|
|
79
|
+
"used_lag": result[2],
|
|
80
|
+
"n_obs": result[3],
|
|
81
|
+
"is_stationary": result[1] < significance,
|
|
82
|
+
"critical_values": result[4],
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def fit_sarima(series, order=(1, 1, 1), seasonal_order=(1, 1, 1, 12),
|
|
87
|
+
forecast_steps=24):
|
|
88
|
+
"""
|
|
89
|
+
SARIMA モデルのフィッティングと予測。
|
|
90
|
+
|
|
91
|
+
Parameters:
|
|
92
|
+
order: (p, d, q) — AR次数, 差分次数, MA次数
|
|
93
|
+
seasonal_order: (P, D, Q, s) — 季節 AR/差分/MA 次数 + 周期
|
|
94
|
+
forecast_steps: 予測期間数
|
|
95
|
+
"""
|
|
96
|
+
model = SARIMAX(series, order=order, seasonal_order=seasonal_order,
|
|
97
|
+
enforce_stationarity=False, enforce_invertibility=False)
|
|
98
|
+
fitted = model.fit(disp=False)
|
|
99
|
+
|
|
100
|
+
# 予測
|
|
101
|
+
forecast = fitted.get_forecast(steps=forecast_steps)
|
|
102
|
+
pred_mean = forecast.predicted_mean
|
|
103
|
+
conf_int = forecast.conf_int()
|
|
104
|
+
|
|
105
|
+
# 診断
|
|
106
|
+
diagnostics = {
|
|
107
|
+
"aic": fitted.aic,
|
|
108
|
+
"bic": fitted.bic,
|
|
109
|
+
"ljung_box_p": fitted.test_serial_correlation("ljungbox")[0][0, 1],
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return fitted, pred_mean, conf_int, diagnostics
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def plot_forecast(series, pred_mean, conf_int, title="SARIMA Forecast",
|
|
116
|
+
figsize=(12, 5)):
|
|
117
|
+
"""時系列の実測値と予測を描画する。"""
|
|
118
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
119
|
+
ax.plot(series.index, series.values, "b-", label="Observed", linewidth=1)
|
|
120
|
+
ax.plot(pred_mean.index, pred_mean.values, "r--", label="Forecast",
|
|
121
|
+
linewidth=2)
|
|
122
|
+
ax.fill_between(conf_int.index, conf_int.iloc[:, 0], conf_int.iloc[:, 1],
|
|
123
|
+
color="red", alpha=0.1, label="95% CI")
|
|
124
|
+
ax.set_title(title, fontweight="bold")
|
|
125
|
+
ax.legend()
|
|
126
|
+
ax.grid(alpha=0.3)
|
|
127
|
+
plt.tight_layout()
|
|
128
|
+
plt.savefig("figures/time_series_forecast.png", dpi=300, bbox_inches="tight")
|
|
129
|
+
plt.close()
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 3. 変化点検出
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
def detect_changepoints(series, method="pelt", penalty="bic", min_size=10):
|
|
136
|
+
"""
|
|
137
|
+
変化点検出。
|
|
138
|
+
|
|
139
|
+
method:
|
|
140
|
+
"pelt" — PELT アルゴリズム (ruptures)
|
|
141
|
+
"cusum" — CUSUM ベース
|
|
142
|
+
"bayesian" — ベイズオンライン変化点検出
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
list of changepoint indices
|
|
146
|
+
"""
|
|
147
|
+
import ruptures as rpt
|
|
148
|
+
|
|
149
|
+
signal = series.values
|
|
150
|
+
|
|
151
|
+
if method == "pelt":
|
|
152
|
+
algo = rpt.Pelt(model="rbf", min_size=min_size).fit(signal)
|
|
153
|
+
cps = algo.predict(pen=10)
|
|
154
|
+
elif method == "cusum":
|
|
155
|
+
algo = rpt.Binseg(model="l2", min_size=min_size).fit(signal)
|
|
156
|
+
cps = algo.predict(n_bkps=5)
|
|
157
|
+
elif method == "bayesian":
|
|
158
|
+
algo = rpt.BottomUp(model="l2", min_size=min_size).fit(signal)
|
|
159
|
+
cps = algo.predict(n_bkps=5)
|
|
160
|
+
|
|
161
|
+
# 最後の要素 (n) を除去
|
|
162
|
+
cps = [cp for cp in cps if cp < len(signal)]
|
|
163
|
+
|
|
164
|
+
return cps
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def plot_changepoints(series, changepoints, figsize=(12, 4)):
|
|
168
|
+
"""変化点を時系列上に可視化する。"""
|
|
169
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
170
|
+
ax.plot(series.index, series.values, "b-", linewidth=1)
|
|
171
|
+
for cp in changepoints:
|
|
172
|
+
ax.axvline(series.index[cp], color="red", linestyle="--",
|
|
173
|
+
alpha=0.7, linewidth=1.5)
|
|
174
|
+
ax.set_title(f"Changepoint Detection ({len(changepoints)} points found)",
|
|
175
|
+
fontweight="bold")
|
|
176
|
+
ax.grid(alpha=0.3)
|
|
177
|
+
plt.tight_layout()
|
|
178
|
+
plt.savefig("figures/changepoints.png", dpi=300, bbox_inches="tight")
|
|
179
|
+
plt.close()
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## 4. 周期解析(FFT / ウェーブレット)
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
def fft_periodicity(series, fs=1.0, top_n=5, figsize=(10, 5)):
|
|
186
|
+
"""
|
|
187
|
+
FFT によるパワースペクトルと支配的周期の抽出。
|
|
188
|
+
"""
|
|
189
|
+
signal = series.values - np.mean(series.values)
|
|
190
|
+
N = len(signal)
|
|
191
|
+
fft_vals = np.fft.rfft(signal)
|
|
192
|
+
fft_power = np.abs(fft_vals)**2
|
|
193
|
+
freqs = np.fft.rfftfreq(N, d=1/fs)
|
|
194
|
+
|
|
195
|
+
# DC成分除去
|
|
196
|
+
fft_power[0] = 0
|
|
197
|
+
|
|
198
|
+
# Top-N 周期
|
|
199
|
+
top_idx = np.argsort(fft_power)[::-1][:top_n]
|
|
200
|
+
dominant_periods = []
|
|
201
|
+
for idx in top_idx:
|
|
202
|
+
if freqs[idx] > 0:
|
|
203
|
+
dominant_periods.append({
|
|
204
|
+
"frequency": freqs[idx],
|
|
205
|
+
"period": 1 / freqs[idx],
|
|
206
|
+
"power": fft_power[idx],
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
210
|
+
ax.plot(freqs[1:], fft_power[1:], "b-", linewidth=1)
|
|
211
|
+
for dp in dominant_periods:
|
|
212
|
+
ax.axvline(dp["frequency"], color="red", linestyle="--", alpha=0.5)
|
|
213
|
+
ax.set_xlabel("Frequency")
|
|
214
|
+
ax.set_ylabel("Power")
|
|
215
|
+
ax.set_title("FFT Power Spectrum", fontweight="bold")
|
|
216
|
+
plt.tight_layout()
|
|
217
|
+
plt.savefig("figures/fft_spectrum.png", dpi=300, bbox_inches="tight")
|
|
218
|
+
plt.close()
|
|
219
|
+
|
|
220
|
+
return dominant_periods
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## 5. Granger 因果性検定
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
from statsmodels.tsa.stattools import grangercausalitytests
|
|
227
|
+
|
|
228
|
+
def granger_causality(df, cause_col, effect_col, max_lag=10,
|
|
229
|
+
significance=0.05):
|
|
230
|
+
"""
|
|
231
|
+
Granger 因果性検定: cause → effect の因果関係を検定する。
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
dict with optimal_lag, p_values, is_causal
|
|
235
|
+
"""
|
|
236
|
+
data = df[[effect_col, cause_col]].dropna()
|
|
237
|
+
results = grangercausalitytests(data, maxlag=max_lag, verbose=False)
|
|
238
|
+
|
|
239
|
+
p_values = {}
|
|
240
|
+
for lag in range(1, max_lag + 1):
|
|
241
|
+
p_val = results[lag][0]["ssr_ftest"][1]
|
|
242
|
+
p_values[lag] = p_val
|
|
243
|
+
|
|
244
|
+
optimal_lag = min(p_values, key=p_values.get)
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
"cause": cause_col,
|
|
248
|
+
"effect": effect_col,
|
|
249
|
+
"optimal_lag": optimal_lag,
|
|
250
|
+
"p_value_at_optimal": p_values[optimal_lag],
|
|
251
|
+
"is_causal": p_values[optimal_lag] < significance,
|
|
252
|
+
"all_p_values": p_values,
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## 6. 異常検出
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
def anomaly_detection_zscore(series, window=30, threshold=3.0):
|
|
260
|
+
"""
|
|
261
|
+
移動平均ベースの Z-score 異常検出。
|
|
262
|
+
"""
|
|
263
|
+
rolling_mean = series.rolling(window=window, center=True).mean()
|
|
264
|
+
rolling_std = series.rolling(window=window, center=True).std()
|
|
265
|
+
z_scores = (series - rolling_mean) / (rolling_std + 1e-10)
|
|
266
|
+
anomalies = series[np.abs(z_scores) > threshold]
|
|
267
|
+
return anomalies, z_scores
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## References
|
|
271
|
+
|
|
272
|
+
### Output Files
|
|
273
|
+
|
|
274
|
+
| ファイル | 形式 |
|
|
275
|
+
|---|---|
|
|
276
|
+
| `results/stationarity_test.csv` | CSV |
|
|
277
|
+
| `results/forecast_results.csv` | CSV |
|
|
278
|
+
| `results/changepoints.csv` | CSV |
|
|
279
|
+
| `results/dominant_periods.csv` | CSV |
|
|
280
|
+
| `results/granger_causality.csv` | CSV |
|
|
281
|
+
| `figures/stl_decomposition.png` | PNG |
|
|
282
|
+
| `figures/time_series_forecast.png` | PNG |
|
|
283
|
+
| `figures/changepoints.png` | PNG |
|
|
284
|
+
| `figures/fft_spectrum.png` | PNG |
|
|
285
|
+
|
|
286
|
+
#### 依存パッケージ
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
statsmodels>=0.14
|
|
290
|
+
ruptures>=1.1
|
|
291
|
+
```
|