TEC-DATA85-08 · Lesson 2 · 12 clock hours · lab
Data Preparation and Feature Engineering for ML
Objective. Students will apply train/validation/test splitting, handle missing values, encode categorical variables, and scale numerical features inside a scikit-learn Pipeline object.
⚠ Pending professional review
This lesson, its worked examples and its practice questions has not yet been verified by an industry-certified professional or by a certification or approval body. It is a study draft and may contain errors. Do not use it as instructions for work on a job site or on live equipment. Always follow your instructor, your supervising professional, and current official references and regulations.
VoTechWorks program approval and accreditation are still in progress. Credentials are issued only by the certifying bodies named in each program, after their own exams.
Why Data Preparation Matters in Machine Learning
A machine learning model learns patterns from numbers. Raw, real-world datasets almost never arrive in that ideal state. They contain missing values, text categories that algorithms cannot read, and numerical columns measured on wildly different scales. Skipping preparation steps does not just reduce accuracy — it can produce models that appear to work during training but fail silently in production. Disciplined data preparation is therefore the foundation of every reliable ML workflow.
The Train / Validation / Test Split
Before touching any data transformations, you must split your dataset. The standard three-way split serves distinct purposes:
- Training set — the data the model learns from.
- Validation set — held out during training; used to tune hyperparameters and compare model versions.
- Test set — touched exactly once, after all decisions are final, to report honest performance.
A common ratio is 70 % training, 15 % validation, 15 % test. Use `train_test_split` from scikit-learn twice: first to carve off the test set, then to split the remainder into training and validation. Always set a `random_state` value so your split is reproducible. Stratify on the target column when the classes are imbalanced so each split contains a representative proportion of each class.
Data Leakage — The Critical Safety Rule
Data leakage means information from outside the training set influences the model during fitting. The most common form is fit-on-test leakage: fitting a scaler or imputer on the full dataset before splitting, so statistics from test rows contaminate the training process. This produces optimistic evaluation scores that will not hold in production — a silent, expensive failure.
Rule: fit all transformers only on training data. Transform validation and test data using those already-fitted transformers.
This is not optional. Treat it the same way you would treat a workplace safety rule: violating it creates harm that may not be visible until later, and at significant cost.
Handling Missing Values with SimpleImputer
Missing values appear as `NaN` in a pandas DataFrame. Two strategies cover most cases:
- Mean or median imputation — replace each missing number with the column mean (sensitive to outliers) or median (more robust). Fit the imputer on training data; it stores that mean or median and applies it to new data.
- Most-frequent imputation — replace missing categories with the most common value in that column.
Never drop rows with missing values from your test set; real production data will have gaps too, and your pipeline must handle them.
Encoding Categorical Variables with OneHotEncoder
Algorithms need numbers. A column containing values like `"Male"`, `"Female"` must be converted. One-hot encoding creates one binary column per unique category. For a column with values `{"Red", "Blue", "Green"}`, the encoder produces three columns: `is_Red`, `is_Blue`, `is_Green`. Set `handle_unknown='ignore'` so the encoder does not crash when a category appears in the test set that was not seen during training.
For ordinal categories where order matters (e.g., `"Low" < "Medium" < "High"`), use `OrdinalEncoder` and specify the order explicitly.
Scaling Numerical Features with StandardScaler
Many algorithms — including logistic regression, support vector machines, and k-nearest neighbors — are sensitive to feature scale. A column ranging from 0 to 1 and a column ranging from 0 to 1,000,000 will not be treated equally without scaling.
StandardScaler subtracts the column mean and divides by the standard deviation, producing a distribution with mean 0 and standard deviation 1. It stores the training mean and standard deviation; those same values are applied to validation and test data — never recalculated on them.
Building a scikit-learn Pipeline with ColumnTransformer
A `Pipeline` chains multiple steps so they behave as a single object. A `ColumnTransformer` applies different transformers to different columns in parallel and concatenates the results. Combining them gives you a single, safe, saveable object.
```python
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
preprocessor = ColumnTransformer(transformers=[
('num', numeric_transformer, numeric_cols),
('cat', categorical_transformer, categorical_cols)
])
```
Call `preprocessor.fit(X_train)` and then `preprocessor.transform(X_val)` and `preprocessor.transform(X_test)`. Never call `fit` on validation or test data.
Saving the Pipeline
Save the fitted pipeline with `joblib.dump(preprocessor, 'pipeline.pkl')`. This lets you apply the exact same transformations to new data in production without recomputing statistics. Load it later with `joblib.load('pipeline.pkl')`.
Workspace Habits
Always document which columns are numeric and which are categorical at the top of your notebook. Version-control your notebook alongside your pickle file. During peer review, confirm that no `fit` or `fit_transform` call is made on validation or test arrays — this is the leakage-check step and it must be completed before a notebook is considered complete.
Key terms8
Data leakageThe introduction of information from the validation or test set into the model training process, causing overly optimistic performance estimates that do not hold on new data.
Train/validation/test splitThe division of a dataset into three non-overlapping subsets used, respectively, for learning, hyperparameter tuning, and final unbiased evaluation.
SimpleImputerA scikit-learn transformer that replaces missing values in a dataset using a statistic such as mean, median, or most-frequent value, computed only from training data.
OneHotEncoderA scikit-learn transformer that converts a categorical column into a set of binary columns, one per unique category, so that algorithms can process text categories as numbers.
StandardScalerA scikit-learn transformer that rescales numerical features to zero mean and unit standard deviation, using statistics fit only on training data.
PipelineA scikit-learn object that chains a sequence of transformation steps and an optional final estimator into a single callable unit, enforcing the correct fit/transform order.
ColumnTransformerA scikit-learn utility that applies different transformer pipelines to different subsets of columns in parallel and concatenates the results into a single array.
Feature engineeringThe process of selecting, transforming, and creating input variables from raw data to improve a machine learning model's ability to learn useful patterns.
Worked examples4
1. A dataset has 1,000 rows. You apply a 70/15/15 train/validation/test split. How many rows belong to each set?
- Training set: 1,000 × 0.70 = 700 rows.
- Validation set: 1,000 × 0.15 = 150 rows.
- Test set: 1,000 × 0.15 = 150 rows.
- Verify totals: 700 + 150 + 150 = 1,000. ✓
Answer: Training: 700 rows; Validation: 150 rows; Test: 150 rows.
2. A numeric column 'income' has the following five training values: 30,000 | 45,000 | 50,000 | 55,000 | 70,000. A test row contains 60,000. What value does StandardScaler assign to the test row?
- Compute the training mean: (30,000 + 45,000 + 50,000 + 55,000 + 70,000) / 5 = 250,000 / 5 = 50,000.
- Compute each deviation from the mean: −20,000; −5,000; 0; 5,000; 20,000.
- Compute variance: (400,000,000 + 25,000,000 + 0 + 25,000,000 + 400,000,000) / 5 = 850,000,000 / 5 = 170,000,000.
- Compute standard deviation: √170,000,000 ≈ 13,038.
- Scale the test value: (60,000 − 50,000) / 13,038 ≈ 10,000 / 13,038 ≈ 0.767.
Answer: The scaled test value is approximately 0.77 (using the training mean of 50,000 and training standard deviation of approximately 13,038).
3. A column 'color' has three unique training values: Red, Blue, Green. A test row contains the value 'Yellow', which was never in training. How does OneHotEncoder with handle_unknown='ignore' represent this test row?
- The encoder creates three binary columns during fit: is_Red, is_Blue, is_Green.
- For a known value like 'Red', the row would be [1, 0, 0].
- The value 'Yellow' is unknown; with handle_unknown='ignore', all three columns are set to 0.
- The result is [0, 0, 0], representing an unknown category without raising an error.
Answer: The test row is encoded as [0, 0, 0] — all binary columns are zero — and no error is raised.
4. A numeric column 'age' in your training set has missing values. The non-missing training values are: 25, 30, 35, 40, 45, 100. Should you use mean or median imputation, and what value would each strategy produce?
- Mean: (25 + 30 + 35 + 40 + 45 + 100) / 6 = 275 / 6 ≈ 45.8. The outlier 100 pulls the mean upward significantly.
- Median: Sort values — 25, 30, 35, 40, 45, 100. With six values, the median is the average of the 3rd and 4th: (35 + 40) / 2 = 37.5.
- Because 100 is a likely outlier, the median (37.5) is more representative of a typical age in this column.
- Choose median imputation for robustness against outliers.
Answer: Mean ≈ 45.8; Median = 37.5. Median imputation is preferred here because the outlier value of 100 inflates the mean, making it unrepresentative of most rows.
The math in this lesson1
Learners apply 70/15/15 percentages to split 1,000 rows into train, validation and test sets.
7.RP.3
In class: Instructor-led demo: load the UCI Adult Income dataset, profile missing values, and walk through a ColumnTransformer pipeline combining SimpleImputer, OneHotEncoder, and StandardScaler; students replicate step by step. · Lab exercise: students receive a messy tabular dataset (housing or employee data) and must produce a clean, split, and transformed set of X_train, X_val, X_test arrays with a saved pipeline pickle file. · Peer review: pairs exchange notebooks and verify that no test-set rows appear in the training pipeline fit step; document findings in a short leakage-check checklist.
Materials: Jupyter Lab, pandas, scikit-learn Pipeline/ColumnTransformer docs, UCI ML Repository datasets, leakage-check checklist handout
Check: Instructor inspects notebook for correct split ratios (e.g., 70/15/15), absence of data leakage, and a runnable pipeline; all three criteria must be met for pass.
Practice check8
Answer each question, then check it. Nothing is recorded; this is your own practice.
Record this lesson on my transcript. Sign in with your key and enrollment email to record lessons (enroll free if you have no key). This page stays open to read and practise.