By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
(Binning, Encoding, Scaling for Data Science)
Feature engineering is the secret sauce that turns raw data into a format ML models can actually use. Think of it like prepping ingredients before cooking: - Raw data = A pile of unwashed, unchopped vegetables.- Feature engineering = Washing, peeling, dicing, and seasoning them so your model (the chef) can make something edible.
Why it matters in production:- Garbage in, garbage out (GIGO): If you feed a model poorly engineered features, it will fail—silently. No amount of hyperparameter tuning will save you.- Performance & cost: Bad features = slower training, higher cloud bills (e.g., AWS SageMaker instance hours), and models that don’t generalize.- Debugging nightmare: If your model’s predictions are off, is it the data, the features, or the algorithm? Feature engineering is the first place to look.
Real-world scenario:You’re building a customer churn prediction model for a SaaS company. Your raw data includes: - customer_age (numeric, but non-linear—churn peaks at 25 and 60).- subscription_plan (categorical: "Basic", "Pro", "Enterprise").- last_login (datetime, but models need numbers).
customer_age
subscription_plan
last_login
Without feature engineering:- Your model treats customer_age as linear (wrong).- It can’t handle subscription_plan (strings vs. numbers).- last_login is useless (datetime ≠ numeric).
With feature engineering:- You bin customer_age into meaningful groups (e.g., "18-25", "26-40").- You encode subscription_plan into numbers (e.g., "Basic" = 0, "Pro" = 1).- You scale last_login into "days since last login" (0-365) and normalize it.
Result: Your model trains faster, predicts better, and costs less to run.
income
["18-25", "26-40", "41-60", "60+"]
age
sklearn.pipeline.Pipeline
GridSearchCV
ColumnTransformer
NaN
None
SimpleImputer
pandas
scikit-learn
matplotlib
monthly_spend
country
churned
Install dependencies:
pip install pandas scikit-learn matplotlib
import pandas as pd # Load data (replace with your dataset) df = pd.read_csv("customer_churn.csv") print(df.head()) print("\nMissing values:\n", df.isnull().sum()) print("\nData types:\n", df.dtypes)
Expected output:
customer_id customer_age subscription_plan monthly_spend last_login churned 0 1 25 Basic 19.9 2023-01-15 1 1 2 42 Pro 49.9 2023-02-20 0 ... Missing values: customer_id 0 customer_age 0 subscription_plan 0 monthly_spend 5 last_login 0 churned 0 dtype: int64 Data types: customer_id int64 customer_age int64 subscription_plan object monthly_spend float64 last_login object churned int64 dtype: object
from sklearn.model_selection import train_test_split # Separate features (X) and target (y) X = df.drop("churned", axis=1) y = df["churned"] # Split into train/test (stratify to maintain class balance) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y )
from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline from sklearn.impute import SimpleImputer from sklearn.preprocessing import ( OneHotEncoder, OrdinalEncoder, StandardScaler, KBinsDiscretizer, ) from sklearn.ensemble import RandomForestClassifier # Define numeric features (to scale) numeric_features = ["customer_age", "monthly_spend"] numeric_transformer = Pipeline( steps=[ ("imputer", SimpleImputer(strategy="median")), # Fill missing values ("scaler", StandardScaler()), # Scale to mean=0, std=1 ] ) # Define categorical features (to encode) categorical_features = ["subscription_plan"] categorical_transformer = Pipeline( steps=[ ("imputer", SimpleImputer(strategy="most_frequent")), # Fill missing values ("onehot", OneHotEncoder(handle_unknown="ignore")), # One-hot encode ] ) # Define binned features (e.g., age groups) binned_features = ["customer_age"] binned_transformer = Pipeline( steps=[ ("binner", KBinsDiscretizer(n_bins=4, encode="ordinal", strategy="quantile")), ("scaler", StandardScaler()), # Scale after binning ] ) # Define datetime features (e.g., last_login → days since last login) def extract_days_since_login(df): df["last_login"] = pd.to_datetime(df["last_login"]) df["days_since_login"] = (pd.Timestamp("today") - df["last_login"]).dt.days return df[["days_since_login"]] # Combine all transformers preprocessor = ColumnTransformer( transformers=[ ("num", numeric_transformer, numeric_features), ("cat", categorical_transformer, categorical_features), ("bin", binned_transformer, binned_features), ("date", FunctionTransformer(extract_days_since_login), ["last_login"]), ] ) # Full pipeline: preprocess + model pipeline = Pipeline( steps=[ ("preprocessor", preprocessor), ("classifier", RandomForestClassifier(random_state=42)), ] )
# Train pipeline.fit(X_train, y_train) # Evaluate from sklearn.metrics import classification_report y_pred = pipeline.predict(X_test) print(classification_report(y_test, y_pred))
precision recall f1-score support 0 0.92 0.95 0.93 200 1 0.85 0.78 0.81 50 accuracy 0.91 250 macro avg 0.88 0.86 0.87 250 weighted avg 0.91 0.91 0.91 250
import matplotlib.pyplot as plt # Get feature names after one-hot encoding feature_names = ( numeric_features + list(pipeline.named_steps["preprocessor"].named_transformers_["cat"].named_steps["onehot"].get_feature_names_out()) + ["binned_customer_age"] + ["days_since_login"] ) # Get feature importances importances = pipeline.named_steps["classifier"].feature_importances_ # Plot plt.figure(figsize=(10, 6)) plt.barh(feature_names, importances) plt.title("Feature Importances") plt.show()
Expected output: (Higher bars = more important features.)
import joblib # Save pipeline joblib.dump(pipeline, "churn_prediction_pipeline.joblib") # Load and predict (example) loaded_pipeline = joblib.load("churn_prediction_pipeline.joblib") new_data = pd.DataFrame({ "customer_id": [101], "customer_age": [30], "subscription_plan": ["Pro"], "monthly_spend": [39.9], "last_login": ["2023-03-15"], }) print("Prediction:", loaded_pipeline.predict(new_data))
Prediction: [0] # 0 = no churn, 1 = churn
python-dotenv
OneHotEncoder(sparse=True)
sklearn.pipeline.make_pipeline
memory
memory="cache_dir"
joblib
pickle
pipeline_v1.joblib
# Using RobustScaler because 'income' has outliers
df.describe()
Pipeline
TargetEncoder
HashingEncoder
OrdinalEncoder
ValueError: Input contains NaN
KBinsDiscretizer(strategy="quantile")
"You scaled your data before splitting into train/test sets. What’s the risk?"
Encoder choice:
"You have a categorical feature with 100 unique values. Which encoder should you use?"
Scaler choice:
"Your data has outliers. Which scaler should you use?"
RobustScaler
Pipeline usage:
MinMaxScaler
strategy="uniform"
strategy="quantile"
"You’re building a model to predict house prices. Your dataset has: - square_footage (numeric, 500-5000 sqft) - neighborhood (categorical, 200 unique values) - year_built (numeric, 1900-2023)
square_footage
neighborhood
year_built
Which feature engineering steps would you apply, and why?"
Answer:1. square_footage: Scale with StandardScaler (unbounded, Gaussian-like).2. neighborhood: Use TargetEncoder (high cardinality → one-hot would explode dimensions).3. year_built: Bin into decades (e.g., "1900-1920", "1921-1940") to capture non-linear trends (older homes may have different value patterns).
StandardScaler
Challenge:You have a dataset with: - age (numeric, 18-80) - income (numeric, 20K-500K) - education (categorical: "High School", "Bachelor", "Master", "PhD")
education
Task:1. Bin age into 4 equal-width bins.2. Encode education as ordinal (High School=0, Bachelor=1, Master=2, PhD=3).3. Scale income to [0, 1] range.4. Combine all steps into a Pipeline.
Solution:```python from sklearn.preprocessing import KBinsDiscretizer, OrdinalEncoder, MinMaxScaler from sklearn.pipeline import Pipeline
pipeline = Pipeline([ ("bin_age", KBinsDiscretizer(n_bins=4, encode="ordinal", strategy="uniform
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.