anomaly_detection 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.