NLP cơ bản: tokenize, BoW và TF-IDF
Tiền xử lý văn bản, tách từ, làm sạch, ma trận thuật ngữ tài liệu, TF-IDF và diễn giải kết quả trên ví dụ minh họa.
Trung bìnhThuật toán ~60 phút
Ôn lại trước khi học
Giới thiệu
Bài này học biến văn bản thô thành số. Việc này giúp máy phân loại review và tweet được.
Kiến thức cần nhớ
Tách từ và làm sạch
- Tokenize: cắt câu thành mảnh nhỏ thường là từ.
- Làm sạch: thường hóa, gỡ dấu câu, số, thẻ HTML.
- Chuẩn hóa: bỏ từ dừng, đưa về gốc từ.
- Ví dụ đời thường: tiếng Việt phải tách từ ghép, không cắt bừa.
Túi từ BoW
- Gom từ vựng, mỗi văn bản thành vector đếm từ.
- Nhiều văn bản xếp thành ma trận hàng là văn bản.
- Ma trận rất thưa vì mỗi văn bản dùng ít từ.
- Ví dụ đời thường: hay và không hay cho cùng một vector nên mất thứ tự.
TF-IDF cân bằng
- TF: từ quan trọng thế nào trong văn bản này.
- IDF: từ hiếm thế nào trên toàn tập.
- Nhân hai cái ra trọng số cuối, từ hiếm được nâng.
- Ví dụ đời thường: ngon ở khắp nơi bị hạ, hải sản tươi hiếm được nâng.
# Ý tưởng TF-IDF: hay trong bài, hiếm toàn tập
def tfidf(tf, df, N):
import math # dùng log
idf = math.log(N / df) # hiếm thì idf cao
return tf * idf # nhân hai cái
Ví dụ
- Input: từ the ở 100% tài liệu -> Output: IDF về 0, TF-IDF thấp dù đếm cao.
- Câu này cho thấy đếm cao chưa chắc quan trọng.
- Input: đảo thứ tự từ giữ nguyên multiset -> Output: vector BoW không đổi.
- Câu này chứng minh BoW mất thứ tự.
💻 Bài tập
Ngôn ngữ: Python 3. Bài 1-2 chỉ dùng thư viện chuẩn và NumPy. Nộp vào day-057/.
Bài 1: Tokenize và làm sạch
| Hàm | Yêu cầu |
|---|---|
clean(text) | Chữ thường, gỡ thẻ HTML, gỡ URL, gỡ số, gộp khoảng trắng |
tokenize(text) | Tách theo ký tự không phải chữ, giữ được chữ tiếng Việt có dấu |
remove_stopwords(tokens, stopwords) | |
ngrams(tokens, n) | Trả list chuỗi nối bằng _ |
clean("<b>Giá 100k!</b> xem tại https://x.vn") -> "giá k xem tại"
tokenize("Học máy, học sâu.") -> ["học", "máy", "học", "sâu"]
ngrams(["học","máy","học"], 2) -> ["học_máy", "máy_học"]
Bài 2: Bag of Words và TF-IDF
class CountVectorizer:
def fit(self, docs): ... # vocab_: dict[từ, cột], sắp alphabet
def transform(self, docs) -> np.ndarray: ...
class TfidfVectorizer:
def fit(self, docs): ... # idf = ln((1 + N) / (1 + df)) + 1
def transform(self, docs): ... # tf là số đếm thô, chuẩn hóa L2 mỗi hàng
docs = ["mèo ăn cá", "chó ăn thịt", "mèo và chó"]
vocab_ có 7 từ; "ăn" xuất hiện ở 2/3 văn bản nên idf thấp hơn "cá"
Đảo thứ tự từ trong 1 văn bản -> vector BoW không đổi
Kết quả TfidfVectorizer phải khớp sklearn.feature_extraction.text.TfidfVectorizer (tham số mặc định, cùng tokenizer).
Bài 3: Tìm văn bản giống nhau (nâng cao)
- Lấy 200 bài báo ngắn (tự thu thập hoặc bộ dữ liệu công khai).
- Biểu diễn TF-IDF. Với một câu truy vấn, trả top 5 bài có cosine cao nhất.
- Lưu ma trận dạng thưa (
dicthoặcscipy.sparse). In tỉ lệ ô khác 0. - So kết quả top 5 khi có và không bỏ từ dừng.
✅ Tiêu chí hoàn thành
- Test mẫu pass.
- TF-IDF khớp
sklearnvới sai số1e-9. - Bài 3 trả kết quả hợp lý cho 3 truy vấn, có in độ thưa.
- Giải thích được vì sao "the" có IDF thấp.
❓ Câu hỏi ôn tập
- Tokenize và làm sạch gồm bước nào?
- Ma trận thuật ngữ hàng cột là gì?
- TF và IDF mỗi cái đo gì?
- BoW mất thông tin gì quan trọng?
🌕 Bạn đã hoàn thành ngày 57. Làm hết bài tập phía trên rồi sang ngày tiếp theo.