Mục lục
- Mục tiêu bài học
- Vì sao bước đọc dữ liệu quan trọng
- CSV —
pd.read_csv - Các tham số quan trọng của
read_csv - JSON —
pd.read_jsonvàjson_normalize - Excel —
pd.read_excel - Đọc trực tiếp từ URL
- Ghi file —
to_csv/to_json/to_excel - Encoding pitfall
- Memory —
chunksizecho file lớn - dtype optimization và Parquet
- Use case AI
- Code Python tổng hợp
- Bài tập
- Tóm tắt
Mục tiêu bài học
- Đọc CSV, JSON, Excel vào
DataFramevớipd.read_csv,pd.read_json,pd.read_excel. - Nắm các tham số hay dùng:
sep,header,names,index_col,usecols,dtype,parse_dates,encoding,na_values,skiprows,nrows. - Ghi DataFrame ra file (
to_csv,to_json,to_excel,to_parquet). - Biết encoding pitfall, đọc file lớn bằng
chunksize, tối ưudtype.
Vì sao bước đọc dữ liệu quan trọng
Mọi project data — từ EDA đến train model ML — đều bắt đầu bằng một bước: đưa dữ liệu từ file (CSV / JSON / Excel / Parquet) vào Python dưới dạng DataFrame. Đọc sai (sai encoding, sai dtype, không parse được ngày, mất cột) thường khiến code phía sau debug rất khó vì lỗi nằm ở giai đoạn loading chứ không phải logic.
Pandas cung cấp họ hàm pd.read_* rất giàu tham số. Bài này tập trung 3 format phổ biến nhất với AI Engineer: CSV (Kaggle dataset, log export), JSON (API response), Excel (báo cáo doanh nghiệp).
CSV — pd.read_csv
CSV (Comma-Separated Values) là format text đơn giản nhất, mỗi dòng là 1 record, các cột phân cách bằng dấu phẩy.
import pandas as pd
# Đọc file CSV cơ bản
df = pd.read_csv("data/sales.csv")
print(df.shape) # (rows, cols)
print(df.head()) # 5 dòng đầu
Mặc định: separator ,, dòng đầu là header, index tự sinh RangeIndex(0..n-1), encoding utf-8.
Các tham số quan trọng của read_csv
Bảng tham số hay dùng nhất:
sep=","— separator. File.tsvdùngsep="\t"; export từ Excel EU dùngsep=";".header=0— dòng dùng làm header (mặc định dòng đầu). Truyềnheader=Nonenếu file không có header.names=["a","b","c"]— tự đặt tên cột (dùng kèmheader=Nonekhi file không có header).index_col=0hoặcindex_col="id"— chọn cột làm index thay vì sinhRangeIndex.usecols=["name","price"]— chỉ đọc các cột cần, tiết kiệm RAM với file rộng.dtype={"id": "int32", "price": "float32"}— ép kiểu khi đọc, tránh pandas tự đoán sai.parse_dates=["created_at"]— parse cột thànhdatetime64[ns]luôn lúc load.encoding="utf-8"— mặc địnhutf-8. File Việt từ Excel hay cầnutf-8-sighoặccp1252.na_values=["NA", "?", "-"]— coi các chuỗi này làNaN.skiprows=3— bỏ 3 dòng đầu (file có metadata text trước header).nrows=1000— chỉ đọc 1000 dòng đầu, hữu ích để preview nhanh file lớn.
import pandas as pd
df = pd.read_csv(
"data/sales.csv",
sep=";", # file EU dùng dấu chấm phẩy
header=0,
usecols=["order_id", "amount", "created_at"],
dtype={"order_id": "int32", "amount": "float32"},
parse_dates=["created_at"], # đổi thành datetime ngay khi đọc
na_values=["NA", "?", ""],
encoding="utf-8-sig",
nrows=5000,
)
print(df.dtypes)
Lưu ý: parse_dates chỉ parse khi format tương đối chuẩn (ISO 8601). Format lạ thì đọc xong gọi pd.to_datetime(df["col"], format="%d/%m/%Y") riêng.
JSON — pd.read_json và json_normalize
JSON dùng nhiều khi nhận response từ REST API. Pandas hỗ trợ qua read_json:
import pandas as pd
# JSON dạng list of records — phổ biến nhất
df = pd.read_json("data/users.json", orient="records")
Tham số orient cho biết JSON ở dạng nào: "records" (list of dicts), "split" ({columns, index, data}), "index" ({index: row}), "columns" ({column: values}), "values" (mảng 2D). Mặc định pandas tự đoán; nếu lỗi thì chỉ định rõ.
Với JSON nested (object lồng object), read_json sẽ để nguyên dict trong cell — không tiện cho phân tích. Dùng pd.json_normalize để flatten:
import json
import pandas as pd
data = [
{"id": 1, "name": "An", "addr": {"city": "HN", "zip": "100000"}},
{"id": 2, "name": "Binh","addr": {"city": "HCM","zip": "700000"}},
]
df = pd.json_normalize(data, sep="_")
print(df.columns.tolist())
# ['id', 'name', 'addr_city', 'addr_zip']
json_normalize còn nhận record_path để khai báo mảng con cần explode, và meta để giữ trường cha — tiện cho response API thực tế.
Excel — pd.read_excel
Excel cần package phụ trợ. Với .xlsx cần openpyxl; với .xls cũ cần xlrd.
pip install openpyxl
import pandas as pd
# Đọc 1 sheet cụ thể (theo tên hoặc index)
df = pd.read_excel("report.xlsx", sheet_name="Sales")
df0 = pd.read_excel("report.xlsx", sheet_name=0)
# Đọc TẤT CẢ sheet → dict {sheet_name: DataFrame}
all_sheets = pd.read_excel("report.xlsx", sheet_name=None)
print(list(all_sheets.keys()))
# Bỏ qua header rườm rà (logo, meta) ở 3 dòng đầu
df2 = pd.read_excel(
"report.xlsx",
sheet_name="Q1",
skiprows=3,
usecols="B:F", # Excel column letters
header=0,
)
Các tham số skiprows, usecols, header, dtype, parse_dates dùng tương tự CSV. Riêng usecols của Excel chấp nhận thêm dạng letter range ("B:F") hoặc list letter (["A","C","E"]).
Đọc trực tiếp từ URL
read_csv / read_json nhận trực tiếp URL — pandas sẽ tự download. Tiện cho dataset công khai trên GitHub, Kaggle public link, S3 URL.
import pandas as pd
# Titanic dataset trên GitHub
url = "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
df = pd.read_csv(url)
print(df.shape)
print(df.columns.tolist())
Với file lớn nên download về local 1 lần rồi đọc, tránh request lại mỗi lần chạy notebook.
Ghi file — to_csv / to_json / to_excel
import pandas as pd
df = pd.DataFrame({
"name": ["An", "Binh", "Cuong"],
"score": [8.5, 7.0, 9.2],
})
# CSV — index=False để không ghi cột RangeIndex thừa
df.to_csv("out.csv", index=False, encoding="utf-8")
# JSON — orient="records" + indent cho dễ đọc
df.to_json("out.json", orient="records", indent=2, force_ascii=False)
# Excel — chọn sheet_name, cần openpyxl
df.to_excel("out.xlsx", index=False, sheet_name="Data")
Điểm cần nhớ:
index=Falsegần như luôn cần khi ghi CSV / Excel — nếu không sẽ thừa cộtUnnamed: 0mỗi lần đọc lại.force_ascii=Falseđể JSON giữ tiếng Việt thay vì escape raá....- Muốn ghi nhiều sheet vào cùng 1 file Excel dùng
pd.ExcelWriter.
import pandas as pd
df1 = pd.DataFrame({"x": [1, 2, 3]})
df2 = pd.DataFrame({"y": [4, 5, 6]})
with pd.ExcelWriter("multi.xlsx", engine="openpyxl") as writer:
df1.to_excel(writer, sheet_name="A", index=False)
df2.to_excel(writer, sheet_name="B", index=False)
Encoding pitfall
Lỗi UnicodeDecodeError khi đọc CSV là chuyện thường gặp với file Việt:
utf-8— chuẩn hiện đại, mặc định của pandas.utf-8-sig— UTF-8 có BOM (Excel "Save As CSV UTF-8" hay sinh ra). Đọc bằngutf-8thường mã ký tự đầu lệch.cp1252/windows-1252— file Excel cũ từ Windows non-Unicode.latin-1— fallback khi không rõ encoding (đọc được mọi byte nhưng có thể sai chữ).
import pandas as pd
# Thử lần lượt encoding hay gặp khi đọc file Excel export
for enc in ("utf-8", "utf-8-sig", "cp1252", "latin-1"):
try:
df = pd.read_csv("vietnamese.csv", encoding=enc)
print(f"OK với encoding={enc}")
break
except UnicodeDecodeError:
continue
Khi ghi file để Excel mở được tiếng Việt: df.to_csv("out.csv", index=False, encoding="utf-8-sig").
Memory — chunksize cho file lớn
File CSV vài GB không load nguyên vào RAM được. Dùng chunksize để stream theo block:
import pandas as pd
total_amount = 0.0
# Mỗi chunk là 1 DataFrame 100k dòng
for chunk in pd.read_csv("big.csv", chunksize=100_000, usecols=["amount"]):
total_amount += chunk["amount"].sum()
print(f"Total: {total_amount:,.2f}")
Khi vẫn không đủ, cân nhắc:
- Pandas 2.x + PyArrow backend:
pd.read_csv(path, engine="pyarrow", dtype_backend="pyarrow")— nhanh hơn, tiết kiệm RAM hơn so với NumPy backend mặc định. - Polars: API gần Pandas, viết bằng Rust, multi-thread sẵn.
- Dask: chia DataFrame lớn thành nhiều partition, xử lý lazy.
dtype optimization và Parquet
Pandas mặc định đoán int64 / float64 / object — tốn RAM. Ép dtype hẹp hơn khi biết miền giá trị:
import pandas as pd
import numpy as np
df = pd.read_csv(
"logs.csv",
dtype={
"user_id": "int32", # đủ chứa < 2 tỉ
"device_id": "int16",
"score": "float32", # nửa RAM so với float64
"country": "category", # cột ít giá trị unique → category cực gọn
},
)
print(df.memory_usage(deep=True).sum() / 1e6, "MB")
Quy tắc nhanh:
- Số nguyên nhỏ < 32k →
int16; < 128 →int8. - Float ML thường
float32đủ chính xác. - Cột string với ít giá trị unique (gender, country, status) →
category— RAM giảm 5–20x.
Parquet nên là format lưu trung gian thay cho CSV: columnar, có schema (giữ dtype), nén tốt, đọc nhanh hơn nhiều lần. Cần pyarrow.
pip install pyarrow
import pandas as pd
df = pd.read_csv("logs.csv")
# Ghi Parquet — giữ dtype, nén snappy mặc định
df.to_parquet("logs.parquet", index=False)
# Đọc lại nhanh hơn nhiều
df2 = pd.read_parquet("logs.parquet")
Use case AI
- Train ML model:
read_csvfile Kaggle (Titanic, House Prices) rồitrain_test_splittrên DataFrame. - Đánh giá LLM: response từ API trả về JSON →
json_normalizeđể có 1 row mỗi sample, cột là metric. - Báo cáo doanh nghiệp: Excel nhiều sheet với header phức tạp →
read_excel(skiprows=, sheet_name=None)rồi concat. - Pipeline preprocessing: đọc CSV thô → clean → ghi
to_parquet. Bước train sau đóread_parquetnhanh hơn ~5–10x.
Code Python tổng hợp
Tạo file CSV mẫu, đọc lại, đọc thêm 1 URL public, rồi ghi DataFrame sang JSON:
import pandas as pd
# 1) Tạo DataFrame mẫu rồi ghi ra CSV
students = pd.DataFrame({
"id": [1, 2, 3, 4, 5],
"name": ["An", "Binh", "Cuong", "Dung", "Hoa"],
"score": [8.5, 7.0, 9.2, 6.5, 8.0],
"dob": ["2003-01-15", "2002-07-22", "2003-11-05",
"2001-03-30", "2002-09-12"],
})
students.to_csv("students.csv", index=False)
# 2) Đọc lại CSV — parse cột dob thành datetime, dùng id làm index
df = pd.read_csv(
"students.csv",
index_col="id",
parse_dates=["dob"],
dtype={"score": "float32"},
)
print(df.dtypes)
print(df.head())
# 3) Đọc Titanic từ URL public
url = "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
titanic = pd.read_csv(url, nrows=10) # preview 10 dòng
print(titanic[["Name", "Age", "Survived"]])
# 4) Ghi DataFrame ra JSON (orient="records", giữ tiếng Việt)
df.reset_index().to_json(
"students.json",
orient="records",
indent=2,
force_ascii=False,
date_format="iso",
)
Bài tập
- Tạo file
students.csvvới 5 dòng (id, name, score, dob), đọc lại bằngread_csvvà in radf.dtypes,df.head(). - Đọc lại file
students.csvvớiindex_col="id"vàparse_dates=["dob"]; xác nhận index làidvàdf.dob.dtypelàdatetime64[ns]. - Tạo 2 DataFrame (
scores,attendance), ghi cả hai vào cùng 1 filereport.xlsxở 2 sheet khác nhau bằngpd.ExcelWriter. Đọc lại vớisheet_name=Noneđể xác minh. - (Mở rộng) Đọc 1 file CSV bất kỳ > 50MB, so sánh RAM trước/sau khi ép
dtypehẹp + chuyển 1 cột string sangcategory(dùngdf.memory_usage(deep=True).sum()).
Tóm tắt
pd.read_csvlà cửa ngõ phổ biến nhất; nhớsep,header,index_col,usecols,dtype,parse_dates,encoding,na_values,skiprows,nrows.- JSON nested →
pd.json_normalize(data, sep="_")để có DataFrame phẳng. - Excel cần
openpyxl; dùngsheet_name=Noneđể lấy dict tất cả sheet,ExcelWriterđể ghi nhiều sheet. - URL truyền thẳng vào
read_csvđược; với file lớn nên cache về local. - Encoding hay gặp:
utf-8,utf-8-sig,cp1252. Ghi tiếng Việt cho Excel mở →utf-8-sig. - File lớn →
chunksize, hoặc Pandas 2.x + PyArrow, Polars, Dask. - Ép
dtype(int32,float32,category) và lưu trung gian bằng Parquet để pipeline đọc nhanh và đỡ tốn đĩa.
- Pandas Docs - pandas.read_csv
- Pandas Docs - pandas.read_json
- Pandas Docs - pandas.json_normalize
- Pandas Docs - pandas.read_excel
- Pandas Docs - pandas.read_parquet
- Pandas Docs - DataFrame.to_csv
- Pandas Docs - pandas.ExcelWriter
- Pandas User Guide - IO tools
- Pandas User Guide - Scaling to large datasets
- Apache Arrow - Reading and Writing Parquet
