Skip to content

This feature is currently in Preview.

Predict on a flat table with RelFM Tabular

RelFMTabular is a standalone alternative to RelFM for data that’s already one flat table per split — features and the label are all on the same row. It skips the relational setup entirely: no Graph, no PropertyTransformer, no shared entity Concept across splits, and no Relationship wrapping a split. Each of context, validation, and the domain you predict for is simply its own Concept.

Reach for RelFMTabular when your data doesn’t need multi-table joins to produce features — a single denormalized table already has everything the model needs per row.

RelFMTabular is a thin factory: pass task_type and it dispatches to one of two classes with disjoint parameters and validation. Construct the subclass directly if you want static type-checking for exactly which parameters apply.

task_typeClassUse for
"binary_classification", "multiclass_classification", "regression"RelFMTabularPredictorOne prediction per row of a domain table
"forecasting"RelFMTabularForecasterFuture values over a time-indexed panel/history table

Both share the same core parameters—database, schema, context, label_column, validation, eval_metric—as well as the job-control and tuning knobs described below. Neither has a training step: context is used directly as in-context examples, just as with RelFM.

ParameterDescriptionDefault
test_batch_sizeBatch size used during inference.256
stream_logsStream job logs to stdout.True
dataset_aliasA user-chosen alias for the dataset, used to name the tables exported to database/schema.context’s Concept name
device"cpu" or "cuda"."cpu"
n_estimatorsEnsemble size. Higher improves quality at the cost of slower inference.8
random_stateSeed for ensemble generation and context sampling.42
sample_sizeMax rows of context sampled as in-context examples. None uses all rows.None
sampling_strategyHow to draw the context sample: "stratified", "most_recent", "mixed", "random", or "balanced"."stratified"
quantile_levelsQuantile levels output when regression_output="distribution" or for forecasting tasks.None (uses [0.1, 0.5, 0.9])
norm_methodsFeature normalization applied before inference: "none", "power" (Yeo-Johnson), "quantile", "quantile_rtdl", or "robust". Pass a list to use different methods across ensemble members. None uses ["none", "power"].None
clamp_minRegression only. Lower bound on predictions (as a percentile).0
clamp_maxRegression only. Upper bound on predictions (as a percentile).100
regression_outputRegression only. "point" returns a single estimate; "distribution" also returns the quantiles in quantile_levels."point"

Unlike RelFM, there’s no graph, property_transformer, source_concept, has_time_column, use_current_time, or parallel_reasoners_init — RelFMTabular has no relational graph to traverse and no separate Logic-reasoner setup.

context must be identified by a single natural-key property (a composite identity across more than one property isn’t supported) and include label_column among its own properties:

from relationalai.semantics.reasoners.predictive import RelFMTabular
relfm_tabular = RelFMTabular(
database="MYDB", schema="MYSCHEMA",
context=Customer, label_column="lifetime_value",
task_type="regression", eval_metric="rmse",
)
Customer.predictions = relfm_tabular.predictions(domain=TestCustomer)

domain (here TestCustomer) must also be identified by a single natural-key property and include the same feature columns as context, excluding label_column. The returned relationship exposes .predicted_value for regression, or .probs/.predicted_labels for classification — the same shape as RelFM’s output.

Forecasting uses context differently: it’s a history/panel table naturally identified by (item_id_column, time_column) together — a composite identity, unlike the predictor’s single natural key.

ParameterDescriptionRequired
time_columnThe datetime property name on context/validation/the forecast() domain.Yes
max_context_lengthHow many time steps of history to look back over.Yes
item_id_columnProperty name that identifies the series. Omit for a single-series forecast, or set it to partition context into multiple series (e.g. one series per store) for panel forecasting.No
relfm_forecast = RelFMTabular(
database="MYDB", schema="MYSCHEMA",
context=SalesHistory, label_column="sales",
time_column="date", item_id_column="storeid",
max_context_length=60,
task_type="forecasting",
)
FutureWindow.forecast = relfm_forecast.forecast(domain=FutureWindow)

domain (here FutureWindow) carries the future (item_id, time) rows to forecast for — no label_column, but time_column (and item_id_column, for panel forecasting) present. The forecast lands exactly on domain’s own (item_id, time) rows, so each series can ask for its own dates at its own spacing. A couple of things are rejected before the job runs:

  • An item in domain that has no matching history in context.
  • A duplicate (item_id, time) row in domain.

The output relationship exposes .predicted_value (point estimate), plus one quantile_<level> property per level when quantile_levels is set — e.g. quantile_10/quantile_50/quantile_90 for [0.1, 0.5, 0.9].

For eval_metric on forecasting tasks, the valid values are "mae", "rmse", and "mape".

Both classes support .score(domain=...), evaluating against a labeled domain and returning {"metric_name": str, "metrics": dict[str, float]}. Omit domain to score against the validation Concept passed to the constructor:

relfm_tabular.score(domain=ValidationCustomer)

If your data instead spans multiple related tables — and you’d rather let an estimator pull in features across joins than flatten everything yourself — see Predict with RelFM or Configure and train a GNN.