পাঠ ১৭ · ৩০-এর মধ্যে · মডিউল ৩

Missing data — কীভাবে ভরাব

Handling missing data
৭ মিনিট পড়া মাঝারি · Intermediate Imputation

এই পাঠে যা শিখবেন

  • MCAR, MAR, MNAR — missing-এর তিন ধরন
  • কখন drop, কখন impute
  • Simple ও advanced imputation technique
  • "Missing" নিজেই signal — কীভাবে ব্যবহার করবেন
  • Sklearn-এ practical imputation pipeline

১ · কেন missing data হয়

বাস্তব-জগতের ডেটা প্রায় কখনোই complete না। Daraz-এর order form-এ phone optional, কেউ দেননি — missing। Hospital-এ blood-test হয়নি কারণ রোগী আগেই ছেড়ে দিয়েছেন — missing। Survey-এ income লিখতে অস্বস্তি — missing। মানুষ, system, sensor — সবার সীমাবদ্ধতায় missing dataMissing Dataএকটি observation-এর কোনো column-এ value উপস্থিত নেই। NaN (Not a Number), None, NULL, "?", "" বিভিন্ন form-এ থাকতে পারে। তৈরি হয়।

ML মডেল most algorithm NaN handle করতে পারে না। তাই missing-এর সাথে কী করব — সিদ্ধান্ত নিতে হয়। কিন্তু সিদ্ধান্ত-এর আগে প্রশ্ন: missing হলো কেন?

২ · MCAR, MAR, MNAR — তিন ধরন

Donald Rubin (১৯৭৬)-এর শ্রেণীবিভাগ

১) MCAR — Missing Completely At Random: missing হওয়ার সম্ভাবনা data-র কোনো variable-এর উপর নির্ভর করে না।
২) MAR — Missing At Random: missing-এর সম্ভাবনা observed অন্য variable-এর উপর নির্ভর করে।
৩) MNAR — Missing Not At Random: missing-এর সম্ভাবনা missing value নিজের উপরই নির্ভর করে।

MCAR উদাহরণ: sensor random failure — যেকোনো reading miss।

MAR উদাহরণ: পুরুষেরা income কম report করেন — missing-এর সম্ভাবনা gender (observed)-এর উপর নির্ভরশীল।

MNAR উদাহরণ: উচ্চ-আয়ের মানুষ income লিখতে চান না — missing-এর সম্ভাবনা income (যা missing) নিজেই উপর নির্ভর।

ভাবুন একটি Bangladesh census। MCAR — enumerator-এর pen শেষ হয়ে গেছে, random row miss। MAR — গ্রামাঞ্চলে phone কম, তাই "phone number" missing rural-এ বেশি (rural variable observed)। MNAR — disabled রোগীরা hospital চেক-আপ এড়িয়ে গেছেন, "checkup result" missing — মানে disability নিজেই missing-এর কারণ।

৩ · কীভাবে চিনব কোন ধরন

MCAR test (Little's MCAR test) আছে, কিন্তু practical:

  • MCAR check: missing rate কি সব subgroup-এ একই? df.groupby('district')['col'].apply(lambda x: x.isnull().mean())।
  • MAR check: missing flag বানিয়ে অন্য variable-এর সাথে correlation।
  • MNAR check: impossible to test from data alone — domain knowledge দরকার।

"Missing rate" measure:

$$\text{missing rate} = \frac{\text{NaN count}}{\text{total rows}} \times 100\%$$

৪ · Strategy ১ — Deletion

(ক) Listwise (row drop):

  • df.dropna() — যে row-এ কোনো NaN, সেটা বাদ।
  • সরল, কিন্তু data হারানো বেশি।
  • উপযুক্ত: missing < ৫% এবং MCAR।

(খ) Pairwise:

  • প্রতিটি analysis-এ যে variable লাগে, শুধু সেই গুলোতে missing-এ row drop।
  • Statistical analysis-এ ব্যবহৃত, ML-এ rare।

(গ) Column drop:

  • df.drop(columns=['col']) — column-এ missing > ৫০-৭০%, drop সবচেয়ে সহজ।
  • কিন্তু সেই column যদি predictive থাকত — তথ্য হারালেন।
Listwise deletion-এ ১০০ column-এর প্রতিটিতে ১% missing থাকলে — পুরো dataset-এর ~৬৩% row drop! ($1 - 0.99^{100} \approx 0.63$)। সাবধান।

৫ · Strategy ২ — Simple imputation

Numeric column-এ:

  • Mean: sensitive to outlier; symmetric distribution-এ ভাল।
  • Median: robust; skewed distribution-এ preferred।
  • Constant (০, -১): domain-specific, যেমন "no purchase" = ০।

Categorical column-এ:

  • Mode: সবচেয়ে frequent category।
  • "Missing" নতুন category: "Unknown" — missing-এ pattern থাকলে ভাল।

সমস্যা: mean-imputation variance underestimate করে, correlation distort করে। সরল কিন্তু crude।

৬ · Strategy ৩ — KNN imputation

KNN imputerK-Nearest Neighbors Imputerএকটি missing value-এর জন্য — k-জন closest non-missing neighbor খুঁজে তাদের average দিয়ে fill। Distance metric: Euclidean সাধারণত। — missing row-এর সবচেয়ে কাছের k-জন non-missing row খুঁজে — তাদের গড় দিয়ে fill। Sklearn-এ KNNImputer।

সুবিধা: non-linear relationship ধরে; mean-এর চেয়ে accurate।
অসুবিধা: বড় data-তে slow ($O(n^2)$ distance), scaling sensitive।

৭ · Strategy ৪ — Iterative imputation (MICE)

MICE (Multiple Imputation by Chained Equations): প্রতিটি column-কে অন্য column থেকে regression দিয়ে predict — iterative। Sklearn-এ IterativeImputer।

  1. প্রতিটি missing column-এ initial impute (mean)।
  2. একটি column-এর missing কে অন্য সব column থেকে regression দিয়ে re-impute।
  3. সব column-এ rotate; converge না হওয়া পর্যন্ত repeat।

Best statistical-quality, কিন্তু expensive। Survey-research-এ standard।

৮ · "Missing" নিজেই signal

Bangladesh fintech-এ "income" missing — সাধারণত সেই user reluctant disclose। "Missing" predictive। কী করব?

  • একটি indicator column যোগ করুন: df['income_missing'] = df['income'].isnull().astype(int)।
  • তারপর income-এ impute করুন।
  • মডেল দু'টি signal পায়: "missing হয়েছিল কি না" ও "imputed value কত"।

Tree-based model (XGBoost, LightGBM) NaN নিজেই handle করতে পারে — split-এর সময় missing-কে আলাদা branch-এ পাঠায়। Linear model-এ এই facility নেই।

Missing data — decision tree Drop or impute? Missing rate কত? <5% — drop row ৫-৪০% — impute >50% — drop column Pattern কী? MCAR/MAR/MNAR? MCAR → mean/median simple, fast MAR → KNN/MICE use other vars MNAR → indicator flag + impute "Missing" নিজেই signal — indicator column যোগ করুন সবসময়
Missing data handling — rate ও pattern অনুযায়ী decision।

৯ · Pandas ও Sklearn কোড

Python · pandas
import pandas as pd
import numpy as np

# নকল bKash data with missing
np.random.seed(0)
df = pd.DataFrame({
    'age': np.random.randint(18, 65, 100).astype(float),
    'income': np.random.lognormal(10, 0.8, 100),
    'district': np.random.choice(['Dhaka','Chattogram','Sylhet'], 100)
})
# inject missing
df.loc[np.random.choice(df.index, 15), 'income'] = np.nan
df.loc[np.random.choice(df.index, 5), 'age'] = np.nan

print("Missing per column:")
print(df.isnull().sum())
print(f"\nMissing rate (income): {df['income'].isnull().mean():.1%}")

# Simple imputation
df_simple = df.copy()
df_simple['age'] = df_simple['age'].fillna(df_simple['age'].median())
df_simple['income'] = df_simple['income'].fillna(df_simple['income'].median())

# Indicator column
df_simple['income_was_missing'] = df['income'].isnull().astype(int)
print("\nAfter imputation:")
print(df_simple.isnull().sum())
print(df_simple.head())

    
Median imputation + indicator column — production-ready pattern। ১৫% missing income ভরা; "income_was_missing" column ML-এর কাছে signal।

১০ · KNN imputer — sklearn

Python · sklearn
import pandas as pd, numpy as np
from sklearn.impute import KNNImputer

np.random.seed(0)
df = pd.DataFrame({
    'age': np.random.randint(18, 65, 50).astype(float),
    'income': np.random.lognormal(10, 0.8, 50),
    'spend': np.random.normal(5000, 1500, 50)
})
df.loc[[2, 7, 14], 'income'] = np.nan
df.loc[[3, 9], 'age'] = np.nan

# KNN with 5 neighbors
imp = KNNImputer(n_neighbors=5)
filled = imp.fit_transform(df)
df_filled = pd.DataFrame(filled, columns=df.columns)

print("Original (with NaN):")
print(df.head(15))
print("\nKNN-imputed:")
print(df_filled.head(15).round(0))

    
KNN অন্য variable (age, spend) ব্যবহার করে similar profile-এর neighbor খুঁজে — তাদের income গড় দিয়ে fill। Mean-এর চেয়ে চেয়ে context-aware।

১১ · Bangladesh-context উদাহরণ

  • NID database: ১৯৭০-র আগের জন্ম-তারিখ approximate — "১লা জানুয়ারী" placeholder। এটা missing-as-encoded।
  • bKash KYC: "occupation" optional field — ৩০-৪০% missing। MAR (urban-এ কম missing)।
  • Hospital records: blood pressure missing — সাধারণত যাদের measure হয়নি (MNAR — অসুস্থ ছিলেন না)।
  • Pathao ride: "rating" optional — যাঁরা rate করেননি, তাঁরা সাধারণত neutral। "Missing = neutral 4-star" assumption।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ আপনার hospital dataset-এ "blood pressure" column-এ ৪০% missing। এটা MCAR/MAR/MNAR? কীভাবে confirm করবেন? কী strategy?

৪০% missing — significant। সরাসরি drop সম্ভব না (অর্ধেক rows হারাব), simple impute বিপজ্জনক (BP medical decision-এ critical)।

Pattern detection:

  • MCAR ধারণা: nurse random forgot — সব patient-এ equal probability।
  • MAR ধারণা: outpatient (kort visit)-এ BP measure হয় না, inpatient-এ হয় — visit_type observed।
  • MNAR ধারণা: high-BP patient-রা dizzy হয়ে চলে গেছেন measurement-এর আগে — value নিজেই missing-এর কারণ।

Confirm-এর পদ্ধতি:

  • df['bp_missing'] = df['bp'].isnull() — flag column।
  • flag বনাম visit_type, age, department crosstab। Outpatient-এ ৭০%, inpatient-এ ১০% — strong MAR signal।
  • Domain expert (doctor) interview: "BP কখন measure হয় না?"
  • MNAR test: hospital protocol — কখন BP optional? যদি রোগী সরে যায় — pattern চেক।

Strategy proposed:

  • Drop-এর বদলে — keep with imputation।
  • Flag column রাখুন: bp_missing।
  • MICE/IterativeImputer ব্যবহার করুন — visit_type, age, weight, diagnosis থেকে predict।
  • Sensitivity analysis: imputed vs non-imputed-এ মডেলের behavior দেখুন।

সাবধানতা:

  • Medical context-এ false-impute বিপজ্জনক। "Imputed BP = 120" decision-এ confidence কম।
  • Production-এ — uncertainty quantification (multiple imputation, draw from posterior)।
  • Document: "এই row-এর BP imputed" — clinician notice করতে পারেন।

Bangladesh hospital context:

  • BSMMU, Square, Apollo — different protocols।
  • Government hospital-এ documentation incomplete বেশি — MNAR risk।
  • Public health study-তে BMRC ethics — imputation methodology pre-register।

মূল উপলব্ধি: ৪০% missing = serious problem। Statistical method-এর পাশাপাশি domain dialogue অপরিহার্য। Health data-তে imputation = clinical decision-এ amplified risk। চিন্তাভাবনা সর্বোচ্চ।

প্র ০২ আপনার কাছে ১০০ column-এর data, প্রতিটিতে ১% missing। Listwise drop-এ কত % row হারাবেন? কেন?

এটি statistical paradox যা অনেককে অবাক করে। সরল calculation:

$$P(\text{row complete}) = (1 - 0.01)^{100} = 0.99^{100} \approx 0.366$$

$$P(\text{row dropped}) = 1 - 0.366 = 0.634 \approx 63.4\%$$

অর্থাৎ — ১% missing প্রতি column-এ থাকলেও — listwise drop-এ ~৬৩% data যাবে। বিধ্বংসী।

কেন এমন:

  • প্রতিটি column independent missing।
  • একটি row বাঁচবে শুধু যদি সব ১০০ column-এ value থাকে।
  • Probability product: ০.৯৯ × ০.৯৯ × ... ১০০ বার।
  • ৫০ column হলেও ~৬০% থাকে; ১০০-তে ৩৭%।

উদাহরণ:

  • ১ লাখ user × ১০০ column survey।
  • প্রতিটি column-এ ১% missing।
  • Listwise: ৩৬,৬০০ user বাঁচবে।
  • Imputation-এর সাথে: পুরো ১,০০,০০০ ব্যবহার সম্ভব।

আরও বাস্তব numbers:

  • ৫% missing প্রতি column, ১০ column → $0.95^{10} = 60\%$ retain।
  • ৫% missing, ৫০ column → $0.95^{50} = 7.7\%$ retain।
  • ১০% missing, ২০ column → $0.9^{20} = 12\%$ retain।

Implication:

  • "Listwise deletion সবসময় safe" — myth।
  • Wide dataset (অনেক column)-এ listwise destructive।
  • Imputation almost always preferred — even simple mean।

Mitigation strategies:

  • Missing pattern visualization: missingno library — heatmap। কোন column-এ correlated missing?
  • Column drop: high-missing column drop, low-missing impute।
  • Threshold-based: "row-এ > ৩টি missing হলে drop, না হলে impute" — hybrid।

Sklearn-এ: Pipeline-এ SimpleImputer বা IterativeImputer — listwise অপ্রয়োজন।

মূল উপলব্ধি: Math-এর intuition-এ "১% missing = ১% data হারানো" — but reality "১% × N column = compounded loss"। Wide data-তে imputation indispensable। এই calculation মাথায় থাকলে — junior থেকে senior data scientist-এ leap।

প্র ০৩ "Missing data is not data" — এই statement-এর বিরুদ্ধে কী বলতে পারেন? কীভাবে missingness নিজেই predictive feature?

আশ্চর্যের ব্যাপার — অনেক production system-এ missing-pattern primary signal। উদাহরণ ও কেন:

(১) Loan default prediction

  • "Phone number" missing-এর rate default-এর সাথে highly correlated।
  • Reason: legitimate borrower contact-এর সব info দেন; defaulter intent থেকে hide করেন।
  • Feature: n_missing_fields — strong predictor।

(২) Credit card fraud

  • Stolen card-এ "billing zip" wrong/missing।
  • "Address verification" failed/missing — fraud signal।
  • Feature: address_fields_missing।

(৩) Healthcare

  • "Lab test" missing — সাধারণত doctor order করেননি (low concern) বা patient avoid করেছেন (concern)।
  • Pattern complex, কিন্তু missing nature-ই signal।

(৪) E-commerce

  • Daraz-এ "review_text" missing — neutral satisfaction (passive)।
  • "Phone verification" skipped — quick checkout, less commitment।
  • Feature: has_phone_verified।

কেন missingness predictive:

  • Selection bias: কে disclosure করতে চায় — non-random।
  • Engagement signal: বেশি field fill = বেশি committed।
  • Detection avoidance: bad actor specific pattern hide করেন।

Implementation pattern:

  • প্রতিটি missing-prone column-এ {col}_missing indicator।
  • Aggregate: n_missing, missing_rate_per_row।
  • Cross-feature: "address_missing AND phone_missing" — compound signal।
  • Tree model কে এই indicator feature feed।

সাবধানতা:

  • Imputation flatten করে dilute: impute করার আগে indicator-এ capture।
  • Model interpretation: "missing-related feature important" — stakeholder-কে explain।
  • Fairness: protected group-এ missing pattern bias বহন করতে পারে।

Bangladesh-specific examples:

  • NID number-এ "0000" — placeholder, NID নেই (rural elderly)।
  • Mobile-banking KYC-এ "occupation" missing → informal worker।
  • Election Commission data-তে "education" missing → privacy concern।

Quote-worthy idea (Rubin): "There is no consensus among statisticians about the best procedure to use." — অর্থাৎ context-dependent, generic rule নেই।

মূল উপলব্ধি: "Data clean" ≠ "missing fix"। Missing-pattern itself rich information। ভাল data scientist missingness কে first-class feature-এ promote করেন।

প্র ০৪ Mean imputation কেন variance underestimate করে? উদাহরণসহ ব্যাখ্যা করুন।

এটি statistical truth যা প্রতিটি data scientist-কে জানতে হয়। সরল উদাহরণ:

সেটআপ:

  • True data: $[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]$।
  • Mean = ৫.৫, std = ৩.০৩।
  • ৫টি random missing করি: $[?, 2, ?, 4, ?, 6, ?, 8, ?, 10]$।
  • Observed mean (২,৪,৬,৮,১০) = ৬।

Mean impute: $[6, 2, 6, 4, 6, 6, 6, 8, 6, 10]$ — ৫টি ৬ যোগ।

Imputed std:

  • True std (পূর্ণ): ৩.০৩।
  • Imputed std: ১.৭০ (নিচে)।
  • Variance loss: ($1.7^2$ vs $3.0^2$) = ২.৯ vs ৯.০ = ৬৮% reduction।

কেন এমন:

  • প্রতিটি impute = mean। Mean-এর variance = ০।
  • Spread artificially compressed।
  • Distribution shape distorted — সরু, সরু, সরু।

আরও subtle ক্ষতি:

(১) Correlation-এ bias

  • X ও Y correlated; X-এ missing।
  • Mean-impute X — correlation toward 0 attenuate।
  • Reason: imputed X-এ no variance, তাই Y-এর সাথে relationship lose।

(২) Standard error underestimate

  • Confidence interval narrower than truth।
  • "Significance" overstated — false positive risk।

(৩) Regression coefficient bias

  • Linear regression-এ slope toward zero।
  • "Effect size" underestimated।

সমাধান:

  • Stochastic imputation: mean + random noise (mean-এ residual draw)।
  • Multiple imputation (MI): m টি plausible value generate করুন → m model fit → result combine।
  • MICE: Iterative regression-based — variance preserved।
  • Bayesian imputation: uncertainty explicit।

Multiple imputation example:

  • Missing-এ ৫টি plausible value draw (different seed)।
  • ৫ ভিন্ন complete dataset।
  • প্রতিটিতে model fit।
  • Coefficient গড় + variance combine (Rubin's rules)।
  • Final result variance properly include করে।

R-এ mice package, Python-এ fancyimpute বা statsmodels support।

Practical guidance:

  • EDA-তে quick mean-impute OK।
  • Production model-এ MICE বা KNN।
  • Statistical inference (publication, regulatory) — multiple imputation mandatory।
  • Tree model-এ NaN as-is — no imputation needed।

Bangladesh research context:

  • Health survey (BDHS) — multiple imputation standard।
  • Economic survey (BBS) — imputation methodology documented।
  • Academic paper-এ "we used mean imputation" → reviewer সাধারণত reject।

মূল উপলব্ধি: Mean imputation simple কিন্তু statistically lazy। Real spread preserved রাখতে — multiple imputation বা model-based। Missing handling = inference quality-এর সরাসরি determinant।

অনুশীলন

  1. Missing rate calculation: একটি DataFrame-এ ১০০ column, প্রতিটিতে ২% missing। Listwise dropped-এর পর কত % row বাঁচবে?

    $0.98^{100} \approx 0.133 = 13.3\%$ row বাঁচবে। ৮৬.৭% হারাবেন।

    Conclusion: imputation almost mandatory wide dataset-এ।

  2. Indicator + impute pipeline: "income" column-এ NaN-এর জন্য — indicator column বানান এবং median দিয়ে fill করুন। Pandas-এ লিখুন।
    df['income_missing'] = df['income'].isnull().astype(int)
    df['income'] = df['income'].fillna(df['income'].median())

    এই pattern Bangladesh fintech KYC pipeline-এ standard। missing flag + median-fill = robust baseline।

  3. KNN vs mean comparison: Sklearn-এর Iris dataset-এ ১০% missing inject করুন একটি column-এ। Mean ও KNN imputation compare করুন original-এর সাথে — কোনটা বেশি accurate?
    from sklearn.datasets import load_iris
    from sklearn.impute import SimpleImputer, KNNImputer
    import numpy as np
    iris = load_iris(as_frame=True).frame
    X = iris.drop(columns=['target']).values
    mask = np.random.rand(*X.shape) < 0.1
    X_missing = X.copy()
    X_missing[mask] = np.nan
    
    mean_imp = SimpleImputer(strategy='mean').fit_transform(X_missing)
    knn_imp = KNNImputer(n_neighbors=5).fit_transform(X_missing)
    
    print(f"Mean MSE: {np.nanmean((mean_imp - X)**2):.3f}")
    print(f"KNN MSE: {np.nanmean((knn_imp - X)**2):.3f}")

    সাধারণত KNN MSE কম — কারণ ভিন্ন species-এ value আলাদা; KNN species-aware fill।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

কোড রানার কাজ না করলে? ব্রাউজারে কাজ না করলে Google Colab ব্যবহার করুন।
পূর্ববর্তী পাঠ
পাঠ ১৬ · EDA