Intro

I adapted the problem from the following link http://kdd.ics.uci.edu/databases/synthetic_control/synthetic_control.data.html. The goal is to classify the time series into 1 of 6 types of time series.

This dataset contains 600 examples of control charts synthetically generated by the process in Alcock and Manolopoulos (1999). There are six different classes of control charts:

  1. Normal
  2. Cyclic
  3. Increasing trend
  4. Decreasing trend
  5. Upward shift
  6. Downward shift

The following image shows ten examples from each class:

Load Required Packages in R NNS (>= 3.9.1)

require(devtools); install_github('OVVO-Financial/NNS', ref = "NNS-Beta-Version")
require(NNS)
require(plyr)
require(data.table)

Download Data

Scan from URL and convert into matrix with each observation as a column.

tsdata <- scan(url("http://kdd.ics.uci.edu/databases/synthetic_control/synthetic_control.data"))
tsdata <- matrix(tsdata, ncol=60, byrow = TRUE)
dim(tsdata)
## [1] 600  60

Augment tsdata matrix with labels

The following were put into columns of the matrix tsdata:

This leaves us with a matrix of 600 rows and 61 columns.

series = cbind(tsdata ,class.id = rep(1:6, each = 100))
dim(series)
## [1] 600  61

Create train and test sets

There are 600 time series, we will randomly remove 20% of the time series for an out of sample experiment.

set.seed(123)
test.index = sample(1:600, 120, replace = FALSE)
test.index
##   [1] 173 473 245 528 561  28 314 530 327 270 565 268 399 337  61 527 144
##  [18]  25 191 555 516 402 371 574 378 408 313 341 166  85 549 514 393 452
##  [35]  14 591 428 122 179 130  80 232 231 206 571  78 596 258 147 599  26
##  [52] 243 438  67 307 113  70 410 486 203 360  52 207 148 437 240 433 434
##  [69] 423 234 400 333 375   1 251 116 200 321 184  58 127 347 217 575  54
##  [86] 224 507 459 454  90 547 529 175 509 163  95 395  48 235 257 300 167
## [103] 244 475 535 441 567 301 541  73 513 537  30 462 351 544 266 461 283
## [120] 195

Checking our dimensions to ensure 120 time series have been removed.

training.ts.set = series[-test.index, ]
dim(training.ts.set)
## [1] 480  61
test.ts.set = series[test.index, ]
dim(test.ts.set)
## [1] 120  61
# Distribution of test set classifications
hist(series[ , "class.id"][test.index])

Use NNS.reg to find the most similar

The following settings in NNS.reg(..., order = "max", n.best = 1, ...) are very similar to a KNN = 1 (with the NNS general case exhibiting significant weighting differences and less sensitivity to the curse of dimensionality). We set up the following independent variables for training IVs.train, the dependent variable DV which is the class.id from our earlier training set training.ts.set, and our independent variables for testing IVs.test.

IVs.train = training.ts.set[ , colnames(training.ts.set) != "class.id"]
DV = training.ts.set[ , "class.id"]
IVs.test = test.ts.set[ , colnames(test.ts.set) != "class.id"]

Using these variables in our NNS.reg we store our Point.est as predictions

predictions = NNS.reg(IVs.train, DV, point.est = IVs.test, order = "max", n.best = 1, plot = FALSE, residual.plot = FALSE)$Point.est

Finally, a check of our accuracy yields:

mean(round(predictions) == test.ts.set[ , "class.id"])
## [1] 0.9833333

More seeds

Let’s try 100 different seeds and visualize the results.

results=numeric()

for(i in 1:100){
set.seed(123+i)
test.index = sample(1:600, 120, replace = FALSE)

training.ts.set = series[-test.index, ]
test.ts.set = series[test.index, ]

IVs.train = training.ts.set[,colnames(training.ts.set) != "class.id"]
DV = training.ts.set[, "class.id"]
IVs.test = test.ts.set[,colnames(test.ts.set) != "class.id"]

predictions = NNS.reg(IVs.train, DV, point.est = IVs.test, order = "max", n.best = 1, plot = FALSE, residual.plot = FALSE)$Point.est

results[i] = mean(round(predictions) == test.ts.set[ , "class.id"])
}

hist(results)

mean(results); sd(results)
## [1] 0.9861667
## [1] 0.00999579

Comments

By reducing the order parameter in the NNS.reg function, we can encode the time series with its regression points, which are clusters, thus permitting larger time-series analysis. This is an active area of development. Also, partial time-series matching is another area of active development.

If you found this presentation interesting or useful, please feel free to reach out via e-mail:

Thanks for your interest!