Data Quality, Pre-processing, Transformations, and Imputation
You’re trying to find a suitable date based on:
| Person | Age | #FB Friends | Euclidean Distance Calculation | Distance |
|---|---|---|---|---|
| A | 25 | 400 | \(\sqrt{5^2 + 150^2}\) | 150.08 |
| B | 27 | 300 | \(\sqrt{3^2 + 50^2}\) | 50.09 |
| C | 30 | 500 | \(\sqrt{0^2 + 250^2}\) | 250.00 |
| D | 60 | 250 | \(\sqrt{30^2 + 0^2}\) | 30.00 |
Based on the distances, the two nearest neighbors (2-NN) are:
What’s the problem here?
NaN).Data preprocessing is important in machine learning because data quality directly affects model performance and predictions.
Note
Many classification algorithms are distance-based, meaning that their results can be affected by the units and scales of the input features.
Understanding why data is missing dictates how to fix it.
MCAR (Missing Completely at Random):
Missingness is independent of both observed and unobserved data.
Example: A sensor battery dies randomly.
MAR (Missing at Random):
Missingness depends systematically on observed data, but not on the missing value itself.
Example: Older patients are less likely to report their income, but among patients of the same age, whether income is missing does not depend on their actual income.
MNAR (Missing Not at Random):
Missingness depends directly on the unobserved value itself.
Example: High earners refuse to reveal their high income on surveys.
When dealing with missing values, simple deletion might be considered:
\[ \begin{aligned} \text{Raw Data} &\longrightarrow \text{Cleaning} \longrightarrow \mathbf{\text{Feature Transformation / Scaling}} \\ &\longrightarrow \text{Feature Selection} \longrightarrow \text{Model Training} \end{aligned} \]
Rescales data to centered mean (\(\mu=0\)) and unit variance (\(\sigma=1\)).
\[x' = \frac{x - \mu}{\sigma}\]
Rescales data into a fixed range, typically \([0, 1]\).
\[x' = \frac{x - x_{\min}}{x_{\max} - x_{\min}}\]
| Encoding | How it Works | Pros | Cons |
|---|---|---|---|
| Label / Ordinal | Maps each category to an integer (\(1, 2, 3...\)) | Compact (\(1\) column) | Implies artificial ordering if data is nominal |
| One-Hot | Creates \(K\) binary indicator columns | No artificial order imposed | Causes high dimensionality (\(d \to \infty\)) for high-cardinality features |
| Binary | Converts integers to binary strings, then splits into binary columns | Compact representation (\(O(\log_2 K)\) columns) | Reduces interpretability compared to One-Hot |
Converts continuous variables into categorical intervals:
import numpy as np
from sklearn.preprocessing import (
StandardScaler,
MinMaxScaler,
OneHotEncoder,
OrdinalEncoder,
FunctionTransformer,
KBinsDiscretizer
)
# Scaling
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_numeric)
# Categorical Encoding
ohe = OneHotEncoder(sparse_output=False, drop='first')
X_ohe = ohe.fit_transform(X_categorical)
# Binning (Equal Frequency)
binner = KBinsDiscretizer(n_bins=4, encode='ordinal', strategy='quantile')
X_binned = binner.fit_transform(X_numeric)
# Custom Nonlinear Transformation
log_transformer = FunctionTransformer(np.log1p)
X_log = log_transformer.fit_transform(X_numeric)Fill in missing data using a chosen strategy:
Imputation is like filling in your average or median or most frequent grade for an assessment you missed.
Scaling is like adjusting the number of everyone’s Facebook friends so that both the number of friends and their age are on a comparable scale. This way, one feature doesn’t dominate the other when making comparisons.
Convert categorical features into binary columns.
Turn “Apple, Banana, Orange” into binary columns:
| Fruit | 🍎 | 🍌 | 🍊 |
|---|---|---|---|
| Apple 🍎 | 1 | 0 | 0 |
| Banana 🍌 | 0 | 1 | 0 |
| Orange 🍊 | 0 | 0 | 1 |
Convert categories into integer values that have a meaningful order.
Turn “Poor, Average, Good” into 1, 2, 3:
| Rating | Ordinal |
|---|---|
| Poor | 1 |
| Average | 2 |
| Good | 3 |
NaNs in feature \(j\) with \(\text{mean}(X_j)\), \(\text{median}(X_j)\), or \(\text{mode}(X_j)\).NaN.import numpy as np
from sklearn.impute import SimpleImputer, KNNImputer
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
# 1. Univariate Mean Imputation
simple_imp = SimpleImputer(strategy='mean')
X_simple = simple_imp.fit_transform(X)
# 2. k-NN Imputation
knn_imp = KNNImputer(n_neighbors=5, weights='uniform')
X_knn = knn_imp.fit_transform(X)
# 3. MICE (Multivariate) Imputation
mice_imp = IterativeImputer(max_iter=10, random_state=42)
X_mice = mice_imp.fit_transform(X)Used for preprocessing and feature engineering.
Implement fit() and transform().
fit(X): Computes statistical parameters (e.g., \(\mu, \sigma\), categories).
transform(X): Applies parameters to transform \(X\).
Examples: StandardScaler, SimpleImputer, OneHotEncoder.
Used for learning patterns and making predictions.
Implement fit() and predict().
fit(X, y): Learns weights/parameters from data.
predict(X): Generates predictions on unseen data.
Examples: DecisionTreeClassifier, SVC, KNeighborsClassifier.
NEVER transform the entire dataset at once!
Train and Test.fit_transform() transformers only on Train.transform() Test using the fitted parameters.from sklearn.pipeline import make_pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
# Define Pipeline
pipeline = make_pipeline(
SimpleImputer(strategy='median'),
StandardScaler(),
KNeighborsClassifier(n_neighbors=5)
)
# Train and Evaluate seamlessly
pipeline.fit(X_train, y_train)
accuracy = pipeline.score(X_test, y_test)Pipeline objects to enforce the Golden Rule and stop data leakage!