How to preprocess data for the Dakota engine¶
Goal: turn a dataframe with your own column names and scales into the
standardized x1, x2, … / y1, y2, … files the Dakota engine expects — and
turn results back the other way, into your original names and scales.
Map and fit¶
from itis_sumo.preprocess.data_preprocessor import DataPreprocessor
preprocessor = DataPreprocessor()
preprocessor.setup_variables(
input_vars=["length", "width"], output_vars=["stress"],
) # length -> x1, width -> x2, stress -> y1
preprocessor.fit(train_raw) # computes normalization stats, if any
train_processed = preprocessor.transform(train_raw)
train_processed.to_csv(training_file, sep=" ", index=False)
setup_variables alone is enough to run — normalization and sign-switching
are both opt-in.
Add normalization or sign-switching (optional)¶
preprocessor.setup_normalization(
input_normalizations={"length": "z_score"},
output_normalizations={"stress": "min_max"},
)
preprocessor.setup_sign_switching(output_sign_switches=["stress"])
Call these before fit() — fit() is what computes the actual
mean/std or min/max from your data; calling it after fit() leaves those
stats uncomputed and normalization silently does nothing (a warning is
logged, not an exception).
normalization_method:"z_score"or"min_max"per variable.- Sign-switching negates the variable both directions — useful when Dakota's variable-bound assumptions (e.g. MOGA's uniform lower/upper bounds) fit a positive-going convention better than your raw data's sign.
Bring predictions back to your own scale¶
predictions = {"y1": preds["y1_hat"]} # mapped-name keys, as returned by evaluate_sumo
original_scale = preprocessor.inverse_transform(predictions)
# {"stress": [...]} -- original name, denormalized/sign-restored
inverse_transform accepts a dict, a DataFrame, or an ndarray (ndarray
form needs column order to match input_variables then output_variables,
since there are no column names to key off of).
Persist and reload (across processes / requests)¶
preprocessor.save_config(run_dir / "preprocessor_config.json")
# ...later, possibly a different process...
reloaded = DataPreprocessor().load_config(run_dir / "preprocessor_config.json")
reloaded.inverse_transform(predictions)
load_config restores a preprocessor already marked fitted — you can call
inverse_transform on it directly without re-fitting, as long as the saved
config came from a preprocessor that was actually fitted.
Filter variables without starting over¶
If you set up a preprocessor with more variables than you end up training on:
preprocessor.filter_by_names(input_names=["length"], exclude=True) # drop "length"
# or: preprocessor.filter_by_patterns(input_patterns=[r"^geom_"])
This re-derives the x1, x2, … mapping over the remaining variables
(filtering renumbers the mapped names), so do it once, up front — not
between a fit()/transform() pair on the same run.
Full class reference: Reference → Data preprocessing.