Home »
Blog »
AI/ML Engineer সিরিজ » Series 03 » Episode 04
Pandas Part 2: groupby, merge, missing values, duplicates
সম্পূর্ণ data wrangling workflow (Series 03, Episode 04)
🟡 INTERMEDIATE
Series 03 — Data — AI-এর ভিত্তি
Episode 04 / 09
📑 এই পর্বে যা যা আছে
- ১. গল্প: Rahim-এর "গড় salary" প্রশ্ন
- ২. সমস্যা: filter দিয়ে সব প্রশ্নের উত্তর হয় না
- ৩. তিন Level-এ groupby বোঝা
- ৪. groupby: split → apply → combine
- ৫. একাধিক aggregation একসাথে
- ৬. Missing value: চেনা ও সামলানো
- ৭. Duplicate: চেনা ও সরানো
- ৮. Merge/Join: দুটো table জোড়া
- ৯. Transformation ও apply
- ১০. বাস্তব উদাহরণ: সম্পূর্ণ wrangling flow
- ১১. একজন AI Engineer-এর দৃষ্টিতে
- ১২. Boss Question
- ১৩. Job Requirement Decoder
- ১৪. সাধারণ ভুল ধারণা
- ১৫. Interview Prep
- ১৬. হাতে-কলমে (Mini Exercise)
- ১৭. Project Connection
- ১৮. সারসংক্ষেপ
- ১৯. পরবর্তী পর্বে কী শিখব
🧩 ১. গল্প: Rahim-এর "গড় salary" প্রশ্ন
Rahim এখন Pandas দিয়ে filter করতে পারে। কিন্তু Boss একটা প্রশ্ন করলেন যা filter দিয়ে হচ্ছে না —
"প্রতিটা শহরে গড় salary কত, আর প্রতিটা role-এ কতজন কাজ করে?"
Rahim: "আপা, আমি তো Dhaka-র job আলাদা করে গড় বের করতে পারি, তারপর Chattogram,
তারপর Sylhet... কিন্তু ৩০টা শহর হলে তো ৩০ বার লিখতে হবে!"
Nila: "একদম না। এই 'প্রতিটা group-এর জন্য একই হিসাব' — এটাই data analysis-এর সবচেয়ে
দরকারি জিনিস, আর Pandas এটাকে এক লাইনে করে দেয়: groupby। আর real data নিয়ে কাজ করতে গেলে
তোমার আরও দুটো জিনিস লাগবেই — missing value আর duplicate সামলানো। আজ সবই শিখবে।"
❓ ২. সমস্যা: filter দিয়ে সব প্রশ্নের উত্তর হয় না
Part 1-এ আমরা শিখেছি single condition-এ row বাছাই। কিন্তু বাস্তবে প্রশ্নগুলো আরও জটিল:
- "প্রতিটা group-এ (শহর/role) গড় কত?" → groupby
- "salary নেই এমন row নিয়ে কী করব?" → missing value handling
- "একই job দুবার আছে কি?" → duplicate handling
- "job data-র সাথে company data মেলাতে হবে" → merge/join
এই episode এই চারটা core wrangling skill শেখায় — যেগুলো ছাড়া কোনো real project এগোয় না।
🪜 ৩. তিন Level-এ groupby বোঝা
Level 1 — সহজ intuition
ভাবুন একগাদা job post-এর কাগজ টেবিলে ছড়ানো। আপনি সেগুলো শহর অনুযায়ী আলাদা স্তূপে ভাগ করলেন (Dhaka-র
স্তূপ, Chattogram-এর স্তূপ)। তারপর প্রতিটা স্তূপের গড় salary হিসাব করলেন। groupby ঠিক এই কাজটাই করে —
ভাগ করো, হিসাব করো, ফল একসাথে সাজাও।
Level 2 — technical ভাবে (split-apply-combine)
Pandas groupby-এর তিনটা ধাপ: split (একটা column-এর value অনুযায়ী data ভাগ),
apply (প্রতিটা group-এ একটা function চালানো, যেমন mean/count), combine
(ফলগুলো একটা নতুন DataFrame-এ জোড়া)। এটাই "split-apply-combine" pattern।
Level 3 — engineer দৃষ্টিতে
engineer রা groupby-কে aggregation ও feature engineering-এর মূল হাতিয়ার হিসেবে দেখে। যেমন "প্রতিটা
customer-এর গড় transaction" একটা শক্তিশালী feature হতে পারে ML model-এর জন্য (Series 05-এ দেখব)।
🔀 ৪. groupby: split → apply → combine
import pandas as pd
df = pd.DataFrame({
"title": ["Python Dev", "ML Engineer", "Data Analyst",
"Backend Dev", "ML Engineer", "Python Dev"],
"salary": [40000, 90000, 45000, 70000, 110000, 50000],
"city": ["Dhaka", "Dhaka", "Chattogram",
"Sylhet", "Dhaka", "Chattogram"],
})
# প্রতিটা শহরে গড় salary
print(df.groupby("city")["salary"].mean())
# city
# Chattogram 47500.0
# Dhaka 80000.0
# Sylhet 70000.0
# প্রতিটা role-এ কতজন
print(df.groupby("title").size())
# প্রতিটা শহরে সর্বোচ্চ salary
print(df.groupby("city")["salary"].max())
groupby("city")["salary"].mean() যেভাবে কাজ করে:
SPLIT (শহর অনুযায়ী) APPLY (mean) COMBINE
Dhaka: 40000,90000,110000 -> 80000 ┐
Chatto: 45000,50000 -> 47500 ├─> একটা ফলাফল table
Sylhet: 70000 -> 70000 ┘
📊 ৫. একাধিক aggregation একসাথে
# প্রতিটা শহরে একসাথে গড়, সর্বোচ্চ, গণনা
result = df.groupby("city")["salary"].agg(["mean", "max", "count"])
print(result)
# ভিন্ন column-এ ভিন্ন হিসাব
df2 = df.assign(experience=[1, 3, 2, 4, 5, 2])
summary = df2.groupby("city").agg(
avg_salary=("salary", "mean"),
max_salary=("salary", "max"),
avg_exp=("experience", "mean"),
job_count=("title", "count"),
)
print(summary)
উপরের agg(avg_salary=("salary", "mean"), ...) ধরনটা (named aggregation) পড়তে সবচেয়ে সহজ ও
modern। ফলে column-এর নাম পরিষ্কার থাকে — report বানানোর জন্য আদর্শ।
🕳️ ৬. Missing value: চেনা ও সামলানো
Real data-তে missing value (NaN) থাকবেই। প্রথমে চেনা, তারপর সিদ্ধান্ত:
import numpy as np
import pandas as pd
df = pd.DataFrame({
"title": ["Python Dev", "ML Engineer", "Data Analyst", "Backend Dev"],
"salary": [40000, np.nan, 45000, np.nan],
"city": ["Dhaka", "Dhaka", None, "Sylhet"],
})
# কোথায় কত missing?
print(df.isnull().sum())
# salary 2
# city 1
# উপায় ১ — missing row বাদ (কম missing হলে)
df.dropna(subset=["salary"])
# উপায় ২ — একটা value দিয়ে পূরণ (fill)
df["salary"] = df["salary"].fillna(df["salary"].median()) # median দিয়ে
df["city"] = df["city"].fillna("Unknown") # category-তে
কোন উপায় কখন?
• খুব কম missing (কয়েক %) → dropna চলে।
• সংখ্যার column → সাধারণত median দিয়ে fill (mean outlier-এ প্রভাবিত হয়)।
• category column → "Unknown" বা সবচেয়ে common value।
সতর্কতা: কোন value দিয়ে fill করবেন তা ঠিক করতে হবে শুধু training data দেখে —
নাহলে data leakage হয় (E08-এ বিস্তারিত)। এই একটা ভুল অনেক junior করে।
👯 ৭. Duplicate: চেনা ও সরানো
df = pd.DataFrame({
"title": ["Python Dev", "ML Engineer", "Python Dev", "ML Engineer"],
"salary": [40000, 90000, 40000, 90000],
"city": ["Dhaka", "Dhaka", "Dhaka", "Dhaka"],
})
# কতগুলো পুরো-row duplicate?
print(df.duplicated().sum()) # 2
# duplicate সরানো (প্রথমটা রেখে)
df_clean = df.drop_duplicates()
# শুধু নির্দিষ্ট column-এর ভিত্তিতে duplicate
df.drop_duplicates(subset=["title", "city"], keep="first")
সব duplicate খারাপ নয়! দুটো ভিন্ন কোম্পানি একই title ও salary দিতে পারে — সেটা বৈধ। তাই অন্ধভাবে
drop_duplicates() নয়; আগে ভাবুন "কোন column-গুলো মিললে এটা সত্যিই একই job?"
(যেমন একটা unique job_id থাকলে সেটার ভিত্তিতে)।
🔗 ৮. Merge/Join: দুটো table জোড়া
প্রায়ই data একাধিক table-এ ছড়ানো থাকে। যেমন এক table-এ job, আরেকটায় company তথ্য — একটা common key দিয়ে জোড়া লাগাতে হয়:
jobs = pd.DataFrame({
"job_id": [1, 2, 3],
"title": ["Python Dev", "ML Engineer", "Data Analyst"],
"company_id": [10, 10, 20],
})
companies = pd.DataFrame({
"company_id": [10, 20],
"company": ["bKash", "Daraz"],
"city": ["Dhaka", "Dhaka"],
})
# common key "company_id" দিয়ে জোড়া
merged = jobs.merge(companies, on="company_id", how="left")
print(merged[["title", "company", "city"]])
| how= | মানে | কখন |
inner | দুই table-এ যেগুলো মেলে শুধু সেগুলো | শুধু মেলানো data চাই |
left | বাঁ table-এর সব, ডানেরটা যেখানে মেলে | মূল table পুরো রাখতে চাই (সবচেয়ে common) |
right | ডান table-এর সব | উল্টো ক্ষেত্রে |
outer | দুই table-এর সব (না মিললে NaN) | কিছুই বাদ দিতে চাই না |
এই merge-এর how ধারণাটা SQL-এর JOIN-এর সাথে হুবহু মেলে — E06 (SQL)-এ আবার দেখব।
একই ধারণা, দুই জায়গায়।
🔧 ৯. Transformation ও apply
# string পরিষ্কার — casing ঠিক করা (Part 1-এর messy data মনে আছে?)
df["city"] = df["city"].str.strip().str.title() # " dhaka " -> "Dhaka"
# comma সরিয়ে salary-কে সংখ্যায়
df["salary"] = (df["salary"].astype(str)
.str.replace(",", "", regex=False)
.astype(float))
# map — category-কে সংখ্যায় (সরল mapping)
df["city_code"] = df["city"].map({"Dhaka": 1, "Chattogram": 2, "Sylhet": 3})
# apply — জটিল custom logic (সম্ভব হলে vectorized-কে অগ্রাধিকার)
df["salary_band"] = df["salary"].apply(
lambda s: "high" if s > 80000 else ("mid" if s > 45000 else "low")
)
লক্ষ করুন .str accessor — এটা পুরো column-এর প্রতিটা string-এ একসাথে কাজ করে (vectorized)।
Part 1-এ দেখা messy data ("Python"/"python", "40,000") এখন এসব দিয়েই পরিষ্কার করা যায়।
🇧🇩 ১০. বাস্তব উদাহরণ: সম্পূর্ণ wrangling flow
import numpy as np
import pandas as pd
# messy raw data (Part 1-এর সেই সমস্যাগুলো সহ)
raw = pd.DataFrame({
"title": ["Python Dev", "python dev", "ML Engineer",
"Data Analyst", "Data Analyst"],
"salary": ["40000", "40,000", "", "4000000", "45000"],
"city": ["Dhaka", "dhaka", "Chattogram", "Dhaka", "Dhaka"],
})
# 1) salary পরিষ্কার -> সংখ্যা
raw["salary"] = (raw["salary"].str.replace(",", "", regex=False)
.replace("", np.nan).astype(float))
# 2) city consistent করা
raw["city"] = raw["city"].str.strip().str.title()
# 3) title consistent (ছোট হাতের অক্ষরে তুলনার জন্য)
raw["title"] = raw["title"].str.strip().str.title()
# 4) outlier ধরা — অস্বাভাবিক salary NaN করি (40 লাখ ভুল)
raw.loc[raw["salary"] > 1_000_000, "salary"] = np.nan
# 5) missing salary -> median দিয়ে fill
raw["salary"] = raw["salary"].fillna(raw["salary"].median())
# 6) duplicate সরানো
raw = raw.drop_duplicates()
# এখন প্রশ্নের উত্তর নির্ভরযোগ্য:
print(raw.groupby("city")["salary"].mean())
দেখুন — Part 1-এর সেই "garbage" data এখন পরিষ্কার। এই পুরো flow-টাই একজন junior AI Engineer-এর
দৈনন্দিন কাজের নমুনা।
🔍 ১১. একজন AI Engineer-এর দৃষ্টিতে
- Cleaning পুনরাবৃত্তিযোগ্য রাখা: প্রতিটা ধাপ script/notebook-এ, যাতে নতুন data এলে আবার চালানো যায়।
- Leakage-সচেতন: fill/scale-এর মান শুধু training data থেকে (E08)।
- Merge-এর পর যাচাই: merge-এর পর
shape দেখে নিশ্চিত হওয়া row অপ্রত্যাশিতভাবে বাড়েনি (many-to-many ভুল)।
- groupby দিয়ে feature: aggregate value (গড়, count) প্রায়ই শক্তিশালী ML feature।
💼 ১২. Boss Question
Boss: "এই groupby-merge দিয়ে আমার business-এ আসলে কী লাভ?"
উত্তর: এগুলোই decision-এর ভিত্তি। groupby দিয়ে আমরা বলতে পারি "কোন শহরে/role-এ salary বেশি"
— যা hiring ও budget সিদ্ধান্তে লাগে। merge দিয়ে বিচ্ছিন্ন data (job + company + location) একসাথে এনে
সম্পূর্ণ ছবি পাই। আর missing/duplicate পরিষ্কার না করলে সব রিপোর্ট ভুল হবে — ভুল রিপোর্ট মানে ভুল
সিদ্ধান্ত, যার খরচ অনেক বেশি। মানে: নির্ভরযোগ্য insight = ভালো সিদ্ধান্ত = business value।
🔎 ১৩. Job Requirement Decoder
"Experience with data cleaning, aggregation, and joining datasets (Pandas)."
| প্রশ্ন | উত্তর |
| এর মানে কী? | আপনি messy data পরিষ্কার করতে, groupby দিয়ে summarize করতে ও একাধিক table জোড়া দিতে পারেন। |
| কোম্পানি কেন চায়? | real data সবসময় messy ও বিভিন্ন উৎসে ছড়ানো; এগুলো একত্র ও পরিষ্কার করা মূল কাজ। |
| কোন সমস্যা সমাধান করে? | অসম্পূর্ণ/ভুল/বিচ্ছিন্ন data থেকে ভুল সিদ্ধান্ত এড়ায়। |
| Junior-এর কী জানা লাগে? | groupby+agg, isnull/fillna/dropna, drop_duplicates, merge (how types), str cleaning। |
| এখনই কী master লাগে না? | জটিল MultiIndex, বিশাল merge-এর performance tuning, big-data join — পরে। |
| GitHub-এ কীভাবে দেখাবেন? | "raw → cleaned" notebook যেখানে প্রতিটা cleaning সিদ্ধান্ত ব্যাখ্যা করা। |
| Interview-তে কী জিজ্ঞেস করতে পারে? | "missing value কীভাবে handle করো?", "inner vs left join?", "split-apply-combine কী?" |
⚠️ ১৪. সাধারণ ভুল ধারণা
ভুল ১: "সব missing value drop করে দাও।" →
ঠিক: অনেক data হারালে model দুর্বল হয়; পরিস্থিতি বুঝে fill নাকি drop ঠিক করুন।
ভুল ২: missing সংখ্যা mean দিয়ে fill করা (সবসময়)। →
ঠিক: outlier থাকলে mean বিভ্রান্ত করে; median প্রায়ই নিরাপদ।
ভুল ৩: পুরো data (train+test) দেখে fill/scale করা। →
ঠিক: এটা data leakage; মান শুধু training থেকে নিন (E08)।
ভুল ৪: merge-এর পর row বেড়ে গেলেও খেয়াল না করা। →
ঠিক: many-to-many merge অজান্তে row বাড়ায়; merge-এর পর shape যাচাই করুন।
ভুল ৫: অন্ধভাবে drop_duplicates()। →
ঠিক: আগে ঠিক করুন কোন column মিললে সেটা "সত্যিই" duplicate।
🎤 ১৫. Interview Prep
প্রশ্ন ১: groupby-এর split-apply-combine ব্যাখ্যা করো।
উত্তর: data একটা key-তে ভাগ (split), প্রতিটা group-এ function চালানো (apply), ফল একসাথে জোড়া (combine)।
প্রশ্ন ২: missing value কীভাবে handle করো?
উত্তর: আগে isnull().sum() দিয়ে পরিমাণ দেখি; কম হলে drop, নাহলে সংখ্যায় median/ category-তে mode বা "Unknown" দিয়ে fill — মান শুধু training থেকে (leakage এড়াতে)।
প্রশ্ন ৩: inner আর left join-এর পার্থক্য?
উত্তর: inner শুধু মেলানো row রাখে; left বাঁ table-এর সব row রাখে, ডানে না মিললে NaN।
প্রশ্ন ৪: mean বনাম median দিয়ে fill — কোনটা কখন?
উত্তর: outlier/ skewed data-তে median নিরাপদ; symmetric distribution-এ mean-ও চলে।
✍️ ১৬. হাতে-কলমে (Mini Exercise)
🧪 হাতে-কলমে: section ১০-এর messy DataFrame নিয়ে:
১. cleaning-এর আগে ও পরে isnull().sum() print করে পার্থক্য দেখুন।
২. প্রতিটা title-এ গড় salary বের করুন (groupby)।
৩. একটা companies table বানিয়ে city-র ভিত্তিতে region column merge করুন।
৪. drop_duplicates() চালানোর আগে ও পরে shape তুলনা করুন।
৫. একটা salary_band column বানান (low/mid/high)।
প্রতিটা ধাপে নিজেকে জিজ্ঞেস করুন: "এই সিদ্ধান্তটা কেন নিলাম?"
🚀 ১৭. Project Connection
flagship V2 (Data Analyzer)-এ এই episode-ই আসল কাজের কেন্দ্র। আমরা raw bangladesh job
data পরিষ্কার করব (skill নাম standardize, salary সংখ্যায়, duplicate সরানো), তারপর groupby
দিয়ে "কোন skill-এ salary বেশি", "কোন শহরে কত job" — এমন প্রশ্নের উত্তর বের করব। প্রয়োজনে company/location
data merge করব।
এই পরিষ্কার-করা data পরে Series 05-এ ML model-এর input হবে। তাই এখানে করা cleaning-এর মান পুরো
project-এর মান নির্ধারণ করবে — মনে রাখুন GIGO (E01)।
📌 ১৮. সারসংক্ষেপ
এই Episode-এ আমরা শিখলাম:
✓ groupby — split-apply-combine দিয়ে প্রতিটা group-এ aggregate (mean/count/max)
✓ agg দিয়ে একসাথে একাধিক হিসাব (named aggregation পড়তে সহজ)
✓ missing value: isnull → dropna বা fillna (median/mode/Unknown), leakage-সচেতনভাবে
✓ duplicate: duplicated/drop_duplicates — তবে অন্ধভাবে নয়
✓ merge: common key-তে join (inner/left/right/outer) — SQL JOIN-এর মতো
✓ str/apply/map দিয়ে transformation ও পরিষ্কার
➡️ ১৯. পরবর্তী পর্বে কী শিখব
পরবর্তী Episode (S03E05): "Matplotlib দিয়ে data-কে চোখে দেখা: distribution, correlation,
outlier।"
সংখ্যায় হিসাব তো করলাম, কিন্তু মানুষ সংখ্যার চেয়ে ছবিতে pattern ভালো ধরে। পরের পর্বে আমরা
visualization শিখব — histogram দিয়ে distribution, scatter দিয়ে সম্পর্ক, box plot দিয়ে
outlier — যাতে data-কে শুধু হিসাব নয়, "চোখে দেখে" বুঝতে পারি।