Categorical encoding
এই পাঠে যা শিখবেন
- One-hot, label, ordinal encoding — সরল technique
- Target/mean encoding — high-cardinality-এ powerful
- Frequency encoding — দ্রুত baseline
- Embedding encoding — DL-এর সাথে
- "Cardinality cliff" — কখন কোন method
১ · কেন encoding দরকার
ML algorithm — linear regression থেকে neural network পর্যন্ত — সব input number-এ চায়। কিন্তু বাস্তব ডেটায় column-এ "Dhaka", "merchant", "iPhone" — strings। এদের কে number-এ রূপান্তর করতে হয়। এটাই categorical encodingCategorical Encodingcategory-type column-কে numeric representation-এ রূপান্তর — যাতে ML model input হিসেবে ব্যবহার করতে পারে। Method-ভেদে accuracy ও interpretability বদলায়।।
সরল উদাহরণ: Daraz delivery district — "Dhaka", "Chattogram", "Sylhet"। Linear regression-এ এই string সরাসরি দিতে পারবেন না।
২ · Categorical-এর দু'ধরন
- Nominal (no order): "Dhaka", "Chattogram" — কোন rank নেই।
- Ordinal (order আছে): "low", "medium", "high" — rank meaningful।
Method-এর choice এই distinction-এর উপর নির্ভর করে।
৩ · One-hot encoding
প্রতিটি unique category-র জন্য একটি new binary column। সবচেয়ে common technique।
Example: "district" = ["Dhaka", "Chattogram", "Sylhet"] → তিনটি column:
district_Dhaka: 0/1district_Chattogram: 0/1district_Sylhet: 0/1
Pandas: pd.get_dummies(df, columns=['district'])।
সুবিধা: no false ordering; linear model-এ natural।
অসুবিধা: high-cardinality-এ explosion (১০০ category = ১০০ column); sparsity।
drop_first=True — multicollinearity এড়াতে এক column drop। Linear regression-এ standard; tree-এ optional।
৪ · Label encoding
প্রতিটি category-কে একটি integer। "Dhaka" = ০, "Chattogram" = ১, "Sylhet" = ২।
সুবিধা: single column; tree model-এ ভাল।
অসুবিধা: false ordering imply। Linear model "Sylhet (২) > Dhaka (০)" ভাবতে পারে।
কখন: tree-based model (XGBoost, RF, LightGBM) এবং nominal data-তে।
৫ · Ordinal encoding
Order জানা থাকলে — সেই order-এ integer assign।
Example: "education" = ["primary", "secondary", "graduate", "post-grad"] → ০, ১, ২, ৩।
Sklearn: OrdinalEncoder(categories=[['primary', 'secondary', ...]]) — manual order।
Linear ও tree উভয়ে কাজ করে। কিন্তু এক step difference সব level-এ equal — সেটা ground truth-এ true কি না, প্রশ্ন।
৬ · Target (mean) encoding
Target encodingTarget Encodingcategory-কে সেই category-র সাথে target variable-এর mean দিয়ে replace। যেমন: "Dhaka" → Dhaka-র customer-দের গড় churn rate। High-cardinality-এ powerful, কিন্তু leakage risk। — প্রতিটি category-কে সেই category-র target-এর mean দিয়ে replace।
Example: Daraz churn prediction। District by churn rate:
- Dhaka — ১৫% churn → "Dhaka" replace = ০.১৫
- Chattogram — ১২% → ০.১২
- Sylhet — ১৮% → ০.১৮
সুবিধা:
- High cardinality-এ effective (১০০০ city → ১ column)।
- Target-এর সাথে relationship explicit।
- Tree ও linear উভয়ে ভাল।
সমস্যা — leakage:
- Train data-তে target দেখে encoding বানান — overfitting।
- সমাধান: K-fold target encoding (out-of-fold mean)।
- Smoothing:
(count*mean + smooth*global_mean) / (count + smooth)— rare category-তে global gravitate।
৭ · Frequency encoding
প্রতিটি category-কে তার count (বা proportion) দিয়ে replace।
- "Dhaka" — ৫০,০০০ row → 50000 (বা ০.৫)।
- "Sylhet" — ১০,০০০ → 10000।
সুবিধা: simple, no target leakage, single column।
সীমা: দু'টি ভিন্ন category-র same frequency হলে — collision।
৮ · Embedding encoding (DL)
Deep learning-এ — categorical column-কে dense vector-এ map। NLP-র word embedding-এর সাধারণীকরণ।
Architecture: Embedding(num_categories, dim) layer — প্রতিটি category একটি $d$-dim vector।
$$\text{embed}(c) = E[c] \in \mathbb{R}^d$$
- $d$ usually $\sqrt[4]{n}$ থেকে $50$।
- Trained jointly with model।
- Similar category কাছাকাছি vector।
Tabular DL (TabNet, FT-Transformer)-এ standard। Production: large e-commerce, RecSys।
৯ · Cardinality cliff — কখন কোন method
- ২-৩ category: one-hot (drop_first=True) বা label।
- ৪-১০ category: one-hot।
- ১০-৫০: target encoding বা frequency।
- ৫০-৫০০: target encoding (smoothed)।
- ৫০০+: embedding (DL) বা hash encoding।
"Cardinality cliff" = যেখানে one-hot impractical হয়ে যায়। সাধারণত ~৫০ category।
১০ · Pandas + Sklearn কোড
import pandas as pd
import numpy as np
df = pd.DataFrame({
'district': ['Dhaka','Chattogram','Sylhet','Dhaka','Khulna','Sylhet','Dhaka'],
'education': ['primary','graduate','secondary','post-grad','primary','graduate','secondary'],
'churn': [1, 0, 1, 0, 1, 0, 1]
})
# 1) One-hot
oh = pd.get_dummies(df['district'], prefix='dist')
print("One-hot:\n", oh)
# 2) Ordinal
edu_order = {'primary': 0, 'secondary': 1, 'graduate': 2, 'post-grad': 3}
df['edu_ord'] = df['education'].map(edu_order)
print("\nOrdinal:\n", df[['education','edu_ord']])
# 3) Frequency
freq = df['district'].value_counts(normalize=True)
df['dist_freq'] = df['district'].map(freq)
print("\nFrequency:\n", df[['district','dist_freq']])
# 4) Target encoding (simple, no smoothing)
target_map = df.groupby('district')['churn'].mean()
df['dist_target'] = df['district'].map(target_map)
print("\nTarget:\n", df[['district','dist_target']])
১১ · Sklearn pipeline
import pandas as pd, numpy as np
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder
from sklearn.compose import ColumnTransformer
df = pd.DataFrame({
'district': ['Dhaka','Chattogram','Sylhet','Dhaka','Khulna'],
'education': ['primary','graduate','secondary','post-grad','primary'],
'income': [25000, 60000, 30000, 80000, 22000]
})
ct = ColumnTransformer([
('district_oh', OneHotEncoder(sparse_output=False), ['district']),
('edu_ord', OrdinalEncoder(categories=[['primary','secondary','graduate','post-grad']]), ['education']),
], remainder='passthrough')
X = ct.fit_transform(df)
feature_names = ct.get_feature_names_out()
print("Feature names:", feature_names)
print("\nEncoded matrix:\n", X)
১২ · Bangladesh-context tips
- Bengali category names: "ঢাকা", "চট্টগ্রাম" — encoding affect করে না কিন্তু consistency রাখুন (Unicode normalization)।
- Mobile operator (3 categories): GP, Robi, Banglalink → one-hot perfect।
- Upazila (~৪৫০): target বা frequency।
- Product SKU (১,০০,০০০+): embedding (DL recommender)।
- Bank account type: "savings", "current", "DPS", "FDR" — ordinal arguable; one-hot safer।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ একটি product_id column-এ ৫০,০০০ unique value। One-hot করলে কী সমস্যা? কী strategy?
৫০,০০০ unique product — Daraz, Amazon-এর মতো বড় e-commerce-এ realistic। One-hot এই situation-এ disaster।
One-hot-এর সমস্যা:
- Memory explosion: ১০ লাখ row × ৫০,০০০ col = ৫×১০¹⁰ cells। Even sparse — RAM-এ ১০-৫০ GB।
- Curse of dimensionality: linear model-এ — সব weight-এ data সামান্য, generalization poor।
- Train time: matrix multiplication exponentially slow।
- Overfitting: rare product-এ specific weight — noise।
- Cold start: নতুন product test-এ — train-এ ছিল না — encoder fail।
Strategy alternatives:
(১) Target encoding
- প্রতিটি product-কে তার গড় target দিয়ে replace।
- "product_X-এর গড় conversion rate ০.০৩"।
- ৫০,০০০ category → ১ column।
- K-fold mean-এ leakage-free।
(২) Frequency encoding
- "product popularity" implicit।
- Rare product → low value।
- Simple, no leakage।
(৩) Hash encoding
- $h(product\_id) \mod K$ — fixed K bins।
- Collision আছে কিন্তু acceptable।
- Stateless — নতুন product handle।
- Sklearn FeatureHasher।
(৪) Embedding (DL)
nn.Embedding(50000, 32)— ৩২-D vector per product।- Trained jointly with task model।
- Best for recommendation, search।
- Memory efficient: ৫০,০০০ × ৩২ = ১.৬M floats।
(৫) Aggregate features
- Product-এর numeric stats: avg_rating, price, n_orders, n_returns।
- Categorical bucket: category_top, brand।
- raw product_id discard করে এই aggregates use।
(৬) Frequency-based grouping
- Top-1000 product-এ one-hot, rest "other"।
- Power-law assumption: top sellers cover ৮০% volume।
- Hybrid approach।
Comparison-এ accuracy:
- Embedding usually best (DL, large data)।
- Target encoding strong baseline।
- Hash encoding slight degradation কিন্তু infra-friendly।
- One-hot impractical।
Production architecture (Daraz-like):
- RecSys: Two-tower model — user embedding × product embedding।
- Click prediction: gradient boosting + target-encoded features।
- Search: pre-trained embedding (BERT for product description)।
- Cold start: content-based embedding (image, text)।
Bangladesh e-commerce realities:
- Daraz: ১০M+ SKU।
- Pickaboo, Evaly (now-defunct): ৫০K-১০০K SKU।
- Local "ekShop": small inventory, one-hot OK।
- Cross-border: international SKU expansion challenge।
মূল উপলব্ধি: "One-hot সব encoding"-এর myth — high-cardinality-এ break। Embedding ও target encoding production-এ অপরিহার্য। Architecture decision data scale-এ বদলায়।
প্র ০২ "Target encoding-এ leakage" বলতে কী বোঝায়? K-fold target encoding কীভাবে এটা solve করে?
Target encoding সবচেয়ে effective high-cardinality method — কিন্তু leakage-এর সবচেয়ে subtle source। বহু Kaggle competitor public LB-এ overfitted টিতে।
Leakage কী:
- Train data দেখে encoding compute — সেই encoding আবার train data-তে apply।
- প্রতিটি row নিজের target নিজের encoded value-তে contribute করছে।
- Model "শিখে": "encoded_value = target" — perfect train accuracy, terrible test।
Concrete example:
- "Dhaka" rows: target = [1, 0, 1, 1] → mean = 0.75।
- প্রতিটি Dhaka row "Dhaka" → 0.75 encoded।
- Linear model "0.75 = positive case" শিখে।
- Test-এ একটি rare district যা train-এ ছিল না — encoder ভেঙে পড়ে।
Test-time problem:
- Test "Sylhet" row — train-এ Sylhet-এর mean ০.৩।
- Train-এর encoding apply OK।
- কিন্তু training-এ model-এর leakage আগেই হয়েছে — accuracy inflated।
K-fold target encoding solution:
- Train data K folds-এ split (যেমন K=5)।
- প্রতিটি fold-এর জন্য — অন্য K-1 folds থেকে mean compute।
- সেই mean current fold-এ apply।
- প্রতিটি train row "out-of-fold" mean পায় — own contribution না।
Pseudocode:
from sklearn.model_selection import KFold
kf = KFold(n_splits=5, shuffle=True)
df['cat_enc'] = 0.0
for train_idx, val_idx in kf.split(df):
means = df.iloc[train_idx].groupby('cat')['target'].mean()
df.loc[val_idx, 'cat_enc'] = df.iloc[val_idx]['cat'].map(means)
Smoothing — additional protection:
$$\text{enc}(c) = \frac{n_c \cdot \bar{y}_c + m \cdot \bar{y}_{global}}{n_c + m}$$
- $n_c$ — count of category $c$।
- $\bar{y}_c$ — category-specific mean।
- $m$ — smoothing parameter (typically ১০-১০০)।
- Rare category → global mean দিকে pull।
Why smoothing:
- "Sylhet" only ৫টি row — mean noisy।
- Without smoothing — overfitting।
- Bayesian interpretation: prior = global, data = category।
Library options:
category_encoders.TargetEncoder— sklearn-compatible।- CatBoost — built-in target encoding (ordered)।
- H2O AutoML — automatic।
Production gotchas:
- Train-এ encoding fit, save mapping → test apply।
- New category test-এ → use global mean fallback।
- Time-series — "future leakage": K-fold-এর বদলে time-aware fold।
- Multi-class — per-class encoding (binary target থেকে আলাদা)।
CatBoost-এর "Ordered Boosting":
- Random permutation।
- Row $i$-এর encoding শুধু row $1...i-1$-এর target থেকে।
- Strict no-leakage by construction।
Bangladesh ML competition context:
- BUET Datathon-এ অনেক participant naive target encoding-এ overfit।
- Kaggle Bangladesh competition — leakage detection essential review point।
- Production ML team-এ — encoding pipeline সবসময় Pipeline-এ wrap।
মূল উপলব্ধি: Target encoding power-tool — কিন্তু sharp। K-fold + smoothing without compromise। CatBoost-এর built-in ordered encoding সবচেয়ে safe। Leakage detection — model-এর train ও test accuracy gap বড় হলে suspicion।
প্র ০৩ "Education" column-এ "primary, secondary, graduate, post-grad" — ordinal। কেন ০, ১, ২, ৩-এর বদলে ০, ৫, ১০, ১৫ ভাল হতে পারে? কিভাবে decide করবেন?
এটি subtle data-science question। Default ordinal (০-১-২-৩) "equal step" assume করে — অনেক সময় false।
Default ordinal-এর সমস্যা:
- "primary → secondary" এক unit।
- "graduate → post-grad" এক unit।
- মডেল ভাবে gap সমান।
- বাস্তব: post-grad-এ পৌঁছাতে অনেক বেশি effort, salary jump আরও বড়।
কেন ০, ৫, ১০, ১৫ better হতে পারে:
- Standard schooling years approximate (primary ৫, secondary ১০, graduate ১৫, post-grad ১৭)।
- Real-world quantity reflect — "years of education"।
- Linear model এই scale-এ accurate fit।
Decision framework:
(১) Domain knowledge
- Bangladesh-এ:
- Primary = class 5 = ৫ years
- Secondary = SSC = ১০ years
- Higher Secondary = HSC = ১২ years
- Graduate = ১৫-১৬ years
- Post-grad = ১৭-১৮ years
- PhD = ২২+ years
(২) Target relationship
- Plot target vs ordinal value।
- Non-linear — gap unequal।
- Equal-spaced ordinal → tree model handle, linear model misfit।
(৩) Model type
- Tree (XGBoost, RF) — order matters; spacing not。 ০-১-২-৩ ও ০-৫-১০-১৫ same।
- Linear/NN — spacing matters। Real-world unit better।
- NN with embedding — ordering even ignored, learn from data।
(৪) Empirical test
- Encoding ১: ০-১-২-৩।
- Encoding ২: ০-৫-১০-১৫।
- Encoding ৩: target encoding।
- Cross-validate, compare RMSE/AUC।
আরও sophisticated approach:
(ক) Optimal ordinal
- Target-vs-category mean থেকে ordering ও spacing infer।
- Isotonic regression।
(খ) Splines/binning
- Education-এর exact value-এর বদলে — বিন (yrs ০-৫, ৫-১০, ১০+)।
- Tree-friendly।
(গ) Multiple representation
- Both: ordinal_simple ও ordinal_years।
- Model দু'টি signal use।
Feature engineering checklist:
- Domain expert interview — "এই category-গুলোর মধ্যে gap কত?"
- Visualization — target vs category mean।
- A/B test — ভিন্ন encoding।
- Regularization-এ confirm — overfit থেকে protect।
Bangladesh-specific examples:
- NID type: "smart, old, tin, none" → ordinal-এ smart=3, none=0; কিন্তু none ও smart-এর gap unequal।
- Income bracket: "< 10K, 10-30K, 30-100K, 100K+" — log-scale spacing logical।
- Mobile plan: "basic, standard, premium" → ordinal default OK।
Common mistake:
- ML competition-এ default ০-১-২-৩ accept — never tune।
- Top kagglers customize spacing।
- Marginal gain — কিন্তু compound হয়।
মূল উপলব্ধি: Ordinal encoding "lazy" approach common। Domain-aware spacing model accuracy boost করে — especially linear models। Tree-এ ordering enough, কিন্তু feature engineering thoughtful — সবসময় better।
প্র ০৪ Tree-based model (XGBoost) ও linear model (Logistic Regression) — categorical encoding-এ requirement-এ কেন পার্থক্য? এর behind কী?
এটি ML interview-এর classic প্রশ্ন। Underlying mechanism বুঝলে — encoding choice intuitive।
Linear model (Logistic Regression):
- Equation: $y = w_1 x_1 + w_2 x_2 + ... + b$।
- প্রতিটি feature-এ একটি weight assign।
- Linear combination।
- Numeric encoding-এ value-এর actual magnitude meaningful।
Linear-এ label encoding-এর সমস্যা:
- "Dhaka=0, Chattogram=1, Sylhet=2"।
- Model: $y = w \cdot district$।
- $w > 0$ — Sylhet (২) prediction Dhaka-র চেয়ে $2w$ বেশি।
- "Sylhet = 2 × Chattogram" implies — false!
- Order ও magnitude both encode — nominal-এ অর্থহীন।
One-hot ভাল কেন:
- প্রতিটি category-র own weight: $w_{Dhaka}, w_{Chattogram}, w_{Sylhet}$।
- Independent estimation।
- No false ordering imposed।
Tree-based model (XGBoost, RF):
- Decision: "feature ≤ threshold?" — true/false split।
- Threshold value-এর only ordering matters, magnitude না।
- "district ≤ 0.5" — Dhaka one branch, others another।
- Tree label encoding-এ category 1 vs 2 vs 3 — split point একই কাজ করে।
Tree-এ label encoding-এর caveat:
- Tree-এর depth অনেক — প্রতিটি category ভাল-ভাবে separate করতে।
- "Dhaka, Chattogram, Sylhet, Khulna" ৪ category — ৩টি split দরকার।
- One-hot-এ ১টি split-এ একটি category isolate।
- Categorical-aware tree (LightGBM-এর native categorical, CatBoost) — direct categorical handle।
Theoretical reason — invariance:
- Tree split monotonic transformation-এর প্রতি invariant।
- Linear monotonic transformation-এ sensitive।
- $x \to \log(x), \sqrt{x}, x^2$ — tree-এ same model; linear-এ ভিন্ন।
Why XGBoost ভাল categorical handle:
- Modern XGBoost (1.5+) —
enable_categorical=True। - LightGBM —
categorical_feature=['col']। - CatBoost — built-in ordered target encoding।
- Internal: optimal split for category set (Fisher's exact, etc.)।
Neural network:
- Embedding layer — category → dense vector।
- Vector trained jointly।
- Similar category কাছাকাছি vector।
- One-hot-এর "lookup table version" — but learned।
Practical guidance:
- Logistic/Linear regression: one-hot (low card), target encoding (high card)।
- XGBoost/RF: label encoding fine; native categorical even better।
- LightGBM/CatBoost: categorical feature flag — automatic।
- Neural network: embedding layer।
- k-NN, k-Means: distance-based — one-hot must (label encoding distorts distance)।
Empirical observation:
- Tree model with label encoding ~ one-hot — small gap।
- Linear model: one-hot >> label encoding (significant gap)।
- Distance-based: one-hot mandatory।
Hybrid approach:
- Production gradient boosting + neural network ensemble।
- Boosting: target encoded।
- NN: embedding।
- Different encodings — different signal।
Bangladesh ML production examples:
- Daraz click prediction: LightGBM + native categorical।
- bKash fraud: XGBoost + target encoding।
- Pathao surge: linear model + one-hot district।
- Recommender (any large platform): NN with embedding।
মূল উপলব্ধি: "Encoding × Model" interaction — ML practitioner-এর core skill। Tree-এর invariance ও linear-এর sensitivity-র underlying math মাথায় থাকলে — encoding decision intuitive। প্রতিটি model-এ optimal encoding ভিন্ন।
অনুশীলন
-
One-hot practice: ["GP", "Robi", "Banglalink", "GP", "Teletalk"] — Pandas-এ one-hot করুন এবং ৫×৪ matrix output verify।
import pandas as pd s = pd.Series(["GP","Robi","Banglalink","GP","Teletalk"]) oh = pd.get_dummies(s) print(oh)৫ rows × ৪ unique = ৪ binary column। প্রতিটি row-তে exactly একটি 1।
-
Target encoding-এ leakage: ১০০ row-এর ছোট DataFrame-এ "city" ও "target" আছে। Naive (full data fit) ও K-fold target encoding দু'টিতে train accuracy compare করুন। কোনটায় inflated?
import pandas as pd, numpy as np from sklearn.model_selection import KFold np.random.seed(0) df = pd.DataFrame({ 'city': np.random.choice(['A','B','C','D'], 100), 'target': np.random.binomial(1, 0.3, 100) }) # Naive (leak) naive = df.groupby('city')['target'].mean() df['naive_enc'] = df['city'].map(naive) # K-fold (proper) df['kfold_enc'] = 0.0 for tr, va in KFold(n_splits=5, shuffle=True, random_state=0).split(df): means = df.iloc[tr].groupby('city')['target'].mean() df.loc[df.index[va], 'kfold_enc'] = df.iloc[va]['city'].map(means) print(df[['city','target','naive_enc','kfold_enc']].head(10))Naive-এ encoded value target-এর সাথে artificially correlated (leakage); K-fold version cleaner।
-
Ordinal spacing: Bangladesh-এ "education" column "primary, SSC, HSC, graduate, post-grad" — কোন numeric value সবচেয়ে domain-realistic? Log-spaced কেন বিবেচনা?
Years of education-এ: primary=5, SSC=10, HSC=12, graduate=16, post-grad=18।
Log-spacing — যদি income-target হয় (log-relationship): post-grad income graduate-এর ১.৫-২× — exponential effect ধরা।
Empirical: cross-validate দু'টি encoding — best select।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পাঠ ২০ · Feature scaling পরবর্তী পাঠ Numeric column standardize/min-max।
- পাঠ ১৮ · Outlier detection আগের পাঠ Outlier handle-এর পর encoding।
- পাঠ ২১ · Feature selection এই পাঠের সাথে সম্পর্কিত Encoded feature থেকে best বাছাই।
- সব AI Courses দেখুন ABCL TECH Python, ML, DL, NLP, CV, GenAI, RL, MLOps।