Open-source agentic AI for transaction monitoring. Just ask Jooby.What's Jube? →

Bagging Classifier

Procedure: bagging classifier

Plain bagging is the random forest’s ingredient without the restricted split candidates: every tree sees every variable at every split, and only the bootstrap resampling decorrelates the ensemble.

library(ipred)

set.seed(1)
n <- 200
amount <- c(rnorm(n / 2, mean = 40, sd = 15), rnorm(n / 2, mean = 220, sd = 60))
velocity <- c(rpois(n / 2, 2), rpois(n / 2, 9))
fraud <- factor(c(rep(0, n / 2), rep(1, n / 2)))
train <- data.frame(amount, velocity, fraud)

model <- bagging(fraud ~ amount + velocity, data = train, nbagg = 100,
                  coob = TRUE)
print(model)

new_cases <- data.frame(amount = c(35, 260), velocity = c(1, 10))
predict(model, new_cases, type = "prob")

Console output:


Bagging classification trees with 100 bootstrap replications 

Call: bagging.data.frame(formula = fraud ~ amount + velocity, data = train, 
    nbagg = 100, coob = TRUE)

Out-of-bag estimate of misclassification error:  0 

     0 1
[1,] 1 0
[2,] 0 1

Tool equivalent: Jube.Service.Repository.AnalyticsTrainingRun.AdvancedAnalyticsBaggingClassifierTrainingService / tool SubmitBaggingClassifierTraining — Kind = Classifier, recall class BaggingClassifierRecall. The DTO exposes TreeCount, MaxDepth, MinLeafSize and SampleFraction but no feature-fraction field at all (ipred’s nbagg/tree depth match one-for-one; there is no mtry-equivalent to set, since bagging by definition offers every variable at every split). Calibrate and DecisionThreshold work exactly as in the forest.

Code audit

SubmitTrainingAsync (Jube.Service/Repository/AnalyticsTrainingRun/AdvancedAnalyticsBaggingClassifierTrainingService.cs) only validates and queues a run; the actual training runs when AdvancedAnalyticsTrainingWorker calls AdvancedAnalyticsBaggingClassifierTrainingExecutor.ExecuteAsync (Jube.Engine/AdvancedAnalytics/Training/AdvancedAnalyticsTrainingWorker.cs:857-859), whose Trainer delegate defaults to BaggingClassifierTrainer.Train (Jube.Engine/AdvancedAnalytics/Classification/BaggingClassifierTrainer.cs:37-59).

No Accord.NET dependency

BaggingClassifierTrainer.cs has no using Accord.*. The trees, the bootstrap loop and the out-of-bag estimate are a hand-written implementation local to this file and Jube.Engine/AdvancedAnalytics/Classification/BaggingTree.cs; nothing is instantiated from Accord.MachineLearning.

Near-duplicate of the random forest trainer, minus feature subsampling

The two trainer files are otherwise almost line-for-line identical (same imputation, same standardisation bookkeeping for reporting only, same Parallel.For bootstrap loop, same DeriveSeed formula unchecked(seed * 7919 + index * 104729 + 17), same Platt calibration call, same warning codes, same Metrics helper shape). The one substantive algorithmic difference is in BuildTree (BaggingClassifierTrainer.cs:370-457): the candidate-feature loop is for (var feature = 0; feature < featureCount; feature++) (line 403) — every variable is a split candidate at every node, with no call to any SampleFeatures-equivalent method and no featuresPerSplit parameter anywhere in the file. This is the textbook distinction between bagging and a random forest (bagging = bootstrap aggregation only; random forest = bagging + restricted feature subsampling per split), and it is genuinely implemented that way here, not merely described that way in the DTO.

Bootstrap sampling

Identical mechanics to the random forest classifier: sampleSize = round(options.SampleFraction * trainDesign.Length) rows drawn with replacement per tree (BaggingClassifierTrainer.cs:158-163), independently seeded per tree. With the default SampleFraction = 1, each tree’s bootstrap sample is the same size as the training split, leaving the standard ~1/e fraction of rows out-of-bag per tree.

Split criterion and aggregation

BuildNode (lines 381-451) uses the same mean * (1 - mean) Gini-proportional impurity and the same midpoint-candidate-threshold search as the random forest classifier, with MinLeafSize enforced on both sides of a candidate split (line 415) and a 1e-12 tie-break tolerance on gain (line 426). BaggingTree.Predict (BaggingTree.cs) returns the leaf’s stored class-1 proportion (NodeProbability), and the ensemble’s raw score (RawScores, BaggingClassifierTrainer.cs:213-228) is the plain average of every tree’s leaf probability — averaged-probability aggregation, the same as the random forest, not a majority hard-vote.

Out-of-bag error: computed and exposed

Structurally identical to the random forest classifier: rows left out of a tree’s bootstrap sample are scored by that tree only (lines 188-194), an out-of-bag ROC AUC is computed via BinaryMetrics.RocAuc over rows with any out-of-bag coverage (lines 199-205) when more than MinimumOutOfBagRows = 10 such rows exist, else an OutOfBagUnavailable warning is recorded (lines 207-211) with no value substituted. This mirrors ipred::bagging’s coob = TRUE out-of-bag misclassification estimate shown in the R console output above, though the product reports AUC rather than a raw misclassification rate.

Calibration

Same Platt-scaling call as the random forest classifier (PlattCalibration.Fit, BaggingClassifierTrainer.cs:234-258), gated on options.Calibrate (default true) and on the validation split containing both classes, with the same calibration-slope sanity checks (CalibrationSlopeLow/CalibrationSlopeHigh, 0.7/1.3, lines 284-292) and DecisionThreshold (default 0.5) applied to the calibrated probability for the reported confusion counts.

Variable importance despite no feature restriction

importance[bestFeature] += rows.Length * bestGain is still accumulated per split (line 440) and normalised across all trees into FeatureImportances (lines 180-183), exactly as in the random forest. Because every variable is always a candidate here, this importance reflects each variable’s typical contribution when competing against every other variable at every split, rather than a random-forest-style importance that also reflects how often a variable was even offered as a candidate.