Skip to content

Train Ordinal Model (Proportional Odds) Node

AI/ML/Ordinal

Fit/Train a proportional-odds model on a target whose levels are ORDERED (1 < 2 < ... < 5, or low < medium < high). Use this instead of a classifier, which treats the levels as unrelated names and so counts predicting `low` for `high` as no worse than predicting `medium`. Use it instead of a regressor, which treats the levels as real numbers and so invents distances the levels do not carry (`high` is not exactly twice `medium`). The model learns one coefficient vector plus ordered cut points, which keeps predictions monotone in the score and, under the default loss, yields calibrated per-level probabilities. Link Function, Loss and Margin widen it to the whole threshold-model family, up to support vector ordinal regression, while Free Features relaxes the shared coefficient into one slope per cut point. Scale your features first with the Fit Feature Scaler node: this is a gradient fit, and unscaled columns make it converge slowly or not at all.

fit_ordinal_logisticml
Inputs11
Outputs6
Security exposure6/10
Packageml

Ratings

Scores range from 0 to 10. Higher values mean more impact, exposure, or operational weight.

SecurityAttack surface and exposure impact.
6/10Medium
PrivacyPotential sensitivity of processed data.
6/10Medium
PerformanceRuntime or resource pressure.
7/10High
GovernancePolicy, audit, or compliance impact.
8/10High
ReliabilityOperational stability considerations.
7/10High
CostExternal or compute cost impact.
7/10High

Input Pins

11

Input

Execution
exec_in

Execution trigger that begins ordinal model training

Data Source

String
source

Choose which backend supplies the training data

Default Database
Database

Class Order

String
class_order

Comma-separated level labels from LOWEST to HIGHEST, e.g. `low, medium, high`. Leave empty when the levels are numeric and their numeric order is the order you want. Non-numeric labels have no inferable order, so training fails rather than guessing one.

Link Function

String
link

The CDF sitting behind the cut points, i.e. which latent distribution you assume produced the levels. Logit gives the proportional-odds model and coefficients that read as log odds ratios. Probit assumes a normally distributed latent variable and is the convention in econometrics and the social sciences. CLogLog is asymmetric — it leaves the bottom level quickly and approaches the top one slowly — which is the right shape for `time until something escalates` targets. Cauchit is heavy-tailed, so extreme rows pull the fit far less than they do under Logit or Probit. Applies to the CumulativeLink loss only: the two threshold losses use a logistic margin and ignore this.

Default Logit
LogitProbitCLogLogCauchit

Loss

String
loss

What the optimizer actually minimizes. CumulativeLink maximizes the likelihood of each level and is the ONLY choice that carries a probability model — the confidence value on the Predict node comes from it. AllThreshold penalizes every cut point that falls on the wrong side of the observation, ImmediateThreshold only the two bracketing it; both drop the proportional-odds assumption and are often more robust when it fails, but they fit cut-point placement rather than a likelihood, so the resulting model yields NO per-level probabilities and Predict returns no confidence.

Default CumulativeLink
CumulativeLinkAllThresholdImmediateThreshold

Margin

String
margin

Shape of the penalty a cut point pays for sitting on the wrong side of an observation. Hinge charges nothing once the cut point clears the margin, so only the observations NEAR a cut point influence the fit at all: Hinge together with the AllThreshold loss IS support vector ordinal regression (Chu & Keerthi's implicit-constraint SVOR), and with ImmediateThreshold it is the explicit-constraint variant. SquaredHinge is the differentiable version of that kink — smoother gradients, but distant violations are punished quadratically, so single outliers drag the cut points. Logistic is smooth everywhere and charges even well-placed cut points a little. IGNORED by the default CumulativeLink loss, which maximizes a likelihood and has no margin.

Default Logistic
LogisticHingeSquaredHinge

Free Features

String
free_features

Comma-separated feature INDICES (0-based, e.g. `0, 3`) that get their own coefficient at EVERY cut point instead of one shared across all of them — the partial proportional-odds model. Empty is the standard model, where a single slope describes every cut point; that is an assumption. Free a feature when you suspect it violates it, then check the Effective Coefficients output: a feature whose per-cut slopes barely differ gained nothing by being freed. Freeing only the ones that do differ keeps every other feature parsimonious. Listing every index gives the fully generalized ordinal model. The price shows up on Crossing Rate: unconstrained per-cut slopes let the cumulative curves cross, which is no longer a valid probability model.

Alpha (L2 Penalty)

Float
alpha

Strength of the L2 penalty on the coefficients; the cut points are never penalized. 0 fits unpenalized. Raise it when the fit diverges or the coefficients blow up.

Default 1
Range 0 to 1000

Max Iterations

Integer
max_iterations

Iteration cap for the Adam optimizer. Training stops here even if the objective is still moving, which is reported on the Converged pin.

Default 500
Range 1 to 1000000

Tolerance

Float
tolerance

Relative change in the objective below which training stops. Smaller values fit tighter but need more iterations; 0 always runs the full iteration budget.

Default 1e-7
Range 0 to 1

Learning Rate

Float
learning_rate

Adam step size. Lower it if training oscillates or produces non-finite values; raise it if the model has not converged within Max Iterations.

Default 0.1
Range 0.000001 to 10

Output Pins

6

Done

Execution
exec_out

Activated once training completes

Model

Struct
model

Thread-safe handle to the trained proportional-odds model. Predictions come back as your original level labels.

NodeMLModelNodeMLModel1 fields
model_refstringrequired
Schema enforced

Levels

Struct
levels

The level order the model was actually trained on, lowest first, plus whether it came from your Class Order list (Explicit) or from reading the labels as numbers (Numeric). Check this first when an ordinal model behaves oddly.

OrdinalLevelsOrdinalLevels2 fields
labelsArray<string>required

Level labels from lowest to highest; the index is the rank the model was trained on.

itemsstringarray item
orderingOrdinalOrderingrequired

Where the ordering came from.

variant 1constvariant

Every distinct label parsed as a number, so the order is the numeric one.

const "Numeric"
variant 2constvariant

The caller supplied the order explicitly.

const "Explicit"

Converged

Boolean
converged

False when the optimizer hit Max Iterations before the objective settled. The model is still usable but under-fitted.

Crossing Rate

Float
crossing_rate

Share of training rows (0.0 to 1.0) whose cumulative curves crossed, i.e. where the fit put P(y <= k) ABOVE P(y <= k+1) and so implied a negative probability for a level. Always 0.0 without Free Features, because a shared slope cannot cross. Anything above 0 means the generalized fit is no longer a clean probability model: prediction clamps and renormalizes so nothing downstream sees a negative number, but the per-level probabilities stop being trustworthy — free fewer features, or go back to the shared model.

Effective Coefficients

Struct
effective_coefficients

The coefficient of every feature at every cut point, one row per cut point from lowest to highest, next to the cut points themselves. Shared features repeat the same value down every row; freed ones vary, and the reported spread (largest minus smallest over the cut points) is how you tell whether freeing a feature bought anything — a spread near zero means one shared slope fitted it just as well and the extra parameters were wasted.

OrdinalEffectiveCoefficientsOrdinalEffectiveCoefficients6 fields
per_thresholdArray<Array<number:double>>required

One row per cut point, lowest cut first, each row holding one coefficient per feature in column order. A shared feature repeats the same value down every row; a freed one varies.

itemsArray<number:double>array item
itemsnumber:doublearray item
format double
thresholdsArray<number:double>required

The fitted cut points on the latent scale, strictly increasing, aligned row for row with `per_threshold`

itemsnumber:doublearray item
format double
free_featuresArray<integer:uint>required

Feature indices that were freed, sorted and de-duplicated as the fit received them

itemsinteger:uintarray item
format uintmin 0
free_feature_spreadArray<FreeFeatureSpread>required

One entry per freed feature, widest spread first

itemsFreeFeatureSpreadarray item

How far one freed feature's coefficient moves across the cut points

indexinteger:uintrequired

Position of the feature inside the training vector

format uintmin 0
minnumber:doublerequired

Smallest coefficient the feature took at any cut point

format double
maxnumber:doublerequired

Largest coefficient the feature took at any cut point

format double
spreadnumber:doublerequired

`max - min`. Near zero means one shared slope described the feature just as well, so freeing it only spent parameters.

format double
n_featuresinteger:uintrequired

Number of feature columns

format uintmin 0
n_thresholdsinteger:uintrequired

Number of cut points, i.e. one less than the number of levels

format uintmin 0

Node Info

Internal name
fit_ordinal_logistic
Category
AI/ML/Ordinal
Version
3