Reusable ML Patterns¶
This page covers reusable patterns for keeping labels, weights, and domain information in the data. Predictors and validators read those coordinates directly, so multilabel prediction, sample weighting, and few-shot domain transfer use the same pipeline machinery as simpler workflows.
Multilabel Classification¶
Use SKLearnPredictor with is_multilabel=True when each target is a binary coordinate. The targets remain named coordinates instead of a separate y matrix.
from sklearn.linear_model import LogisticRegression
from xdflow.transforms.sklearn_transform import SKLearnPredictor
predictor = SKLearnPredictor(
LogisticRegression,
sample_dim="trial",
target_coord=["target__ethanol", "target__hexanal", "target__limonene"],
is_classifier=True,
is_multilabel=True,
max_iter=500,
)
predictor.fit(train_container)
predictions = predictor.predict(test_container) # dims: ("trial", "target")
probabilities = predictor.predict_proba(test_container) # dims: ("trial", "target")
For wildcard target coordinates, pass a pattern such as target_coord="target__*". XDFlow resolves the target coordinates at fit time and wraps compatible sklearn classifiers with MultiOutputClassifier.
Class and Domain Weighting¶
Use BalanceClassWeightTransform to attach a sample_weight coordinate that downstream sklearn-compatible estimators can consume. Weighting stays in the container, so it can move with the same trial axis as the labels and metadata.
from sklearn.linear_model import LogisticRegression
from xdflow.composite import Pipeline
from xdflow.transforms.basic_transforms import BalanceClassWeightTransform
from xdflow.transforms.sklearn_transform import SKLearnPredictor
pipeline = Pipeline(
name="balanced_classifier",
steps=[
("weights", BalanceClassWeightTransform(class_coord="stimulus")),
("clf", SKLearnPredictor(LogisticRegression, sample_dim="trial", target_coord="stimulus")),
],
)
For transfer settings, balance within domains while assigning domain-level totals:
weights = BalanceClassWeightTransform(
class_coord="stimulus",
balance_domains=True,
domain_coord="animal",
domain_weights={"source": 0.25, "target": 0.75},
normalize_domain_totals=True,
weight_normalize="sum",
)
The default sklearn wrappers look for a sample_weight coordinate. Pass sample_weight_coord=None to disable this behavior.
Few-Shot Domain Transfer¶
Use SampledDomainKFoldValidator when validation should occur only on target-domain folds, while training uses all source-domain samples plus a controlled number of target-domain samples. The domain policy is part of the validator configuration instead of a custom split script.
from sklearn.linear_model import LogisticRegression
from xdflow.composite import Pipeline
from xdflow.cv import SampledDomainKFoldValidator
from xdflow.transforms.sklearn_transform import SKLearnPredictor
pipeline = Pipeline(
name="few_shot_transfer",
steps=[
("clf", SKLearnPredictor(LogisticRegression, sample_dim="trial", target_coord="stimulus")),
],
)
cv = SampledDomainKFoldValidator(
domain_coord="animal",
source_domains=["animal_a", "animal_b"],
target_domains="animal_c",
label_coord="stimulus",
default_samples_per_label=2,
label_sample_counts={"control": None},
n_splits=5,
random_state=0,
verbose=False,
)
cv.set_pipeline(pipeline)
score = cv.cross_validate(data_container, verbose=False)
Sampling semantics:
default_samples_per_label=0: zero-shot target training for labels not otherwise specifieddefault_samples_per_label=2: two target-domain samples per label per foldlabel_sample_counts={"control": None}: use all available target-domain training samples forcontrol- source-domain trials are included in every fold unless
source_domainsexcludes them
This validator is intentionally domain-agnostic. Domain labels can represent animals, subjects, sessions, instruments, sites, or any other sample-level grouping.