anomaly_detection 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.
@@ -0,0 +1,123 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+
5
+ using std::string;
6
+
7
+ double algdiv ( double *a, double *b );
8
+ double alnrel ( double *a );
9
+ double apser ( double *a, double *b, double *x, double *eps );
10
+ double bcorr ( double *a0, double *b0 );
11
+ double beta ( double a, double b );
12
+ double beta_asym ( double *a, double *b, double *lambda, double *eps );
13
+ double beta_frac ( double *a, double *b, double *x, double *y, double *lambda,
14
+ double *eps );
15
+ void beta_grat ( double *a, double *b, double *x, double *y, double *w,
16
+ double *eps,int *ierr );
17
+ void beta_inc ( double *a, double *b, double *x, double *y, double *w,
18
+ double *w1, int *ierr );
19
+ void beta_inc_values ( int *n_data, double *a, double *b, double *x, double *fx );
20
+ double beta_log ( double *a0, double *b0 );
21
+ double beta_pser ( double *a, double *b, double *x, double *eps );
22
+ double beta_rcomp ( double *a, double *b, double *x, double *y );
23
+ double beta_rcomp1 ( int *mu, double *a, double *b, double *x, double *y );
24
+ double beta_up ( double *a, double *b, double *x, double *y, int *n, double *eps );
25
+ void binomial_cdf_values ( int *n_data, int *a, double *b, int *x, double *fx );
26
+ void cdfbet ( int *which, double *p, double *q, double *x, double *y,
27
+ double *a, double *b, int *status, double *bound );
28
+ void cdfbin ( int *which, double *p, double *q, double *s, double *xn,
29
+ double *pr, double *ompr, int *status, double *bound );
30
+ void cdfchi ( int *which, double *p, double *q, double *x, double *df,
31
+ int *status, double *bound );
32
+ void cdfchn ( int *which, double *p, double *q, double *x, double *df,
33
+ double *pnonc, int *status, double *bound );
34
+ void cdff ( int *which, double *p, double *q, double *f, double *dfn,
35
+ double *dfd, int *status, double *bound );
36
+ void cdffnc ( int *which, double *p, double *q, double *f, double *dfn,
37
+ double *dfd, double *phonc, int *status, double *bound );
38
+ void cdfgam ( int *which, double *p, double *q, double *x, double *shape,
39
+ double *scale, int *status, double *bound );
40
+ void cdfnbn ( int *which, double *p, double *q, double *s, double *xn,
41
+ double *pr, double *ompr, int *status, double *bound );
42
+ void cdfnor ( int *which, double *p, double *q, double *x, double *mean,
43
+ double *sd, int *status, double *bound );
44
+ void cdfpoi ( int *which, double *p, double *q, double *s, double *xlam,
45
+ int *status, double *bound );
46
+ void cdft ( int *which, double *p, double *q, double *t, double *df,
47
+ int *status, double *bound );
48
+ void chi_noncentral_cdf_values ( int *n_data, double *x, double *lambda,
49
+ int *df, double *cdf );
50
+ void chi_square_cdf_values ( int *n_data, int *a, double *x, double *fx );
51
+ void cumbet ( double *x, double *y, double *a, double *b, double *cum,
52
+ double *ccum );
53
+ void cumbin ( double *s, double *xn, double *pr, double *ompr,
54
+ double *cum, double *ccum );
55
+ void cumchi ( double *x, double *df, double *cum, double *ccum );
56
+ void cumchn ( double *x, double *df, double *pnonc, double *cum,
57
+ double *ccum );
58
+ void cumf ( double *f, double *dfn, double *dfd, double *cum, double *ccum );
59
+ void cumfnc ( double *f, double *dfn, double *dfd, double *pnonc,
60
+ double *cum, double *ccum );
61
+ void cumgam ( double *x, double *a, double *cum, double *ccum );
62
+ void cumnbn ( double *s, double *xn, double *pr, double *ompr,
63
+ double *cum, double *ccum );
64
+ void cumnor ( double *arg, double *result, double *ccum );
65
+ void cumpoi ( double *s, double *xlam, double *cum, double *ccum );
66
+ void cumt ( double *t, double *df, double *cum, double *ccum );
67
+ double dbetrm ( double *a, double *b );
68
+ double dexpm1 ( double *x );
69
+ double dinvnr ( double *p, double *q );
70
+ void dinvr ( int *status, double *x, double *fx,
71
+ unsigned long *qleft, unsigned long *qhi );
72
+ double dlanor ( double *x );
73
+ double dpmpar ( int *i );
74
+ void dstinv ( double *zsmall, double *zbig, double *zabsst,
75
+ double *zrelst, double *zstpmu, double *zabsto, double *zrelto );
76
+ double dstrem ( double *z );
77
+ void dstzr ( double *zxlo, double *zxhi, double *zabstl, double *zreltl );
78
+ double dt1 ( double *p, double *q, double *df );
79
+ void dzror ( int *status, double *x, double *fx, double *xlo,
80
+ double *xhi, unsigned long *qleft, unsigned long *qhi );
81
+ void erf_values ( int *n_data, double *x, double *fx );
82
+ double error_f ( double *x );
83
+ double error_fc ( int *ind, double *x );
84
+ double esum ( int *mu, double *x );
85
+ double eval_pol ( double a[], int *n, double *x );
86
+ double exparg ( int *l );
87
+ void f_cdf_values ( int *n_data, int *a, int *b, double *x, double *fx );
88
+ void f_noncentral_cdf_values ( int *n_data, int *a, int *b, double *lambda,
89
+ double *x, double *fx );
90
+ double fifdint ( double a );
91
+ double fifdmax1 ( double a, double b );
92
+ double fifdmin1 ( double a, double b );
93
+ double fifdsign ( double mag, double sign );
94
+ long fifidint ( double a );
95
+ long fifmod ( long a, long b );
96
+ double fpser ( double *a, double *b, double *x, double *eps );
97
+ void ftnstop ( string msg );
98
+ double gam1 ( double *a );
99
+ void gamma_inc ( double *a, double *x, double *ans, double *qans, int *ind );
100
+ void gamma_inc_inv ( double *a, double *x, double *x0, double *p, double *q,
101
+ int *ierr );
102
+ void gamma_inc_values ( int *n_data, double *a, double *x, double *fx );
103
+ double gamma_ln1 ( double *a );
104
+ double gamma_log ( double *a );
105
+ void gamma_rat1 ( double *a, double *x, double *r, double *p, double *q,
106
+ double *eps );
107
+ void gamma_values ( int *n_data, double *x, double *fx );
108
+ double gamma_x ( double *a );
109
+ double gsumln ( double *a, double *b );
110
+ int ipmpar ( int *i );
111
+ void negative_binomial_cdf_values ( int *n_data, int *f, int *s, double *p,
112
+ double *cdf );
113
+ void normal_cdf_values ( int *n_data, double *x, double *fx );
114
+ void poisson_cdf_values ( int *n_data, double *a, int *x, double *fx );
115
+ double psi ( double *xx );
116
+ void psi_values ( int *n_data, double *x, double *fx );
117
+ double rcomp ( double *a, double *x );
118
+ double rexp ( double *x );
119
+ double rlog ( double *x );
120
+ double rlog1 ( double *x );
121
+ void student_cdf_values ( int *n_data, int *a, double *x, double *fx );
122
+ double stvaln ( double *p );
123
+ void timestamp ( void );
@@ -0,0 +1,23 @@
1
+ // rice
2
+ #include <rice/rice.hpp>
3
+ #include <rice/stl.hpp>
4
+
5
+ std::vector<size_t> anomalies(const std::vector<float>& x, int period, float k, float alpha, const std::string& direction);
6
+
7
+ extern "C"
8
+ void Init_ext() {
9
+ auto rb_mAnomalyDetection = Rice::define_module("AnomalyDetection");
10
+
11
+ rb_mAnomalyDetection
12
+ .define_singleton_function(
13
+ "_detect",
14
+ [](std::vector<float> x, int period, float k, float alpha, const std::string& direction) {
15
+ auto res = anomalies(x, period, k, alpha, direction);
16
+
17
+ auto a = Rice::Array();
18
+ for (auto v : res) {
19
+ a.push(v);
20
+ }
21
+ return a;
22
+ });
23
+ }
@@ -0,0 +1,5 @@
1
+ require "mkmf-rice"
2
+
3
+ $CXXFLAGS += " -std=c++17 $(optflags)"
4
+
5
+ create_makefile("anomaly_detection/ext")
@@ -0,0 +1,458 @@
1
+ /*!
2
+ * STL C++ v0.1.0
3
+ * https://github.com/ankane/stl-cpp
4
+ * Unlicense OR MIT License
5
+ *
6
+ * Ported from https://www.netlib.org/a/stl
7
+ *
8
+ * Cleveland, R. B., Cleveland, W. S., McRae, J. E., & Terpenning, I. (1990).
9
+ * STL: A Seasonal-Trend Decomposition Procedure Based on Loess.
10
+ * Journal of Official Statistics, 6(1), 3-33.
11
+ */
12
+
13
+ #pragma once
14
+
15
+ #include <algorithm>
16
+ #include <cassert>
17
+ #include <cmath>
18
+ #include <optional>
19
+ #include <vector>
20
+
21
+ namespace stl {
22
+
23
+ bool est(const float* y, size_t n, size_t len, int ideg, float xs, float* ys, size_t nleft, size_t nright, float* w, bool userw, const float* rw) {
24
+ auto range = ((float) n) - 1.0;
25
+ auto h = std::max(xs - ((float) nleft), ((float) nright) - xs);
26
+
27
+ if (len > n) {
28
+ h += (float) ((len - n) / 2);
29
+ }
30
+
31
+ auto h9 = 0.999 * h;
32
+ auto h1 = 0.001 * h;
33
+
34
+ // compute weights
35
+ auto a = 0.0;
36
+ for (auto j = nleft; j <= nright; j++) {
37
+ w[j - 1] = 0.0;
38
+ auto r = fabs(((float) j) - xs);
39
+ if (r <= h9) {
40
+ if (r <= h1) {
41
+ w[j - 1] = 1.0;
42
+ } else {
43
+ w[j - 1] = pow(1.0 - pow(r / h, 3), 3);
44
+ }
45
+ if (userw) {
46
+ w[j - 1] *= rw[j - 1];
47
+ }
48
+ a += w[j - 1];
49
+ }
50
+ }
51
+
52
+ if (a <= 0.0) {
53
+ return false;
54
+ } else { // weighted least squares
55
+ for (auto j = nleft; j <= nright; j++) { // make sum of w(j) == 1
56
+ w[j - 1] /= a;
57
+ }
58
+
59
+ if (h > 0.0 && ideg > 0) { // use linear fit
60
+ auto a = 0.0;
61
+ for (auto j = nleft; j <= nright; j++) { // weighted center of x values
62
+ a += w[j - 1] * ((float) j);
63
+ }
64
+ auto b = xs - a;
65
+ auto c = 0.0;
66
+ for (auto j = nleft; j <= nright; j++) {
67
+ c += w[j - 1] * pow(((float) j) - a, 2);
68
+ }
69
+ if (sqrt(c) > 0.001 * range) {
70
+ b /= c;
71
+
72
+ // points are spread out enough to compute slope
73
+ for (auto j = nleft; j <= nright; j++) {
74
+ w[j - 1] *= b * (((float) j) - a) + 1.0;
75
+ }
76
+ }
77
+ }
78
+
79
+ *ys = 0.0;
80
+ for (auto j = nleft; j <= nright; j++) {
81
+ *ys += w[j - 1] * y[j - 1];
82
+ }
83
+
84
+ return true;
85
+ }
86
+ }
87
+
88
+ void ess(const float* y, size_t n, size_t len, int ideg, size_t njump, bool userw, const float* rw, float* ys, float* res) {
89
+ if (n < 2) {
90
+ ys[0] = y[0];
91
+ return;
92
+ }
93
+
94
+ auto nleft = 0;
95
+ auto nright = 0;
96
+
97
+ auto newnj = std::min(njump, n - 1);
98
+ if (len >= n) {
99
+ nleft = 1;
100
+ nright = n;
101
+ for (auto i = 1; i <= n; i += newnj) {
102
+ auto ok = est(y, n, len, ideg, (float) i, &ys[i - 1], nleft, nright, res, userw, rw);
103
+ if (!ok) {
104
+ ys[i - 1] = y[i - 1];
105
+ }
106
+ }
107
+ } else if (newnj == 1) { // newnj equal to one, len less than n
108
+ auto nsh = (len + 1) / 2;
109
+ nleft = 1;
110
+ nright = len;
111
+ for (auto i = 1; i <= n; i++) { // fitted value at i
112
+ if (i > nsh && nright != n) {
113
+ nleft += 1;
114
+ nright += 1;
115
+ }
116
+ auto ok = est(y, n, len, ideg, (float) i, &ys[i - 1], nleft, nright, res, userw, rw);
117
+ if (!ok) {
118
+ ys[i - 1] = y[i - 1];
119
+ }
120
+ }
121
+ } else { // newnj greater than one, len less than n
122
+ auto nsh = (len + 1) / 2;
123
+ for (auto i = 1; i <= n; i += newnj) { // fitted value at i
124
+ if (i < nsh) {
125
+ nleft = 1;
126
+ nright = len;
127
+ } else if (i >= n - nsh + 1) {
128
+ nleft = n - len + 1;
129
+ nright = n;
130
+ } else {
131
+ nleft = i - nsh + 1;
132
+ nright = len + i - nsh;
133
+ }
134
+ auto ok = est(y, n, len, ideg, (float) i, &ys[i - 1], nleft, nright, res, userw, rw);
135
+ if (!ok) {
136
+ ys[i - 1] = y[i - 1];
137
+ }
138
+ }
139
+ }
140
+
141
+ if (newnj != 1) {
142
+ for (auto i = 1; i <= n - newnj; i += newnj) {
143
+ auto delta = (ys[i + newnj - 1] - ys[i - 1]) / ((float) newnj);
144
+ for (auto j = i + 1; j <= i + newnj - 1; j++) {
145
+ ys[j - 1] = ys[i - 1] + delta * ((float) (j - i));
146
+ }
147
+ }
148
+ auto k = ((n - 1) / newnj) * newnj + 1;
149
+ if (k != n) {
150
+ auto ok = est(y, n, len, ideg, (float) n, &ys[n - 1], nleft, nright, res, userw, rw);
151
+ if (!ok) {
152
+ ys[n - 1] = y[n - 1];
153
+ if (k != n - 1) {
154
+ auto delta = (ys[n - 1] - ys[k - 1]) / ((float) (n - k));
155
+ for (auto j = k + 1; j <= n - 1; j++) {
156
+ ys[j - 1] = ys[k - 1] + delta * ((float) (j - k));
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+
164
+ void ma(const float* x, size_t n, size_t len, float* ave) {
165
+ auto newn = n - len + 1;
166
+ auto flen = (float) len;
167
+ auto v = 0.0;
168
+
169
+ // get the first average
170
+ for (auto i = 0; i < len; i++) {
171
+ v += x[i];
172
+ }
173
+
174
+ ave[0] = v / flen;
175
+ if (newn > 1) {
176
+ auto k = len;
177
+ auto m = 0;
178
+ for (auto j = 1; j < newn; j++) {
179
+ // window down the array
180
+ v = v - x[m] + x[k];
181
+ ave[j] = v / flen;
182
+ k += 1;
183
+ m += 1;
184
+ }
185
+ }
186
+ }
187
+
188
+ void fts(const float* x, size_t n, size_t np, float* trend, float* work) {
189
+ ma(x, n, np, trend);
190
+ ma(trend, n - np + 1, np, work);
191
+ ma(work, n - 2 * np + 2, 3, trend);
192
+ }
193
+
194
+ void rwts(const float* y, size_t n, const float* fit, float* rw) {
195
+ for (auto i = 0; i < n; i++) {
196
+ rw[i] = fabs(y[i] - fit[i]);
197
+ }
198
+
199
+ auto mid1 = (n - 1) / 2;
200
+ auto mid2 = n / 2;
201
+
202
+ // sort
203
+ std::sort(rw, rw + n);
204
+
205
+ auto cmad = 3.0 * (rw[mid1] + rw[mid2]); // 6 * median abs resid
206
+ auto c9 = 0.999 * cmad;
207
+ auto c1 = 0.001 * cmad;
208
+
209
+ for (auto i = 0; i < n; i++) {
210
+ auto r = fabs(y[i] - fit[i]);
211
+ if (r <= c1) {
212
+ rw[i] = 1.0;
213
+ } else if (r <= c9) {
214
+ rw[i] = pow(1.0 - pow(r / cmad, 2), 2);
215
+ } else {
216
+ rw[i] = 0.0;
217
+ }
218
+ }
219
+ }
220
+
221
+ void ss(const float* y, size_t n, size_t np, size_t ns, int isdeg, size_t nsjump, bool userw, float* rw, float* season, float* work1, float* work2, float* work3, float* work4) {
222
+ for (auto j = 1; j <= np; j++) {
223
+ auto k = (n - j) / np + 1;
224
+
225
+ for (auto i = 1; i <= k; i++) {
226
+ work1[i - 1] = y[(i - 1) * np + j - 1];
227
+ }
228
+ if (userw) {
229
+ for (auto i = 1; i <= k; i++) {
230
+ work3[i - 1] = rw[(i - 1) * np + j - 1];
231
+ }
232
+ }
233
+ ess(work1, k, ns, isdeg, nsjump, userw, work3, work2 + 1, work4);
234
+ auto xs = 0.0;
235
+ auto nright = std::min(ns, k);
236
+ auto ok = est(work1, k, ns, isdeg, xs, &work2[0], 1, nright, work4, userw, work3);
237
+ if (!ok) {
238
+ work2[0] = work2[1];
239
+ }
240
+ xs = k + 1;
241
+ size_t nleft = std::max(1, (int) k - (int) ns + 1);
242
+ ok = est(work1, k, ns, isdeg, xs, &work2[k + 1], nleft, k, work4, userw, work3);
243
+ if (!ok) {
244
+ work2[k + 1] = work2[k];
245
+ }
246
+ for (auto m = 1; m <= k + 2; m++) {
247
+ season[(m - 1) * np + j - 1] = work2[m - 1];
248
+ }
249
+ }
250
+ }
251
+
252
+ void onestp(const float* y, size_t n, size_t np, size_t ns, size_t nt, size_t nl, int isdeg, int itdeg, int ildeg, size_t nsjump, size_t ntjump, size_t nljump, size_t ni, bool userw, float* rw, float* season, float* trend, float* work1, float* work2, float* work3, float* work4, float* work5) {
253
+ for (auto j = 0; j < ni; j++) {
254
+ for (auto i = 0; i < n; i++) {
255
+ work1[i] = y[i] - trend[i];
256
+ }
257
+
258
+ ss(work1, n, np, ns, isdeg, nsjump, userw, rw, work2, work3, work4, work5, season);
259
+ fts(work2, n + 2 * np, np, work3, work1);
260
+ ess(work3, n, nl, ildeg, nljump, false, work4, work1, work5);
261
+ for (auto i = 0; i < n; i++) {
262
+ season[i] = work2[np + i] - work1[i];
263
+ }
264
+ for (auto i = 0; i < n; i++) {
265
+ work1[i] = y[i] - season[i];
266
+ }
267
+ ess(work1, n, nt, itdeg, ntjump, userw, rw, trend, work3);
268
+ }
269
+ }
270
+
271
+ void stl(const float* y, size_t n, size_t np, size_t ns, size_t nt, size_t nl, int isdeg, int itdeg, int ildeg, size_t nsjump, size_t ntjump, size_t nljump, size_t ni, size_t no, float* rw, float* season, float* trend) {
272
+ auto work1 = std::vector<float>(n + 2 * np);
273
+ auto work2 = std::vector<float>(n + 2 * np);
274
+ auto work3 = std::vector<float>(n + 2 * np);
275
+ auto work4 = std::vector<float>(n + 2 * np);
276
+ auto work5 = std::vector<float>(n + 2 * np);
277
+
278
+ auto userw = false;
279
+ auto k = 0;
280
+
281
+ assert(ns >= 3);
282
+ assert(nt >= 3);
283
+ assert(nl >= 3);
284
+ assert(np >= 2);
285
+
286
+ assert(isdeg == 0 || isdeg == 1);
287
+ assert(itdeg == 0 || itdeg == 1);
288
+ assert(ildeg == 0 || ildeg == 1);
289
+
290
+ assert(ns % 2 == 1);
291
+ assert(nt % 2 == 1);
292
+ assert(nl % 2 == 1);
293
+
294
+ while (true) {
295
+ onestp(y, n, np, ns, nt, nl, isdeg, itdeg, ildeg, nsjump, ntjump, nljump, ni, userw, rw, season, trend, work1.data(), work2.data(), work3.data(), work4.data(), work5.data());
296
+ k += 1;
297
+ if (k > no) {
298
+ break;
299
+ }
300
+ for (auto i = 0; i < n; i++) {
301
+ work1[i] = trend[i] + season[i];
302
+ }
303
+ rwts(y, n, work1.data(), rw);
304
+ userw = true;
305
+ }
306
+
307
+ if (no <= 0) {
308
+ for (auto i = 0; i < n; i++) {
309
+ rw[i] = 1.0;
310
+ }
311
+ }
312
+ }
313
+
314
+ class StlResult {
315
+ public:
316
+ std::vector<float> seasonal;
317
+ std::vector<float> trend;
318
+ std::vector<float> remainder;
319
+ std::vector<float> weights;
320
+ };
321
+
322
+ class StlParams {
323
+ std::optional<size_t> ns_ = std::nullopt;
324
+ std::optional<size_t> nt_ = std::nullopt;
325
+ std::optional<size_t> nl_ = std::nullopt;
326
+ int isdeg_ = 0;
327
+ int itdeg_ = 1;
328
+ std::optional<int> ildeg_ = std::nullopt;
329
+ std::optional<size_t> nsjump_ = std::nullopt;
330
+ std::optional<size_t> ntjump_ = std::nullopt;
331
+ std::optional<size_t> nljump_ = std::nullopt;
332
+ std::optional<size_t> ni_ = std::nullopt;
333
+ std::optional<size_t> no_ = std::nullopt;
334
+ bool robust_ = false;
335
+
336
+ public:
337
+ inline StlParams seasonal_length(size_t ns) {
338
+ this->ns_ = ns;
339
+ return *this;
340
+ };
341
+
342
+ inline StlParams trend_length(size_t nt) {
343
+ this->nt_ = nt;
344
+ return *this;
345
+ };
346
+
347
+ inline StlParams low_pass_length(size_t nl) {
348
+ this->nl_ = nl;
349
+ return *this;
350
+ };
351
+
352
+ inline StlParams seasonal_degree(int isdeg) {
353
+ this->isdeg_ = isdeg;
354
+ return *this;
355
+ };
356
+
357
+ inline StlParams trend_degree(int itdeg) {
358
+ this->itdeg_ = itdeg;
359
+ return *this;
360
+ };
361
+
362
+ inline StlParams low_pass_degree(int ildeg) {
363
+ this->ildeg_ = ildeg;
364
+ return *this;
365
+ };
366
+
367
+ inline StlParams seasonal_jump(size_t nsjump) {
368
+ this->nsjump_ = nsjump;
369
+ return *this;
370
+ };
371
+
372
+ inline StlParams trend_jump(size_t ntjump) {
373
+ this->ntjump_ = ntjump;
374
+ return *this;
375
+ };
376
+
377
+ inline StlParams low_pass_jump(size_t nljump) {
378
+ this->nljump_ = nljump;
379
+ return *this;
380
+ };
381
+
382
+ inline StlParams inner_loops(bool ni) {
383
+ this->ni_ = ni;
384
+ return *this;
385
+ };
386
+
387
+ inline StlParams outer_loops(bool no) {
388
+ this->no_ = no;
389
+ return *this;
390
+ };
391
+
392
+ inline StlParams robust(bool robust) {
393
+ this->robust_ = robust;
394
+ return *this;
395
+ };
396
+
397
+ StlResult fit(const float* y, size_t n, size_t np);
398
+ StlResult fit(const std::vector<float>& y, size_t np);
399
+ };
400
+
401
+ StlParams params() {
402
+ return StlParams();
403
+ }
404
+
405
+ StlResult StlParams::fit(const float* y, size_t n, size_t np) {
406
+ auto ns = this->ns_.value_or(np);
407
+
408
+ auto isdeg = this->isdeg_;
409
+ auto itdeg = this->itdeg_;
410
+
411
+ auto res = StlResult {
412
+ std::vector<float>(n),
413
+ std::vector<float>(n),
414
+ std::vector<float>(),
415
+ std::vector<float>(n)
416
+ };
417
+
418
+ auto ildeg = this->ildeg_.value_or(itdeg);
419
+ auto newns = std::max(ns, (size_t) 3);
420
+ if (newns % 2 == 0) {
421
+ newns += 1;
422
+ }
423
+
424
+ auto newnp = std::max(np, (size_t) 2);
425
+ auto nt = (size_t) ceil((1.5 * newnp) / (1.0 - 1.5 / (float) newns));
426
+ nt = this->nt_.value_or(nt);
427
+ nt = std::max(nt, (size_t) 3);
428
+ if (nt % 2 == 0) {
429
+ nt += 1;
430
+ }
431
+
432
+ auto nl = this->nl_.value_or(newnp);
433
+ if (nl % 2 == 0 && !this->nl_.has_value()) {
434
+ nl += 1;
435
+ }
436
+
437
+ auto ni = this->ni_.value_or(this->robust_ ? 1 : 2);
438
+ auto no = this->no_.value_or(this->robust_ ? 15 : 0);
439
+
440
+ auto nsjump = this->nsjump_.value_or((size_t) ceil(((float) newns) / 10.0));
441
+ auto ntjump = this->ntjump_.value_or((size_t) ceil(((float) nt) / 10.0));
442
+ auto nljump = this->nljump_.value_or((size_t) ceil(((float) nl) / 10.0));
443
+
444
+ stl(y, n, newnp, newns, nt, nl, isdeg, itdeg, ildeg, nsjump, ntjump, nljump, ni, no, res.weights.data(), res.seasonal.data(), res.trend.data());
445
+
446
+ res.remainder.reserve(n);
447
+ for (auto i = 0; i < n; i++) {
448
+ res.remainder.push_back(y[i] - res.seasonal[i] - res.trend[i]);
449
+ }
450
+
451
+ return res;
452
+ }
453
+
454
+ StlResult StlParams::fit(const std::vector<float>& y, size_t np) {
455
+ return StlParams::fit(y.data(), y.size(), np);
456
+ }
457
+
458
+ }
@@ -0,0 +1,3 @@
1
+ module AnomalyDetection
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,22 @@
1
+ # extensions
2
+ require "anomaly_detection/ext"
3
+
4
+ # modules
5
+ require "anomaly_detection/version"
6
+
7
+ module AnomalyDetection
8
+ def self.detect(series, period:, max_anoms: 0.1, alpha: 0.05, direction: "both")
9
+ raise ArgumentError, "series must contain at least 2 periods" if series.size < period * 2
10
+
11
+ if series.is_a?(Hash)
12
+ sorted = series.sort_by { |k, _| k }
13
+ x = sorted.map(&:last)
14
+ else
15
+ x = series
16
+ end
17
+
18
+ res = _detect(x, period, max_anoms, alpha, direction)
19
+ res.map! { |i| sorted[i][0] } if series.is_a?(Hash)
20
+ res
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.