Training finishes cleanly, but the first attempt to predict a single new row dies
with ValueError: Expected 2D array, got 1D array instead, often followed by a hint
about reshape. A second flavour: X has 2 features, but LogisticRegression is expecting 3 features as input. A third, quieter one: sklearn warns that feature
names do not match those seen during fit — or nothing errors at all, and predictions
are silently nonsense.
First week with scikit-learn, at the exact moment a model meets genuinely new data:
predicting one customer, wiring a model into a small script, or serving a teammate's
request. The trainee passes a plain Python list (model.predict([1, 95, 260])),
drops a column, or rebuilds the input DataFrame with columns in a different order
than training. Linked module: 1.2 (Full ML loop once, end to end).
Every sklearn model predicts on a table, never a bare row: two dimensions, rows by
columns. A list like [1, 95, 260] is 1D, so sklearn refuses — one row must still
arrive as a table with one row. The feature-count error means the input table has a
different number of columns than the training table; a column was dropped or an extra
one added. The dangerous case is order: models identify features by position (and by
name, when trained on a DataFrame). Values placed in a different order can flow
through without any error when names are absent — days_since_last_order lands where
orders_last_90d belonged, and the prediction is confidently wrong. Confirm by
printing three things side by side: the exact feature list used at fit time,
new_row.shape, and new_row.columns. Any mismatch in count, order, or names is the
failure.
Read the error text first — sklearn's message contains its own fix (reshape(1, -1)
for arrays). The better habit: build every predict-time input as a one-row DataFrame
with named columns, then force the training order with the saved feature list —
pd.DataFrame([{...}])[features]. That one indexing step fixes 1D-vs-2D, catches
missing columns loudly (KeyError names the culprit), and repairs column order in the
same line. For the feature-count error, diff the input's columns against the saved
feature list and rebuild the row; never pad with zeros to silence the message.
Keep one explicit features list as the single source of truth, defined once before
fit and reused everywhere: X = df[features] at training, row[features] at
prediction. Save that list with the model (one dict through joblib) so predict-time
code cannot drift from it. Prefer DataFrames over bare NumPy arrays at predict time —
names turn silent misorder into loud errors. Test the whole path early: right after
saving, load the model and predict one hand-written row before any real caller does.
Q: "Your model trains fine, but predicting one new customer throws a 2D-array error.
What is happening and how do you fix it properly?" Strong answer: explain that
sklearn expects a rows-by-columns table even for one row, name the quick fix
(one-row DataFrame or reshape(1, -1)), then go beyond it — keep an explicit saved
feature list and rebuild predict-time rows with it, because column order and missing
columns are the errors that do not announce themselves. Mentioning the silent
wrong-order case separates engineers from tutorial-followers.