পাঠ ১৪ · ২৫-এর মধ্যে · মডিউল ২

CSV পড়া ও পরিষ্কার করা

CSV reading & cleaning
৭ মিনিট পড়া মাঝারি · Intermediate Pandas কোডসহ

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

  • CSV কী — কেন AI-এর সব tabular ডেটা এতে
  • read_csv()-এর মূল params — sep, header, names, encoding
  • dtype manually দেওয়া — memory ও speed-এ লাভ
  • parse_dates ও na_values — date ও missing automatic detect
  • String column পরিষ্কার — strip, lower, regex
  • Type conversion — pd.to_numeric, pd.to_datetime (errors='coerce')
  • Duplicate ও save — drop_duplicates, to_csv, to_parquet

১ · CSV কী — কেন AI-তে এত গুরুত্বপূর্ণ

CSVCSV (Comma-Separated Values)একটি plain-text tabular format — প্রতিটি row একটি লাইন, column comma দিয়ে আলাদা। ১৯৭০-এর দশক থেকে চলমান। সব ভাষা, সব tool এতে read/write পারে — তাই universal data exchange-এ rajaa। হলো AI-র সবচেয়ে সাধারণ data format। Excel, Google Sheets, R, Python, SQL — সব tool এতে কাজ করে। সরকারি ডেটা (BBS, A2I), Kaggle dataset, IoT sensor log — অধিকাংশ CSV-তে।

কিন্তু বাস্তব CSV প্রায় কখনো "পরিষ্কার" নয় — column name-এ space, missing value নানা রূপে ("N/A", "NaN", "-"), date string-এ inconsistency, duplicate row, encoding mismatch। AI মডেল train-এর আগে — এই data cleaning-ই সময়ের ৬০-৮০% নেয়।

CSV হলো বাজার থেকে আনা কাঁচা সবজি — মাটি লেগে আছে, পচা পাতা মেশানো, আকার বিভিন্ন। রান্নার (model training) আগে ধোয়া, কাটা, বাছাই (cleaning, type cast, dedup) অপরিহার্য। ভাল chef রান্নার চেয়ে preparation-এ বেশি সময় দেন।

২ · read_csv basics — মূল params

ধরুন আমাদের একটি দোকানের sales ডেটা shop_sales.csv:

Python · Pandas
import pandas as pd
from io import StringIO

# Demo CSV — বাংলাদেশের দোকানের sales
csv_text = """date,product,price_bdt,qty,customer
2025-01-15,চাল ৫কেজি,450,2,রহিম উদ্দিন
2025-01-15,তেল ১লিটার,180,1,সালমা বেগম
2025-01-16,ডাল ১কেজি,140,3,করিম মিয়া
2025-01-16,চিনি ১কেজি,125,1,ফাতেমা খাতুন
"""

# Basic read
df = pd.read_csv(StringIO(csv_text))
print(df)
print()
print("Shape:", df.shape)
print("Columns:", list(df.columns))

    
read_csv-র গুরুত্বপূর্ণ params

১) sep=',' — separator (TSV হলে '\t')।
২) header=0 — কোন row header (None দিলে header নেই)।
৩) names=[...] — নিজে column name দিতে।
৪) index_col='id' — কোন column-কে index।
৫) encoding='utf-8' — বাংলা data-র জন্য আবশ্যক।
৬) nrows=1000 — preview-এ প্রথম N row।

বাংলা/Unicode data-র জন্য সবসময় encoding='utf-8' বা 'utf-8-sig' (BOM থাকলে) দিন। Windows Excel-এ save করলে কখনো 'cp1252' বা 'latin-1' লাগে। ভুল encoding দিলে বাংলা অক্ষর "??????" হয়ে যাবে।

৩ · dtype hint — কেন manually দিতে হয়

read_csv default-এ column-এর type inference করে — কিন্তু সবসময় সঠিক নয়। বড় ফাইলে এই inference slow এবং memory-হাঙ্গরী। dtypedtype (data type)একটি column-এর data type — int64, float64, object (string), datetime64 ইত্যাদি। সঠিক dtype = কম memory + দ্রুত operation। int8 (1 byte) vs int64 (8 byte) — ১০ GB → ১.৩ GB। manually দিলে — memory ৫-১০× কমে, read ২-৩× দ্রুত।

Python · Pandas
import pandas as pd
from io import StringIO

csv_text = """student_id,name,marks,grade
101,আরিফা সুলতানা,87,A
102,মুনির হাসান,72,B
103,তানিয়া আক্তার,95,A
104,সাদিকুর রহমান,68,B
"""

# dtype manually — অনেক দ্রুত ও memory-efficient
dtypes = {
    "student_id": "int32",     # 4 byte (default int64 = 8 byte)
    "name":       "string",    # nullable string (default object)
    "marks":      "int8",      # 0-127 যথেষ্ট
    "grade":      "category",  # repeating values — category দ্রুত
}

df = pd.read_csv(StringIO(csv_text), dtype=dtypes)
print(df.dtypes)
print()
print(f"Memory: {df.memory_usage(deep=True).sum()} bytes")

    
category dtype — যখন একই value বহুবার আসে (যেমন "A", "B", "C" grade)। ১০ লক্ষ row-এর CSV-এ category column ১০-৫০× কম memory নেয়।

৪ · parse_dates ও na_values — automatic detection

Date-string default-এ object (string) থাকে — datetime অপারেশন (sort, diff, year extract) করা যায় না। parse_dates দিলে — auto-cast। Missing value — CSV-তে নানা রূপে ("N/A", "NA", "NaN", "-", "null", খালি)। NaNNaN (Not a Number)Pandas-এ missing value-র representation — IEEE 754 floating-point standard থেকে। NaN-এ যেকোনো arithmetic NaN দেয়। isna()/notna() দিয়ে check; fillna()/dropna() দিয়ে handle। হিসেবে recognize করতে — na_values param।

Python · Pandas
import pandas as pd
from io import StringIO

# বাস্তব dirty CSV — date string ও nana রূপের missing value
csv_text = """order_date,customer,amount,status
2025-01-15,রহিম,450,paid
2025-01-16,সালমা,N/A,pending
2025-01-17,করিম,-,paid
2025-01-18,ফাতেমা,1250,
2025-01-19,তানিয়া,null,paid
"""

df = pd.read_csv(
    StringIO(csv_text),
    parse_dates=["order_date"],                # date column auto-cast
    na_values=["N/A", "-", "null", ""],        # সব missing variant
)

print(df)
print()
print(df.dtypes)
print()
print("Missing per column:")
print(df.isna().sum())

    
order_date এখন datetime64[ns], amount NaN-সহ float। isna().sum() — প্রতি column-এ কতগুলো missing — exploration-এর প্রথম ধাপ।

৫ · Inspection ও column cleanup

CSV পড়ার পর প্রথম কাজ — কী আছে দেখা। df.info(), df.describe(), df.head(), df.sample(5)। তারপর column name পরিষ্কার (extra space, mixed case)।

Python · Pandas
import pandas as pd
from io import StringIO

# Column name-এ space, mixed case, inconsistent
csv_text = """ Order ID , Customer Name ,Total Amount ,Order Date
1, রহিম উদ্দিন ,450,2025-01-15
2,SALMA BEGUM,180,2025-01-16
3,karim mia,140,2025-01-17
"""

df = pd.read_csv(StringIO(csv_text))
print("Original columns:", list(df.columns))

# 1) column name পরিষ্কার — strip + lower + underscore
df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")
print("Cleaned columns:", list(df.columns))

# 2) rename specific
df = df.rename(columns={"order_id": "id", "customer_name": "customer"})
print()
print(df.head())
print()
df.info()

    

৬ · String column পরিষ্কার

Customer name-এ leading/trailing space, mixed case — সব unify করতে .str accessor। Vectorized — for-loop-এর চেয়ে ১০০× দ্রুত।

Python · Pandas
import pandas as pd

df = pd.DataFrame({
    "customer": [" রহিম উদ্দিন ", "SALMA BEGUM", "karim  mia", "Fatema-Khatun"],
    "phone":    ["+880-1711-123456", "01712 345 678", "8801713-987654", "1714.222.333"],
})

# 1) Whitespace পরিষ্কার
df["customer"] = df["customer"].str.strip()

# 2) Lowercase + একাধিক space একটায়
df["customer_clean"] = (
    df["customer"]
    .str.lower()
    .str.replace(r"\s+", " ", regex=True)      # multiple space → 1
    .str.replace("-", " ", regex=False)
)

# 3) Phone — সব non-digit বাদ
df["phone_clean"] = df["phone"].str.replace(r"\D", "", regex=True)

print(df)

    
str.replace(regex=True) — যেকোনো regex pattern। \s+ = এক বা একাধিক whitespace, \D = non-digit। AI text preprocessing-এর backbone।

৭ · Type conversion — to_numeric, to_datetime

Read-এর সময় miss করলেও — পরে cast করা যায়। errors='coerce' দিলে — invalid value NaN হয়ে যায় (crash না করে)।

Python · Pandas
import pandas as pd

df = pd.DataFrame({
    "price":  ["450", "180.5", "invalid", "1,250", ""],
    "date":   ["2025-01-15", "15/01/2025", "Jan 17, 2025", "bad", None],
})

# 1) Numeric conversion — comma সরাও আগে
df["price_num"] = (
    df["price"]
    .str.replace(",", "", regex=False)
    .pipe(pd.to_numeric, errors="coerce")      # invalid → NaN
)

# 2) Datetime conversion — multiple format try
df["date_parsed"] = pd.to_datetime(
    df["date"],
    errors="coerce",
    format="mixed",                            # multi-format auto-infer
)

print(df)
print()
print(df.dtypes)

    
Data leakage সাবধান! Cleaning-এর সময় accidentally row shuffle/sort করে দিলে — train/test split-এ leakage হতে পারে। Cleaning-এর আগে index reset করুন এবং final shuffle শুধু train-time-এ করুন। কখনোই raw data কে in-place modify করে fresh-copy হারাবেন না।

৮ · Duplicate handling

Python · Pandas
import pandas as pd

df = pd.DataFrame({
    "order_id": [1, 2, 3, 2, 4, 4],
    "customer": ["রহিম", "সালমা", "করিম", "সালমা", "ফাতেমা", "ফাতেমা"],
    "amount":   [450, 180, 140, 180, 1250, 1250],
})

print("Before:", len(df))
print("Duplicate rows:", df.duplicated().sum())

# সম্পূর্ণ identical row বাদ
df_dedup = df.drop_duplicates()
print("After full dedup:", len(df_dedup))

# নির্দিষ্ট column-এ — order_id-তে duplicate, প্রথমটা রাখো
df_unique = df.drop_duplicates(subset=["order_id"], keep="first")
print(df_unique)

    

৯ · Save — to_csv ও parquet preview

Python · Pandas
import pandas as pd

df = pd.DataFrame({
    "id":       [1, 2, 3],
    "product":  ["চাল", "তেল", "ডাল"],
    "price":    [450, 180, 140],
})

# CSV — index=False দরকার, encoding utf-8
df.to_csv("clean_sales.csv", index=False, encoding="utf-8")
print("Saved to CSV")

# Parquet — binary, columnar, ১০-৫০× ছোট
# df.to_parquet("clean_sales.parquet", engine="pyarrow")
# print("Saved to Parquet")

# Read back to verify
df_back = pd.read_csv("clean_sales.csv", encoding="utf-8")
print(df_back)

    
index=False — না দিলে output-এ extra "Unnamed: 0" column আসবে। ParquetParquetApache-এর columnar binary format। CSV-র চেয়ে ১০-৫০× ছোট, ৫-১০× দ্রুত read। Schema preserved (dtype বাঁচে)। Big data + AI pipeline-এ standard। PyArrow বা Fastparquet দিয়ে read/write। = production AI pipeline-এ standard। CSV human-readable, Parquet machine-efficient।

১০ · বাংলা CSV — common gotcha

  • Encoding mismatch: Windows Excel save করলে CP-1252 বা UTF-8-with-BOM। Linux/Mac default UTF-8। বাংলা অক্ষর "????" হয়ে গেলে — encoding ভুল।
  • BOM (Byte Order Mark): File-এর শুরুতে invisible 3 byte ()। প্রথম column name-এ যুক্ত হয়। Solution: encoding='utf-8-sig'।
  • Comma in field: "ঢাকা, বাংলাদেশ" — comma আছে। Quote না দিলে column shift। Pandas auto-handle করে যদি "..." দিয়ে wrapped থাকে।
  • Mixed line endings: Windows \r\n, Unix \n। Pandas auto-handle, কিন্তু custom parser-এ সমস্যা।
  • Date format: বাংলাদেশে DD/MM/YYYY, US-এ MM/DD/YYYY। dayfirst=True দিন।
CSV cleaning pipeline — raw → typed DataFrame read → inspect → clean → cast → save raw_csv dirty data 📁 shop_sales.csv encoding? BOM, comma N/A variants read_csv() encoding, dtype na_values, dates 📥 ingest utf-8-sig parse_dates=[...] na_values=[...] inspect info() head() isna() describe() 🔍 explore missing %? dtype check unique values clean .str strip/lower to_numeric/datetime 🧹 transform errors='coerce' drop_duplicates fillna/dropna typed DF ready for AI → to_parquet ✅ clean int64, datetime, category, string iterate — re-inspect after clean ⚠️ ধাপে-ধাপে গুরুত্বপূর্ণ বিষয় 📁 raw: never modify in-place 📥 read: utf-8 + dtype memory ৫× কম 🔍 inspect: isna ratio value_counts 🧹 clean: vectorize no for-loop ✅ save: parquet for AI csv for share
CSV cleaning pipeline — raw থেকে typed DataFrame পর্যন্ত পাঁচটি ধাপ। প্রতিটিতে নিজস্ব challenge ও pandas API। Clean একবারে হয় না — iterate।

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

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

প্র ০১ একটি বাংলা CSV file Excel-এ save করার পর Python-এ পড়লে অক্ষর "????" হয়ে যাচ্ছে। UTF-8, UTF-16, Windows-1252 — কোনটা কী? BOM কী? Detect ও fix-এর systematic উপায় কী?

বাংলা/Unicode data নিয়ে কাজ করার সময় encoding সবচেয়ে সাধারণ frustration। সঠিক বুঝলে — ১৫ মিনিটের সমস্যা সমাধান হয়, ভুল বুঝলে — ৫ ঘণ্টা গায়েব।

Encoding কী:

  • প্রতিটি অক্ষর = একটি বা একাধিক byte। কোন byte কোন অক্ষর — সেটাই encoding।
  • ASCII (1963) — শুধু English (1 byte/char, 128 char)।
  • Unicode = সব ভাষার character set (১,১১,৪০০+ codepoint)।
  • UTF-8/16/32 = Unicode encode করার বিভিন্ন scheme।

UTF-8 (universal default):

  • Variable-length: ১-৪ byte per character।
  • English (ASCII compat) ১ byte, বাংলা সাধারণত ৩ byte।
  • Linux, Mac, Web, Python 3 — সবার default।
  • "ক" = E0 A6 95 (3 byte)।

UTF-16:

  • ২ বা ৪ byte/char। বাংলা ২ byte।
  • Windows internal, Java internal।
  • BOM (Byte Order Mark) প্রয়োজন — endianness বোঝাতে।
  • Web-এ uncommon।

Windows-1252 (CP-1252):

  • ASCII + ১২৮ extra char (European)।
  • Windows পুরাতন default — Excel save legacy।
  • বাংলা সমর্থন করে না — তাই বাংলা file CP-1252-এ save হলে data lost (replacement char দিয়ে)।

BOM (Byte Order Mark):

  • File-এর শুরুতে invisible marker — encoding hint।
  • UTF-8 BOM: EF BB BF (ASCII-তে দেখায় )।
  • Excel সবসময় BOM যোগ করে — Pandas confused: প্রথম column name "name" হয়ে যায়।
  • Solution: encoding='utf-8-sig' — BOM auto-strip।

Detection workflow:

# 1) chardet/charset-normalizer দিয়ে detect
import chardet
with open("data.csv", "rb") as f:
    raw = f.read(100000)            # প্রথম 100KB যথেষ্ট
detected = chardet.detect(raw)
print(detected)
# {'encoding': 'utf-8', 'confidence': 0.99, ...}

# 2) Hex দেখা — প্রথম byte
# EF BB BF = UTF-8 BOM
# FF FE = UTF-16 LE
# FE FF = UTF-16 BE

# 3) Try-fail-fallback
encodings = ["utf-8-sig", "utf-8", "cp1252", "latin-1", "utf-16"]
for enc in encodings:
    try:
        df = pd.read_csv("data.csv", encoding=enc)
        print(f"Worked: {enc}")
        break
    except UnicodeDecodeError:
        continue

Fix strategies:

  • Source-এ ঠিক করুন: Excel "Save As → CSV UTF-8" option ব্যবহার।
  • Re-encode: file.read().decode('cp1252').encode('utf-8')।
  • errors='replace': ভুল byte ? দিয়ে replace (data loss সম্ভব)।
  • errors='ignore': ভুল byte skip (সাবধান)।

Real-world advice:

  • সবসময় UTF-8 in your pipeline।
  • Source data CP-1252 হলে — ingest pipeline-এ একবার convert।
  • Excel থেকে এলে — encoding='utf-8-sig' default।
  • Document encoding in README — team-এ confusion এড়াতে।

মূল উপলব্ধি: Encoding = byte-to-character mapping। Unicode/UTF-8 আজকের universal standard। বাংলা data-তে UTF-8 + BOM-aware ingest = ৯৯% সমস্যা solved। chardet + try-fallback = robust pipeline।

প্র ০২ read_csv default-এ অনেক column-কে object (string) dtype-এ রাখে। AI training-এর আগে কেন numeric/datetime cast দরকার? Memory ও speed-এর numbers কী?

dtype = data type। Pandas-এ এটাই ৭০% performance optimization। বুঝে dtype দিলে — ১০ GB CSV ১.৩ GB হয়, query ১০× দ্রুত।

Default behavior:

  • read_csv first 1000 row sample করে dtype infer করে।
  • String → object (Python list-of-strings, slow)।
  • Numeric → int64 / float64 (8 byte each)।
  • Date string → object — auto-parse করে না (parse_dates না দিলে)।

কেন cast আবশ্যক:

  • Math operation: string-এ + = concat, numeric-এ + = sum।
  • Comparison: "10" < "9" (string compare!) — wrong।
  • Aggregation: mean/sum/median — numeric চাই।
  • ML model: sklearn/TF/PyTorch — numpy float চায়।
  • Date arithmetic: "যত দিন আগে" — datetime দরকার।

Memory comparison (১ million row):

             default       optimized      saving
int64  →     int8           8MB → 1MB     8×
float64 →    float32        8MB → 4MB     2×
object →     category       50MB → 2MB    25×
object →     string[pyarrow] 50MB → 8MB   6×

Real benchmark:

  • NYC Taxi 2GB CSV → optimized dtype → 350MB।
  • Read time: 45s → 12s।
  • groupby aggregation: 8s → 1s।

Cast strategies:

# Strategy 1 — read_csv-এ dtype dict
df = pd.read_csv("big.csv", dtype={
    "user_id": "int32",
    "rating":  "float32",
    "country": "category",
    "name":    "string"
})

# Strategy 2 — read পরে cast
df["price"] = pd.to_numeric(df["price"], errors="coerce")
df["date"]  = pd.to_datetime(df["date"], errors="coerce")
df["cat"]   = df["cat"].astype("category")

# Strategy 3 — downcast automatic
df["score"] = pd.to_numeric(df["score"], downcast="integer")
# auto picks smallest int that fits

Category dtype magic:

  • Repeating string ("M"/"F", "A"/"B"/"C") → integer codes internally।
  • ৫০ MB → ২ MB common।
  • groupby/sort dramatically faster।
  • ML-এ one-hot/label-encoding-এর pre-step।

Nullable types (modern):

  • Int64 (capital I) — supports NaN unlike int64।
  • string — better than object for text।
  • Float32/Float64 — explicit nullable।
  • boolean — supports NA।

Arrow backend (modern):

  • pd.read_csv("f.csv", dtype_backend="pyarrow")
  • Apache Arrow under the hood।
  • Memory & speed dramatic improvement।
  • String-heavy workload-এ ৫-১০× ভাল।

AI training impact:

  • DataLoader speed = training speed bottleneck (often)।
  • Wrong dtype → conversion per batch → GPU starvation।
  • Tabular ML (XGBoost) — float32 preferred (GPU memory)।
  • Embedding lookup — int32 index efficient।

Common mistakes:

  • Phone number → int (leading 0 lost)। Use string।
  • ID column → int64 default (waste)। Use int32 or string।
  • Yes/No → object। Use category বা bool।
  • Year → int64। Use int16 (1900-2100 fits in 16-bit)।

মূল উপলব্ধি: dtype = pandas optimization-এর foundation। Default safe কিন্তু wasteful। Production AI pipeline-এ — explicit dtype + category + parquet = ১০-১০০× efficiency। memory_usage(deep=True) দিয়ে measure করুন, then optimize।

প্র ০৩ Real-world dirty data — null variants ("N/A", "NaN", "-", ""), inconsistent spelling ("Dhaka"/"DHAKA"/"ঢাকা"), swapped columns। ছোট ১ MB CSV বনাম ১০ GB CSV — strategy আলাদা কেন?

Real CSV কখনই tutorial-এর মতো clean না। Strategy data scale-এর সাথে fundamentally পাল্টায় — ১ MB-তে যা trivial, ১০ GB-তে impossible।

Common dirtiness categories:

  • Null variants: "", "N/A", "NaN", "null", "-", "?", "missing", "n/a", "NA"।
  • Encoding noise: trailing space, BOM, hidden Unicode (zero-width)।
  • Spelling variations: "Dhaka"/"dhaka"/"DHAKA"/"ঢাকা"/"Dhka" (typo)।
  • Date chaos: "2025-01-15", "15/01/25", "Jan 15", "1/15/25"।
  • Number chaos: "1,250", "1.250 BDT", "৳1250", "USD 12"।
  • Schema drift: column add/remove between months।
  • Swapped columns: source bug — name ও phone কখনো অদলবদল।
  • Embedded delimiter: "Dhaka, Bangladesh" comma-cell।
  • Multiline cell: address-এ newline।

Small CSV (<100 MB) strategy:

  1. Pandas in-memory load।
  2. Manual exploration: head(), info(), value_counts()।
  3. Eyeball every column — anomaly হাতে catch।
  4. Iterative fix — Jupyter cell-by-cell।
  5. Visual check: matplotlib histogram।
  6. Export cleaned version।

Large CSV (1-10 GB) strategy:

  1. Sample first: nrows=10000 দিয়ে structure বুঝুন।
  2. Schema infer ও lock — explicit dtype।
  3. Chunked read: chunksize=100000 — process per chunk।
  4. Dask/Polars consider: lazy evaluation, parallel।
  5. Convert to Parquet — future read ১০× faster।
  6. Sampling-based validation — 1% random sample-এ check।

Huge CSV (>10 GB) strategy:

  1. Pandas-এ আনার আগে — DuckDB/Polars/SQL।
  2. DuckDB: SELECT * FROM 'data.csv' WHERE... — no load।
  3. Spark for distributed cluster।
  4. Schema validation — Great Expectations, Pandera।
  5. Streaming pipeline — Apache Beam, Flink।

Null variant handling:

# All variants একসাথে
NA_VALS = ["", "N/A", "n/a", "NA", "NaN", "nan",
           "null", "NULL", "-", "?", "missing", "."]
df = pd.read_csv("data.csv", na_values=NA_VALS, keep_default_na=True)

Spelling normalization:

# Step 1: lowercase + strip
df["city"] = df["city"].str.strip().str.lower()

# Step 2: known mapping
city_map = {
    "dhaka":  "Dhaka",   "ঢাকা":  "Dhaka",
    "ctg":    "Chittagong", "chittagong": "Chittagong",
    "dhka":   "Dhaka",   # typo
}
df["city"] = df["city"].map(city_map).fillna(df["city"])

# Step 3: fuzzy match for residual
from rapidfuzz import process
unique = df["city"].unique()
for c in unique:
    match, score, _ = process.extractOne(c, list(city_map.values()))
    if score > 85:
        df.loc[df["city"] == c, "city"] = match

Schema drift detection:

EXPECTED_COLS = {"id", "name", "amount", "date"}

cols = set(df.columns)
missing = EXPECTED_COLS - cols
extra   = cols - EXPECTED_COLS

if missing:
    raise ValueError(f"Missing: {missing}")
if extra:
    print(f"Warning — new columns: {extra}")

Swapped columns detection:

  • Statistical: phone column-এ all-digit expected; name-এ alphabet — heuristic check।
  • Data dictionary cross-validate।
  • Sample row eyeball দেখুন।

Modern alternative tools:

  • Polars: Rust-backed, ৫-১০× pandas faster।
  • DuckDB: SQL on CSV/Parquet without load।
  • Dask: pandas API, parallel/distributed।
  • Modin: drop-in pandas replacement।

Validation framework:

  • Pandera: schema-as-code, fail-fast।
  • Great Expectations: data quality test suite।
  • cerberus: light-weight schema validator।

মূল উপলব্ধি: Small data — manual + iterative। Large data — schema-first, chunked, alternative engine। Validation = pipeline-এর প্রথম step। "Garbage in, garbage out" — AI-তে এই উক্তি বিশেষ true। ৬০% data scientist-এর সময় cleaning-এ। Tooling discipline = AI productivity।

প্র ০৪ CSV বনাম Parquet বনাম JSON — AI pipeline-এ কোনটা কখন? File size, read speed, schema preservation, tool compatibility — চারটি দৃষ্টিতে comparison।

File format choice = AI pipeline-এর hidden bottleneck। ভুল choice = ১০× slower training, ১০× higher cloud cost। Modern AI engineer তিনটিই জানে — কখন কোনটা।

CSV (Comma-Separated Values):

  • Pros:
    • Universal — every tool reads।
    • Human-readable — text editor-এ open।
    • Streaming-friendly — line-by-line।
    • Excel/Google Sheets compatible।
  • Cons:
    • Largest size (no compression default)।
    • Slowest read (parse + type infer)।
    • No schema (every read re-infer)।
    • No nested data।
    • Encoding ambiguity।
  • Use when: Data exchange, manual review, small data (<100 MB), human consumption।

Parquet (Apache, columnar):

  • Pros:
    • ৫-১০× smaller than CSV (Snappy/Gzip default)।
    • ৫-১০× faster read (binary, columnar)।
    • Schema preserved (dtype safe)।
    • Column pruning — শুধু needed columns load।
    • Predicate pushdown — filter at file level।
    • Nested data support (struct, list, map)।
  • Cons:
    • Binary — text editor-এ খোলা যায় না।
    • Excel direct support নেই।
    • Append-friendly নয় (immutable)।
    • PyArrow/Fastparquet dependency।
  • Use when: Big data, AI training, data lake, repeated read, cloud storage (S3)।

JSON / JSONL:

  • Pros:
    • Nested data natural (dict, list)।
    • Web API standard।
    • Schema flexible — fields vary per row।
    • Human-readable।
    • JSONL (line-delimited) — streaming friendly।
  • Cons:
    • Verbose (key repeat per row)।
    • Slower than Parquet, similar to CSV।
    • Tabular data inefficient।
  • Use when: API response, semi-structured (LLM outputs), nested record, log data, NoSQL export।

Benchmark — 10M row tabular dataset:

Format       Size    Write    Read    Compressed
─────────────────────────────────────────────────
CSV          850 MB  120 s    45 s    No
CSV.gz       180 MB  140 s    55 s    Yes
JSON         1.2 GB  150 s    65 s    No
JSONL        1.1 GB  130 s    50 s    No
Parquet       95 MB   18 s     8 s    Snappy
Parquet+zstd  60 MB   25 s     9 s    Zstd
Feather      105 MB    9 s     5 s    LZ4

AI pipeline stages — কোনটা কখন:

  • Ingest (raw): CSV/JSON থেকে আসে — clients এতে দেয়।
  • Bronze layer (raw clean): Parquet — schema lock, compress।
  • Silver layer (feature): Parquet — partitioned by date।
  • Gold layer (model-ready): Parquet/Feather — fast load।
  • Training: Parquet → DataLoader → batch।
  • Export to client: CSV (universal)।

Modern alternatives:

  • Feather (Arrow IPC): Fastest, no compression default. Memory-mapped। Short-term cache।
  • HDF5: Scientific computing, large arrays. Hierarchical।
  • Avro: Schema-evolution friendly, Kafka standard।
  • ORC: Hadoop ecosystem, similar to Parquet।
  • Delta Lake / Iceberg: Parquet + ACID transactions, version control।

Compression options:

  • Snappy: fast compress/decompress, moderate ratio (Parquet default)।
  • Gzip: better compression, slower।
  • Zstd: best of both — recommended modern।
  • LZ4: fastest, lower ratio।
  • Brotli: best for text, slow।

Schema preservation matters:

# CSV — dtype lost
df.to_csv("f.csv")
df2 = pd.read_csv("f.csv")        # all columns object/inferred again

# Parquet — dtype preserved
df.to_parquet("f.parquet")
df2 = pd.read_parquet("f.parquet")  # exactly same dtypes
assert df.dtypes.equals(df2.dtypes)

Cloud cost reality:

  • S3 storage: $0.023/GB/month — Parquet ১০× কম storage।
  • S3 read: $0.0004/1000 GET — column pruning ১০× কম read।
  • BigQuery/Athena query: byte-scanned billing — Parquet ১০-১০০× কম bill।
  • 1 TB CSV → 100 GB Parquet → $২০/month → $২/month।

Decision flowchart:

  • Human review করবে? → CSV।
  • Nested data? → JSON।
  • API response? → JSON।
  • Big tabular + read repeated? → Parquet।
  • Streaming append? → JSONL বা Avro।
  • Need ACID? → Delta Lake।
  • Quick interim cache? → Feather।

মূল উপলব্ধি: CSV = lingua franca (universal but inefficient)। Parquet = AI workhorse (binary, columnar, schema-safe)। JSON = nested/API data। ভাল engineer pipeline-এ multi-format flow design করেন — ingest CSV, store Parquet, export CSV। Format = silent performance lever। ১০× efficiency শুধু format change-এ পাওয়া যায়।

অনুশীলন

  1. Read with options: নিচের CSV-text-কে read করুন — date parse, missing value detect, এবং price column-কে int8 dtype-এ।
    order,date,price,status
    1,2025-01-15,450,paid
    2,2025-01-16,N/A,pending
    3,2025-01-17,180,paid
    import pandas as pd
    from io import StringIO
    
    csv_text = """order,date,price,status
    1,2025-01-15,450,paid
    2,2025-01-16,N/A,pending
    3,2025-01-17,180,paid"""
    
    df = pd.read_csv(
        StringIO(csv_text),
        parse_dates=["date"],
        na_values=["N/A"],
        dtype={"order": "int16", "status": "category"},
    )
    # price-এ NaN আছে — int8-এ যায় না, Int16 nullable
    df["price"] = df["price"].astype("Int16")
    print(df.dtypes)
    print(df)
  2. String column পরিষ্কার: একটি name column যেখানে মিশ্রিত case + extra space আছে — সব title-case + single-space-এ আনুন।
    import pandas as pd
    
    df = pd.DataFrame({
        "name": [" রহিম   উদ্দিন ", "SALMA  BEGUM", "karim mia ", "  Fatema   "]
    })
    
    df["name_clean"] = (
        df["name"]
        .str.strip()
        .str.replace(r"\s+", " ", regex=True)
        .str.title()                              # English-এ প্রতি word capital
    )
    print(df)

    বাংলা characters-এ .title() no-op — শুধু English-এ কাজ করে। বাংলা data-তে strip+single-space যথেষ্ট।

  3. Type conversion safety: একটি price column-এ comma, BDT prefix, এবং invalid value — সব float-এ cast করুন (errors='coerce')।
    import pandas as pd
    
    df = pd.DataFrame({
        "price": ["450", "1,250 BDT", "৳180", "invalid", "৳1,500.50", None]
    })
    
    df["price_num"] = (
        df["price"]
        .astype(str)
        .str.replace(r"[^\d.]", "", regex=True)   # শুধু digit ও . রাখো
        .replace("", None)
        .pipe(pd.to_numeric, errors="coerce")
    )
    print(df)
    print(f"\nMissing: {df['price_num'].isna().sum()}")

    Regex [^\d.] — digit ও dot বাদে সব বাদ। তারপর to_numeric — invalid → NaN।

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

কোড রানার কাজ না করলে? ব্রাউজারে কাজ না করলে Google Colab ব্যবহার করুন — Google-এর ফ্রি অনলাইন Python পরিবেশ। সেখানে Pandas pre-installed, এবং Drive থেকে CSV upload সহজ।
পূর্ববর্তী পাঠ
পাঠ ১৩ · Pandas DataFrame পরিচিতি