library(NNS)
library(data.table)
require(knitr)
require(rgl)
require(meboot)NNS.reg is a very robust regression
technique capable of nonlinear regressions of continuous variables and
classification tasks in machine learning problems.
We have extended the NNS.reg
applications per the use of an ensemble method of classification in
NNS.boost.
One major advantage NNS.boost has over tree
based methods is the ability to seamlessly extrapolate beyond the
current range of observations.
Popular boosting algorithms take a series of weak learning decision
tree models, and aggregate their outputs. NNS is also a
decision tree of sorts, by partitioning each regressor with respect to
the dependent variable. We can directly control the number of “splits”
with the NNS.reg(..., order = , ...)
parameter.
We can see how NNS partitions each regressor by calling
the $rhs.partitions output. You will notice that each
partition is not an equal interval, nor of equal length, which
differentiates NNS from other bandwidth or tree-based
techniques.
Higher dependence between a regressor and the dependent variable will
allow for a larger number of partitions. This is determined internally
with the NNS.dep measure.
NNS.reg(iris[,1:4], iris[,5], residual.plot = FALSE, ncores = 1)$rhs.partitions## V1 V2 V3 V4
## 1: 4.3 2.0 1.000000 0.1
## 2: 4.4 2.2 1.100000 0.2
## 3: 4.5 2.3 1.200000 0.3
## 4: 4.6 2.4 1.300000 0.4
## 5: 4.7 2.5 1.400000 0.5
## 6: 4.8 2.6 1.500000 0.6
## 7: 4.9 2.7 1.600000 1.0
## 8: 5.0 2.8 1.700000 1.1
## 9: 5.1 2.9 1.900000 1.2
## 10: 5.2 3.0 3.000000 1.3
## 11: 5.3 3.1 3.300000 1.4
## 12: 5.4 3.2 3.500000 1.5
## 13: 5.5 3.3 3.600000 1.6
## 14: 5.6 3.4 3.700000 1.7
## 15: 5.7 3.5 3.800000 1.8
## 16: 5.8 3.6 3.900000 1.9
## 17: 5.9 3.7 4.000000 2.0
## 18: 6.0 3.8 4.100000 2.1
## 19: 6.1 3.9 4.200000 2.2
## 20: 6.2 4.0 4.300000 2.3
## 21: 6.3 4.1 4.400000 2.4
## 22: 6.4 4.2 4.500000 2.5
## 23: 6.5 4.4 4.600000 NA
## 24: 6.6 NA 4.700000 NA
## 25: 6.7 NA 4.800000 NA
## 26: 6.8 NA 4.900000 NA
## 27: 6.9 NA 5.000000 NA
## 28: 7.0 NA 5.100000 NA
## 29: 7.1 NA 5.200000 NA
## 30: 7.2 NA 5.300000 NA
## 31: 7.3 NA 5.400000 NA
## 32: 7.4 NA 5.500000 NA
## 33: 7.6 NA 5.600000 NA
## 34: 7.7 NA 5.700000 NA
## 35: 7.9 NA 5.800000 NA
## 36: NA NA 5.900000 NA
## 37: NA NA 6.000000 NA
## 38: NA NA 6.100000 NA
## 39: NA NA 6.300000 NA
## 40: NA NA 6.350000 NA
## 41: NA NA 6.352852 NA
## 42: NA NA 6.353125 NA
## 43: NA NA 6.600000 NA
## 44: NA NA 6.700000 NA
## 45: NA NA 6.900000 NA
## V1 V2 V3 V4
NNS.boost()Through resampling of the training set and letting each iterated set of data speak for themselves (while paying extra attention to the residuals throughout), we can test various regressor combinations in these dynamic decision trees…only keeping those combinations that add predictive value. From there we simply aggregate the predictions.
NNS.boost will automatically search for
an accuracy threshold from the training set, reporting
iterations remaining and level obtained in the console. A plot of the
frequency of the learning accuracy on the training set is also
provided.
Once a threshold is obtained,
NNS.boost will test various feature
combinations against different splits of the training set and report
back the frequency of each regressor used in the final estimate.
Let’s have a look and see how it works. We use 140 random
iris observations as our training set with the 10 holdout
observations as our test set. For brevity, we set
epochs = 10, learner.trials = 10, folds = 1.
NOTE: Base category of response variable should be 1, not 0
for classification problems when using
NNS.boost(..., type = "CLASS").
set.seed(1234)
test.set = sample(150, 10)
a = NNS.boost(IVs.train = iris[-test.set, 1:4],
DV.train = iris[-test.set, 5],
IVs.test = iris[test.set, 1:4],
epochs = 10, learner.trials = 10,
status = FALSE, balance = TRUE,
type = "CLASS", folds = 1)a$results## [1] 1 2 3 3 3 3 3 3 2 3
a$feature.weights## Petal.Width Sepal.Width Sepal.Length Petal.Length
## 0.2857143 0.2857143 0.2857143 0.1428571
mean( a$results == as.numeric(iris[test.set, 5]) )## [1] 1
A perfect classification.
NNS.stack()The NNS.stack() routine cross-validates
for a given objective function the n.best parameter in the
multivariate NNS.reg function as well as
the threshold parameter in the dimension reduction
NNS.reg version.
NNS.stack can be used for classification
via
NNS.stack(..., type = "CLASS", ...).
For brevity, we set folds = 1.
NOTE: Base category of response variable should be 1, not 0
for classification problems when using
NNS.stack(..., type = "CLASS").
b = NNS.stack(IVs.train = iris[-test.set, 1:4],
DV.train = iris[-test.set, 5],
IVs.test = iris[test.set, 1:4],
type = "CLASS", balance = TRUE,
ncores = 1, folds = 1)
b$OBJfn.reg
[1] 1
$NNS.reg.n.best
[1] 1
$probability.threshold
[1] 0.44625
$OBJfn.dim.red
[1] 0.9477124
$NNS.dim.red.threshold
[1] 0.495
$reg
[1] 1 2 3 3 3 3 3 3 2 3
$dim.red
[1] 1 2 3 3 3 3 3 3 2 3
$stack
[1] 1 2 3 3 3 3 3 3 2 3mean( b$stack == as.numeric(iris[test.set, 5]) )[1] 1depth = "max" will force all observations to be
their own partition, forcing a perfect fit of the multivariate
regression. In essence, this is the basis for a kNN nearest
neighbor type of classification.
n.best = 1 will use the single nearest neighbor.
When coupled with depth = "max", NNS will
emulate a kNN = 1 but as the dimensions increase the
results diverge demonstrating NNS is less sensitive to the
curse of dimensionality than kNN.
extreme will use the maximum or minimum
threshold obtained, and may result in errors if that
threshold cannot be eclipsed by subsequent iterations.
If the user is so motivated, detailed arguments further examples are provided within the following: