Appearance
📘 Buổi 8: Pandas & Numpy — Data Cleaning chuyên nghiệp
Pandas = Excel on steroids. Xử lý 1 triệu dòng trong vài giây — điều mà Excel chỉ biết treo máy.
🎯 Mục tiêu buổi học
Sau buổi này, học viên sẽ:
- Tạo và thao tác DataFrame: select, filter, sort, group
- Xử lý missing values:
dropna,fillna,interpolate - Xử lý duplicates, data type conversion, string cleaning
- Merge/concat DataFrames (tương đương
JOINtrong SQL)
📋 Tổng quan
Ở Buổi 7, bạn đã nắm vững Python cơ bản — data types (int, float, str, list, dict), control flow (if/else, for, while), viết function, và đọc/ghi file. Bạn biết Python là ngôn ngữ linh hoạt, xử lý được mọi format dữ liệu. Nhưng nếu chỉ dùng Python thuần để phân tích data — bạn sẽ viết hàng trăm dòng code chỉ để lọc, nhóm, tính tổng. Đó là lý do Pandas tồn tại.
Pandas là thư viện Python chuyên xử lý dữ liệu dạng bảng (tabular data) — chính xác thứ mà Data Analyst làm việc hàng ngày. Hãy nghĩ Pandas như sự kết hợp hoàn hảo: nó có giao diện bảng như Excel, sức mạnh truy vấn như SQL, và tốc độ xử lý của Python. Còn Numpy (Numerical Python) là nền tảng toán học bên dưới Pandas — mỗi cột DataFrame thực chất là một numpy array, và hiểu Numpy giúp bạn viết code nhanh hơn gấp 10–100 lần so với Python thuần.
Nhớ lại hành trình OSEMN (Obtain → Scrub → Explore → Model → iNterpret): Buổi 7 bạn đã biết cách Obtain dữ liệu bằng Python (open, csv, json). Buổi 8 tập trung vào bước Scrub — làm sạch dữ liệu bằng Pandas & Numpy, bước quan trọng nhất chiếm 60–80% thời gian của Data Analyst.
mermaid
flowchart LR
A["📥 Obtain<br/>Buổi 7: Python đọc file"] --> B["🧹 Scrub<br/>✅ Buổi 8: Pandas Data Cleaning"]
B --> C["🔍 Explore<br/>Buổi 9: EDA"]
C --> D["🤖 Model<br/>Buổi 12+"]
D --> E["📊 iNterpret<br/>Buổi 10-11: Visualization"]
style B fill:#e8f5e9,stroke:#4caf50,stroke-width:3px💡 Tại sao chuyển từ Excel sang Pandas?
| Tiêu chí | Excel | Pandas |
|---|---|---|
| Giới hạn dòng | ~1,048,576 dòng | Hàng chục triệu dòng (tuỳ RAM) |
| Tốc độ xử lý 1M dòng | Treo máy / crash | 2–5 giây |
| Lặp lại thao tác | Click lại từ đầu | 1 dòng code, chạy lại vô hạn |
| Audit trail | Không biết ai sửa gì | Code = documentation |
| Kết nối data sources | Limited | CSV, Excel, SQL, API, JSON, Parquet... |
📌 Phần 1: Pandas Basics — DataFrame là gì và tại sao nó mạnh
Series vs DataFrame
Pandas có 2 cấu trúc dữ liệu chính:
- Series: Một cột dữ liệu — giống 1 cột trong Excel hoặc 1 list Python, nhưng có index (nhãn cho mỗi row).
- DataFrame: Bảng 2 chiều — gồm nhiều Series ghép lại, giống 1 sheet Excel hoặc 1 bảng SQL.
python
import pandas as pd
import numpy as np
# Series — 1 cột doanh thu
revenue = pd.Series([15000000, 22000000, 18500000, 31000000],
index=["Q1", "Q2", "Q3", "Q4"],
name="doanh_thu")
print(revenue)
# Q1 15000000
# Q2 22000000
# Q3 18500000
# Q4 31000000
# Name: doanh_thu, dtype: int64python
# DataFrame — bảng dữ liệu hoàn chỉnh
df = pd.DataFrame({
"san_pham": ["Laptop", "Chuột", "Bàn phím", "Màn hình", "Tai nghe"],
"gia": [25000000, 350000, 1200000, 8500000, 2500000],
"so_luong": [120, 500, 300, 80, 450],
"danh_muc": ["Máy tính", "Phụ kiện", "Phụ kiện", "Máy tính", "Phụ kiện"]
})
print(df)| san_pham | gia | so_luong | danh_muc | |
|---|---|---|---|---|
| 0 | Laptop | 25000000 | 120 | Máy tính |
| 1 | Chuột | 350000 | 500 | Phụ kiện |
| 2 | Bàn phím | 1200000 | 300 | Phụ kiện |
| 3 | Màn hình | 8500000 | 80 | Máy tính |
| 4 | Tai nghe | 2500000 | 450 | Phụ kiện |
Đọc dữ liệu từ file
Trong thực tế, bạn hiếm khi tự gõ data. Pandas đọc được gần như mọi format:
python
# Đọc CSV — format phổ biến nhất
df = pd.read_csv("sales_data.csv")
# Đọc Excel — khi đồng nghiệp gửi file .xlsx
df = pd.read_excel("bao_cao_q4.xlsx", sheet_name="Sheet1")
# Đọc JSON — khi nhận data từ API
df = pd.read_json("api_response.json")
# Đọc từ SQL — kết nối trực tiếp database
import sqlite3
conn = sqlite3.connect("ecommerce.db")
df = pd.read_sql("SELECT * FROM orders WHERE year = 2025", conn)python
# Kiểm tra nhanh dataset sau khi đọc — 5 lệnh "must-run"
print(f"Kích thước: {df.shape[0]:,} dòng × {df.shape[1]} cột")
print(df.head()) # 5 dòng đầu
print(df.info()) # Kiểu dữ liệu, missing values
print(df.describe()) # Thống kê cơ bản (mean, std, min, max)
print(df.dtypes) # Kiểu dữ liệu từng cộtSelection — Chọn dữ liệu: loc, iloc, boolean indexing
Đây là kỹ năng quan trọng nhất — tương đương SELECT ... WHERE trong SQL và Filter trong Excel.
python
# loc — chọn theo TÊN cột/index (label-based)
df.loc[0:2, ["san_pham", "gia"]] # Dòng 0-2, cột san_pham & gia
# iloc — chọn theo VỊ TRÍ (integer-based)
df.iloc[0:3, [0, 1]] # 3 dòng đầu, 2 cột đầu
# Boolean indexing — lọc theo điều kiện (= WHERE trong SQL)
expensive = df[df["gia"] > 2000000] # Sản phẩm giá > 2 triệu
print(expensive)💡 So sánh 3 công cụ — Lọc dữ liệu
| Thao tác | Excel | SQL | Pandas |
|---|---|---|---|
| Lọc giá > 2M | Filter → Number > 2000000 | WHERE gia > 2000000 | df[df["gia"] > 2000000] |
| Chọn 2 cột | Ẩn cột khác | SELECT col1, col2 | df[["col1", "col2"]] |
| Lọc nhiều điều kiện | Filter nhiều lần | WHERE a > 1 AND b = 'X' | df[(df["a"] > 1) & (df["b"] == "X")] |
Thao tác cột — rename, drop, assign, apply
python
# Thêm cột mới — tính doanh thu
df["doanh_thu"] = df["gia"] * df["so_luong"]
# Đổi tên cột
df = df.rename(columns={"gia": "don_gia", "so_luong": "sl_ban"})
# Xóa cột không cần
df = df.drop(columns=["danh_muc"])
# apply — áp dụng function lên từng giá trị (giống kéo công thức Excel)
df["phan_loai_gia"] = df["don_gia"].apply(
lambda x: "Cao cấp" if x > 5000000 else "Phổ thông"
)
print(df[["san_pham", "don_gia", "phan_loai_gia"]])| san_pham | don_gia | phan_loai_gia | |
|---|---|---|---|
| 0 | Laptop | 25000000 | Cao cấp |
| 1 | Chuột | 350000 | Phổ thông |
| 2 | Bàn phím | 1200000 | Phổ thông |
| 3 | Màn hình | 8500000 | Cao cấp |
| 4 | Tai nghe | 2500000 | Phổ thông |
📌 Phần 2: Data Cleaning với Pandas — Nghệ thuật làm sạch dữ liệu
Data thực tế luôn bẩn — missing values, duplicate rows, sai kiểu dữ liệu, chuỗi không nhất quán. Bước Scrub trong OSEMN chiếm 60–80% thời gian, và Pandas là vũ khí tối thượng cho việc này.
Missing values — Xử lý giá trị thiếu (NaN)
python
# Tạo dataset có missing values (NaN) — mô phỏng thực tế
df_dirty = pd.DataFrame({
"ma_kh": ["KH001", "KH002", "KH003", "KH004", "KH005", "KH006"],
"ten": ["An", "Bình", None, "Dũng", "Em", "Phúc"],
"email": ["an@mail.com", None, "cuong@mail.com", None, "em@mail.com", "phuc@mail.com"],
"tuoi": [28, 35, None, 42, 31, None],
"doanh_thu": [5000000, 12000000, 8000000, None, 3500000, 9500000]
})
print(df_dirty)| ma_kh | ten | tuoi | doanh_thu | ||
|---|---|---|---|---|---|
| 0 | KH001 | An | an@mail.com | 28.0 | 5000000.0 |
| 1 | KH002 | Bình | NaN | 35.0 | 12000000.0 |
| 2 | KH003 | NaN | cuong@mail.com | NaN | 8000000.0 |
| 3 | KH004 | Dũng | NaN | 42.0 | NaN |
| 4 | KH005 | Em | em@mail.com | 31.0 | 3500000.0 |
| 5 | KH006 | Phúc | phuc@mail.com | NaN | 9500000.0 |
python
# Bước 1: Kiểm tra missing values
print(df_dirty.isnull().sum())
# ma_kh 0
# ten 1
# email 2
# tuoi 2
# doanh_thu 1
print(f"Tỷ lệ missing: {df_dirty.isnull().sum().sum() / df_dirty.size * 100:.1f}%")
# Tỷ lệ missing: 20.0%python
# Bước 2: Xử lý — chọn chiến lược phù hợp từng cột
# dropna — xóa dòng có NaN (khi missing ít, < 5%)
df_clean = df_dirty.dropna(subset=["ten"]) # Xóa dòng thiếu tên
# fillna — điền giá trị thay thế
df_dirty["tuoi"] = df_dirty["tuoi"].fillna(df_dirty["tuoi"].median()) # Điền median
df_dirty["doanh_thu"] = df_dirty["doanh_thu"].fillna(df_dirty["doanh_thu"].mean()) # Điền mean
df_dirty["email"] = df_dirty["email"].fillna("không_có@unknown.com") # Điền giá trị mặc định
# ffill / bfill — điền theo dòng trước/sau (time series)
# df["price"] = df["price"].fillna(method="ffill") # Forward fill⚠️ Lỗi phổ biến khi xử lý NaN
- Xóa hết NaN mà không suy nghĩ → mất 50% data. Luôn kiểm tra tỷ lệ missing trước!
- Điền mean cho cột có outlier → bị lệch. Dùng
medianthay vìmeankhi dữ liệu skewed. - Quên kiểm tra cột nào bị NaN → Luôn chạy
df.isnull().sum()đầu tiên.
Duplicates — Xử lý dòng trùng lặp
python
# Tạo data có duplicate
df_orders = pd.DataFrame({
"order_id": [1001, 1002, 1002, 1003, 1004, 1004],
"san_pham": ["Laptop", "Chuột", "Chuột", "Bàn phím", "Tai nghe", "Tai nghe"],
"gia": [25000000, 350000, 350000, 1200000, 2500000, 2500000]
})
# Kiểm tra duplicate
print(df_orders.duplicated().sum()) # 2 dòng trùng
print(df_orders[df_orders.duplicated()]) # Xem dòng nào trùng
# Xóa duplicate — giữ dòng đầu tiên
df_orders = df_orders.drop_duplicates(subset=["order_id"], keep="first")
print(f"Sau cleaning: {len(df_orders)} dòng")
# Sau cleaning: 4 dòngData type conversion — Chuyển đổi kiểu dữ liệu
python
# Thực tế: cột ngày thường bị đọc thành string
df_sales = pd.DataFrame({
"ngay_mua": ["2025-01-15", "2025-02-20", "2025-03-10"],
"gia_str": ["15,000,000", "22,500,000", "8,750,000"],
"so_luong": ["5", "3", "10"]
})
# Chuyển string → datetime
df_sales["ngay_mua"] = pd.to_datetime(df_sales["ngay_mua"])
# Chuyển string có dấu phẩy → số
df_sales["gia"] = df_sales["gia_str"].str.replace(",", "").astype(int)
# Chuyển string → int
df_sales["so_luong"] = pd.to_numeric(df_sales["so_luong"])
print(df_sales.dtypes)
# ngay_mua datetime64[ns]
# gia_str object
# gia int64
# so_luong int64String cleaning — Làm sạch chuỗi
python
# Data thực tế: chuỗi lộn xộn, không nhất quán
df_customers = pd.DataFrame({
"ten": [" Nguyễn Văn An ", "TRẦN THỊ BÌNH", "lê văn cường", "Phạm Dũng "],
"email": ["AN@Gmail.COM", "binh@yahoo.com", "CUONG@MAIL.COM", "dung@mail.com"],
"thanh_pho": ["Hà Nội", "hà nội", "HÀ NỘI", "TP.HCM"]
})
# Chuẩn hóa chuỗi bằng .str accessor
df_customers["ten"] = df_customers["ten"].str.strip().str.title()
df_customers["email"] = df_customers["email"].str.lower().str.strip()
df_customers["thanh_pho"] = df_customers["thanh_pho"].str.title()
# Tìm kiếm & thay thế
has_gmail = df_customers["email"].str.contains("gmail")
df_customers["email_provider"] = df_customers["email"].str.extract(r"@(\w+)\.")
print(df_customers)| ten | thanh_pho | email_provider | ||
|---|---|---|---|---|
| 0 | Nguyễn Văn An | an@gmail.com | Hà Nội | gmail |
| 1 | Trần Thị Bình | binh@yahoo.com | Hà Nội | yahoo |
| 2 | Lê Văn Cường | cuong@mail.com | Hà Nội | |
| 3 | Phạm Dũng | dung@mail.com | Tp.Hcm |
📌 Method Chaining — Viết code Pandas "sạch"
Thay vì viết từng dòng riêng lẻ, Pandas cho phép nối các thao tác thành pipeline:
python
# ❌ Không tối ưu — nhiều dòng trung gian
df = df.dropna(subset=["ten"])
df = df.drop_duplicates()
df = df.reset_index(drop=True)
df = df.sort_values("doanh_thu", ascending=False)
# ✅ Method chaining — sạch, rõ ràng, professional
df_clean = (df
.dropna(subset=["ten"])
.drop_duplicates()
.reset_index(drop=True)
.sort_values("doanh_thu", ascending=False)
)Method chaining giống pipeline trong shell (cat file | grep error | sort). Mỗi bước nhận DataFrame từ bước trước, xử lý, trả về DataFrame mới.
📌 Phần 3: Numpy Essentials — Tốc độ và toán học
Numpy array vs Python list — Tại sao nhanh hơn?
Numpy (Numerical Python) là thư viện nền tảng mà Pandas xây dựng trên đó. Numpy array lưu dữ liệu trong bộ nhớ liên tục (contiguous memory) và sử dụng C code bên dưới — nhanh hơn Python list 10–100 lần.
python
import numpy as np
import time
# So sánh tốc độ: Python list vs Numpy array
size = 1_000_000
# Python list
py_list = list(range(size))
start = time.time()
result_py = [x * 2 for x in py_list]
print(f"Python list: {time.time() - start:.4f}s")
# Python list: 0.0850s
# Numpy array
np_arr = np.arange(size)
start = time.time()
result_np = np_arr * 2
print(f"Numpy array: {time.time() - start:.4f}s")
# Numpy array: 0.0015s → Nhanh hơn ~56 lần!💡 Tại sao Numpy nhanh hơn?
| Đặc điểm | Python list | Numpy array |
|---|---|---|
| Kiểu dữ liệu | Hỗn hợp (int, str, ...) | Đồng nhất (toàn int64 hoặc float64) |
| Bộ nhớ | Phân tán (pointers) | Liên tục (contiguous block) |
| Vòng lặp | Python loop (chậm) | Vectorized C code (nhanh) |
| DataFrame | — | Mỗi cột Pandas = 1 numpy array |
Vectorized operations — Tính toán không cần loop
python
# Doanh thu và chi phí của 5 cửa hàng (đơn vị: triệu VNĐ)
revenue = np.array([150, 220, 180, 310, 250])
cost = np.array([90, 130, 110, 180, 160])
# Vectorized — không cần for loop!
profit = revenue - cost
margin = (profit / revenue) * 100
print("Lợi nhuận:", profit) # [60 90 70 130 90]
print("Biên LN (%):", margin.round(1)) # [40. 40.9 38.9 41.9 36. ]Statistical functions — Thống kê nhanh
python
daily_sales = np.array([
15_500_000, 22_300_000, 18_700_000, 31_200_000, 12_800_000,
28_900_000, 19_500_000, 25_600_000, 14_200_000, 33_100_000
])
print(f"Trung bình: {np.mean(daily_sales):>15,.0f} VNĐ")
print(f"Trung vị: {np.median(daily_sales):>15,.0f} VNĐ")
print(f"Độ lệch chuẩn:{np.std(daily_sales):>15,.0f} VNĐ")
print(f"Min: {np.min(daily_sales):>15,.0f} VNĐ")
print(f"Max: {np.max(daily_sales):>15,.0f} VNĐ")
print(f"Percentile 25:{np.percentile(daily_sales, 25):>15,.0f} VNĐ")
print(f"Percentile 75:{np.percentile(daily_sales, 75):>15,.0f} VNĐ")
# Trung bình: 22,180,000 VNĐ
# Trung vị: 20,900,000 VNĐ
# Độ lệch chuẩn: 6,864,267 VNĐ
# Min: 12,800,000 VNĐ
# Max: 33,100,000 VNĐ
# Percentile 25: 15,800,000 VNĐ
# Percentile 75: 27,675,000 VNĐBoolean masking & np.where
python
# Boolean masking — lọc dữ liệu siêu nhanh
sales = np.array([15, 22, 8, 31, 12, 28, 5, 33, 19, 27])
# Tìm ngày có doanh thu > 20 triệu
high_days = sales[sales > 20]
print(f"Ngày doanh thu cao: {high_days}") # [22 31 28 33 27]
print(f"Số ngày cao: {len(high_days)}/{len(sales)}") # 5/10
# np.where — giống IF trong Excel
labels = np.where(sales > 20, "Tốt", "Cần cải thiện")
print(labels)
# ['Cần cải thiện' 'Tốt' 'Cần cải thiện' 'Tốt' 'Cần cải thiện'
# 'Tốt' 'Cần cải thiện' 'Tốt' 'Cần cải thiện' 'Tốt']📌 Khi nào dùng Numpy vs Pandas?
- Numpy: Tính toán số học thuần túy, xử lý mảng đồng nhất, cần tốc độ tối đa
- Pandas: Dữ liệu dạng bảng (nhiều cột, nhiều kiểu), lọc/nhóm/merge, phân tích business
- Thực tế: Bạn sẽ dùng Pandas 90% thời gian — Numpy chạy "ngầm" bên dưới. Nhưng hiểu Numpy giúp bạn debug nhanh hơn và viết code hiệu quả hơn.
📌 Phần 4: Merge & Concat — Nối bảng như SQL JOIN
Trong thực tế, dữ liệu không bao giờ nằm trong 1 bảng duy nhất. Bạn có bảng orders, bảng customers, bảng products — cần nối chúng lại để phân tích. Nếu bạn biết JOIN trong SQL (Buổi 5), đây chỉ là cú pháp khác cho cùng một tư duy.
pd.merge — SQL JOIN trong Pandas
python
# Bảng đơn hàng
orders = pd.DataFrame({
"order_id": [1001, 1002, 1003, 1004, 1005],
"customer_id": ["KH01", "KH02", "KH03", "KH01", "KH05"],
"product_id": ["SP01", "SP02", "SP01", "SP03", "SP02"],
"so_luong": [2, 1, 3, 1, 2]
})
# Bảng khách hàng
customers = pd.DataFrame({
"customer_id": ["KH01", "KH02", "KH03", "KH04"],
"ten_kh": ["Nguyễn An", "Trần Bình", "Lê Cường", "Phạm Dũng"],
"thanh_pho": ["Hà Nội", "TP.HCM", "Đà Nẵng", "Hà Nội"]
})
# Bảng sản phẩm
products = pd.DataFrame({
"product_id": ["SP01", "SP02", "SP03"],
"ten_sp": ["Laptop", "Chuột Logitech", "Bàn phím cơ"],
"don_gia": [25000000, 850000, 2200000]
})python
# INNER JOIN — chỉ lấy dòng có match ở cả 2 bảng
df_inner = pd.merge(orders, customers, on="customer_id", how="inner")
print(f"Inner join: {len(df_inner)} dòng") # 4 dòng (KH05 không có trong customers)
# LEFT JOIN — giữ tất cả orders, thêm info customers
df_left = pd.merge(orders, customers, on="customer_id", how="left")
print(f"Left join: {len(df_left)} dòng") # 5 dòng (KH05 có NaN ở ten_kh, thanh_pho)
# Nối 3 bảng — pipeline thực tế
df_full = (orders
.merge(customers, on="customer_id", how="left")
.merge(products, on="product_id", how="left")
)
df_full["thanh_tien"] = df_full["don_gia"] * df_full["so_luong"]
print(df_full[["order_id", "ten_kh", "ten_sp", "thanh_tien"]])| order_id | ten_kh | ten_sp | thanh_tien | |
|---|---|---|---|---|
| 0 | 1001 | Nguyễn An | Laptop | 50000000 |
| 1 | 1002 | Trần Bình | Chuột Logitech | 850000 |
| 2 | 1003 | Lê Cường | Laptop | 75000000 |
| 3 | 1004 | Nguyễn An | Bàn phím cơ | 2200000 |
| 4 | 1005 | NaN | Chuột Logitech | 1700000 |
💡 So sánh Merge types — Pandas vs SQL
| Pandas | SQL | Kết quả |
|---|---|---|
how="inner" | INNER JOIN | Chỉ dòng match cả 2 bảng |
how="left" | LEFT JOIN | Giữ tất cả bảng trái |
how="right" | RIGHT JOIN | Giữ tất cả bảng phải |
how="outer" | FULL OUTER JOIN | Giữ tất cả cả 2 bảng |
on="col" | ON a.col = b.col | Cột dùng để nối |
pd.concat — Nối DataFrame theo dòng hoặc cột
concat khác merge: nó ghép DataFrames lại (stack) thay vì nối theo key. Giống UNION trong SQL hơn là JOIN.
python
# Doanh thu Q1 và Q2 — 2 file riêng biệt
q1 = pd.DataFrame({
"thang": ["T1", "T2", "T3"],
"doanh_thu": [150_000_000, 180_000_000, 200_000_000]
})
q2 = pd.DataFrame({
"thang": ["T4", "T5", "T6"],
"doanh_thu": [220_000_000, 195_000_000, 280_000_000]
})
# Nối theo dòng (axis=0) — ghép Q1 + Q2
half_year = pd.concat([q1, q2], ignore_index=True)
print(half_year)| thang | doanh_thu | |
|---|---|---|
| 0 | T1 | 150000000 |
| 1 | T2 | 180000000 |
| 2 | T3 | 200000000 |
| 3 | T4 | 220000000 |
| 4 | T5 | 195000000 |
| 5 | T6 | 280000000 |
python
# Nối theo cột (axis=1) — thêm cột từ nguồn khác
chi_phi = pd.DataFrame({
"thang": ["T1", "T2", "T3"],
"chi_phi": [90_000_000, 110_000_000, 120_000_000]
})
q1_full = pd.concat([q1, chi_phi["chi_phi"]], axis=1)
q1_full["loi_nhuan"] = q1_full["doanh_thu"] - q1_full["chi_phi"]
print(q1_full)Multi-index basics
Khi dữ liệu có nhiều cấp nhóm (ví dụ: doanh thu theo thành phố VÀ theo tháng), Pandas dùng Multi-index để tổ chức:
python
df_sales = pd.DataFrame({
"thanh_pho": ["Hà Nội", "Hà Nội", "TP.HCM", "TP.HCM", "Đà Nẵng", "Đà Nẵng"],
"quy": ["Q1", "Q2", "Q1", "Q2", "Q1", "Q2"],
"doanh_thu": [500, 620, 780, 850, 300, 340]
})
# Tạo Multi-index
df_multi = df_sales.set_index(["thanh_pho", "quy"])
print(df_multi)
# Truy vấn theo cấp
print(df_multi.loc["Hà Nội"]) # Tất cả quý của Hà Nội
print(df_multi.loc[("TP.HCM", "Q2")]) # TP.HCM quý 2⚠️ SettingWithCopyWarning — Lỗi kinh điển
python
# ❌ SAI — tạo view, không phải copy → warning
df_filtered = df[df["gia"] > 5000000]
df_filtered["status"] = "premium" # ⚠️ SettingWithCopyWarning!
# ✅ ĐÚNG — dùng .copy() để tạo bản sao độc lập
df_filtered = df[df["gia"] > 5000000].copy()
df_filtered["status"] = "premium" # ✅ Không warningLuôn dùng .copy() khi muốn tạo DataFrame mới từ filter để tránh lỗi này.
🔑 Từ khóa chính
| Tiếng Việt | English | Giải thích |
|---|---|---|
| Khung dữ liệu | DataFrame | Bảng dữ liệu 2 chiều trong Pandas — tương đương 1 sheet Excel |
| Giá trị thiếu | Missing Value (NaN) | Ô dữ liệu trống, không có giá trị — cần dropna hoặc fillna |
| Nối bảng | Merge / Concat | Ghép 2+ DataFrame — merge = JOIN, concat = UNION |
| Áp dụng hàm | Apply | Áp dụng function lên từng dòng/cột — giống kéo công thức Excel |
| Chỉ mục | Index | Nhãn xác định mỗi dòng trong DataFrame — giống Primary Key |
| Mảng số học | Numpy Array | Cấu trúc dữ liệu cốt lõi của Numpy — nhanh hơn list 10–100x |
| Phép toán vector | Vectorized Operation | Tính toán trên toàn mảng mà không cần vòng lặp |
| Dòng trùng lặp | Duplicate | Dòng dữ liệu bị lặp — dùng drop_duplicates để xóa |
📊 Tổng kết buổi học
✅ Checklist — Bạn đã nắm được
- [ ] Tạo DataFrame, đọc data từ CSV/Excel/JSON/SQL
- [ ] Chọn dữ liệu bằng
loc,iloc, boolean indexing - [ ] Thao tác cột:
rename,drop,assign,apply - [ ] Kiểm tra và xử lý missing values:
isnull,dropna,fillna - [ ] Xóa duplicates với
drop_duplicates - [ ] Chuyển đổi kiểu dữ liệu:
astype,to_datetime,pd.to_numeric - [ ] Làm sạch chuỗi:
.str.strip(),.str.lower(),.str.contains() - [ ] Dùng Numpy cho tính toán nhanh:
np.mean,np.where, boolean masking - [ ] Merge DataFrames (inner, left, right, outer) — tương đương SQL JOIN
- [ ] Concat DataFrames theo dòng/cột
- [ ] Viết method chaining pipeline sạch
🗺️ Hành trình học tập
Buổi 3-4: Excel — Click chuột, giới hạn 1M dòng
↓
Buổi 5-6: SQL — Query database, JOIN bảng
↓
Buổi 7: Python — Lập trình cơ bản, đọc/ghi file
↓
✅ Buổi 8: Pandas & Numpy — Data Cleaning chuyên nghiệp
↓
→ Buổi 9: EDA với Python — Phân tích khám phá dữ liệuBạn đã hoàn thành bước nhảy lớn nhất: từ click chuột trong Excel → viết code Pandas xử lý hàng triệu dòng. Từ buổi này, bạn chính thức là Pandas user — mọi bài toán data cleaning, dù 100 dòng hay 10 triệu dòng, đều giải quyết bằng cùng một đoạn code.
🔗 Tài liệu tham khảo
- Pandas Official Documentation — Tài liệu chính thức, đầy đủ nhất
- Numpy Official Documentation — Tài liệu chính thức Numpy
- 10 Minutes to Pandas — Hướng dẫn nhanh từ Pandas chính thức
- Pandas Cheat Sheet — DataCamp — Bảng tóm tắt lệnh Pandas
- Python for Data Analysis — Wes McKinney — Sách kinh điển từ tác giả Pandas
- Real Python — Pandas Tutorials — Hướng dẫn thực hành Pandas