Checking What Arrives at the Model
A model can produce a number from the wrong columns or units. Define and validate the request before trusting its arithmetic.
13 sections · 4 questions · 2 coding challenges
The arrow keys move between sections too.
Treating Data Expectations as Testable Rules
BOTIE
The tiny contract here checks names, shape, and finite values. A real schema also needs units and domain-specific constraints that cannot be inferred from an array’s dtype.
Sources for this history
What If Temperature Arrives in the Humidity Column?
Botie’s service receives two numbers, just as expected. Yet they are in the wrong order. A shape check passes while the model interprets humidity as temperature.
An input contract states names, order, types, units, allowed missingness, and shape. Validation turns malformed requests into clear errors before they produce misleading predictions.
The candidate batches illustrate width and finiteness checks, not every possible data-quality rule.
Step 1 of 3
Read named fields
Named values can arrive in any object order.
| Incoming field | Value |
|---|---|
| humidity | 25 |
| temperature | 12 |
humidity
- Value
- 25
temperature
- Value
- 12
Step 2 of 3
Apply the saved order
The model’s feature list determines coordinates.
| Saved feature order | Array row |
|---|---|
| temperature | 12 |
| humidity | 25 |
temperature
- Array row
- 12
humidity
- Array row
- 25
Step 3 of 3
Reject malformed data
A missing field is different from an explicit zero.
- Missing temperature
- report an error
Input validation protects the meaning of the fitted columns
Validation checks the data boundary before downstream operations run.
Can this batch safely reach the model?
A row can have the wrong width or contain a value the model cannot calculate with. Try these cases separately and check the result before performing a prediction.
BOTIE
Column means after the batch passes validation
- 02
- 13
Follow the operations
1. Input records
1 2 3 4 2. Required feature count
2
3. Validate a finite feature table
1 2 3 4 4. Mean of each column
- 02
- 13
5. Result
- 02
- 13
This numerical check cannot infer feature names or units. The request parser must enforce those separately.
1. Write the Contract Before the Parser
Let's decide what the service accepts before converting a request to an array. Is it one record or a batch? Which fields must be present, and what happens to unfamiliar fields? The numeric type is not enough to describe a measurement: a float could be Celsius or Fahrenheit.
Categorical fields need a rule for unknown categories. A missing measurement needs either a clear rejection or the saved imputation procedure. Quietly inserting zero would give the model a value with a meaning the caller never supplied.
The examples reject missing or extra fields and non-finite numbers.
2. Build Arrays From Names
Read each field in the saved feature order rather than trusting object insertion order. Convert to a declared numeric dtype, then check the resulting shape.
Reject booleans if the field is a measured quantity rather than a flag. Some languages treat booleans as numbers, so an apparently successful conversion can hide a malformed request.
A correct array shape is necessary but not sufficient for a correct input.
3. Check Values Before Model Arithmetic
NaN and infinity can propagate through calculations and make later failures difficult to interpret. Reject them at the boundary. Bounds should reflect a justified domain rule, not arbitrary clipping that disguises a broken sensor.
Separate validation from scoring. A request that fails validation should not return a normal-looking prediction.
Required shape = (number_of_records, 2)
Feature order = [temperature_c, humidity_percent]
All values must be finiteUnits must be supplied correctly even when a wrong-unit value happens to fall within accepted numeric bounds.
Use feature names to restore the expected order
The record arrived with keys in a different order from the model's saved feature list. Index by the saved names instead of relying on dictionary insertion order.
import numpy as np
features = ['humidity', 'temperature', 'pressure']
record = {'pressure': 1000., 'temperature': 18., 'humidity': 60.}
row = np.array([record[name] for name in features])
print(row.tolist())[60.0, 18.0, 1000.0]The model receives humidity first because that is its saved convention. Practice adds explicit checks for missing or unexpected fields and non-finite values.
4. Test Failure Paths as Carefully as Success
Include swapped fields, missing values, unexpected strings, NaN, empty batches, and wrong widths. Check that the error identifies the failed rule without exposing private record contents.
A schema change is a versioned change to the prediction interface. Coordinate it with preparation and model artifacts so a valid old request is not silently reinterpreted.
Botie’s workshop validates a numerical table, then lets the same data pass downstream.
5. A Number Needs a Name and a Unit
Temperature and humidity can both be valid floating-point values while being assigned to the wrong columns. A parser should build arrays from declared names in a fixed order, rather than trusting the order of keys supplied by the caller.
Units also belong to the interface. Celsius and Fahrenheit values can both look plausible numerically. Either accept one documented unit or perform an explicit conversion before model preprocessing. Do not infer units from the magnitude alone.
6. Construct the Model Row from Names
Validate required fields before calculating a prediction. Missing fields, unknown fields and explicit null values need declared policies. Rejecting unknown fields can reveal a caller's typo; accepting them may be appropriate when a versioned envelope carries other metadata.
This small parser rejects both missing and extra fields and requires finite numerical values. It demonstrates the contract independently of any web framework.
Preserve feature order despite dictionary order
The incoming dictionary lists humidity first, but the model contract lists temperature first.
import numpy as np
def row(record):
names = ['temperature','humidity']
if set(record) != set(names):
raise ValueError('Expected temperature and humidity')
if any(isinstance(record[name], (bool, str)) for name in names):
raise ValueError('Expected numerical measurements')
values = np.array([record[name] for name in names], dtype=float)
if not np.isfinite(values).all():
raise ValueError('Measurements must be finite')
return values
print(row({'humidity': 60., 'temperature': 12.}).tolist())[12.0, 60.0]The caller's key order cannot swap the model's feature meanings. A complete contract can add valid ranges and explicit unit fields.
7. An Error Response Should Identify the Broken Promise
Distinguish a missing measurement from an unsupported unit, a wrong shape and a non-finite value. A caller can correct a specific contract error; a generic failed prediction provides little help.
Keep validation separate from a learned missing-value rule. If the model was trained to impute an allowed missing field, apply that saved policy. If it was not, silently filling zero invents behaviour the model was never evaluated to handle.
Check yourself
Questions on Parts 1 to 7
Question 1 of 4
Which array is correct?
Use the information below.
Saved feature order [temperature,humidity]; record contains named values humidity=25, temperature=12.Try it with Botie
Build with Botie
Write and run Python