Xử Lý Ngôn Ngữ Tự Nhiên với Python: Hướng Dẫn Phân Loại Văn Bản

Build a text classification pipeline from scratch using Python and NLP.

Viết bởi admin
June 20, 2026 8 phút đọc 1 lượt xem
Xử lý ngôn ngữ tự nhiên với Python

Xử lý ngôn ngữ tự nhiên (NLP — Natural Language Processing) là một trong những lĩnh vực thú vị và ứng dụng thực tế nhất của trí tuệ nhân tạo. Từ phân loại email spam, phân tích cảm xúc review sản phẩm, đến chatbot và trợ lý ảo — NLP có mặt ở khắp nơi. Trong bài hướng dẫn này, chúng ta sẽ xây dựng từ đầu một hệ thống phân loại văn bản tiếng Việt, đi qua toàn bộ pipeline từ tiền xử lý văn bản thô đến mô hình production-ready.

Cài Đặt

pip install nltk scikit-learn underthesea pandas numpy matplotlib seaborn

Cho tiếng Việt, chúng ta sẽ dùng thư viện underthesea — bộ công cụ NLP tiếng Việt được phát triển bởi cộng đồng mã nguồn mở Việt Nam, hỗ trợ word tokenization, POS tagging và nhiều tác vụ NLP khác.

Bước 1: Tiền Xử Lý Văn Bản với NLTK

Trước khi đưa văn bản vào mô hình, cần tiền xử lý để loại bỏ nhiễu và chuẩn hóa:

import nltk
import re
import string
from underthesea import word_tokenize

# Download NLTK data (chỉ cần làm một lần)
nltk.download('stopwords')
nltk.download('punkt')

# Danh sách stopwords tiếng Việt cơ bản
vi_stopwords = set([
    'và', 'của', 'là', 'có', 'trong', 'với', 'một', 'các',
    'được', 'những', 'để', 'từ', 'này', 'đã', 'không', 'cũng',
    'như', 'cho', 'về', 'thì', 'đó', 'hay', 'bị', 'khi', 'vì'
])

def preprocess_vietnamese(text):
    """Pipeline tiền xử lý văn bản tiếng Việt."""
    # Lowercase
    text = text.lower()
    # Loại bỏ URL
    text = re.sub(r'httpS+|wwwS+', '', text)
    # Loại bỏ HTML tags
    text = re.sub(r'', '', text)
    # Loại bỏ ký tự đặc biệt, giữ lại dấu tiếng Việt
    text = re.sub(r'[^wsÀ-ɏḀ-ỿ]', ' ', text)
    # Tách từ (word tokenization) với underthesea
    tokens = word_tokenize(text, format='text').split()
    # Loại bỏ stopwords và token quá ngắn
    tokens = [t for t in tokens if t not in vi_stopwords and len(t) > 1]
    return ' '.join(tokens)

# Test
sample = "Sản phẩm này rất tốt và tôi rất hài lòng với chất lượng!"
print(preprocess_vietnamese(sample))

Bước 2: Bag of Words và TF-IDF

Để đưa văn bản vào mô hình ML, cần chuyển thành dạng số. Hai phương pháp phổ biến nhất:

from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
import pandas as pd

# Dữ liệu mẫu — phân loại cảm xúc review sản phẩm
texts = [
    "Sản phẩm tuyệt vời, giao hàng nhanh, rất hài lòng",
    "Chất lượng kém, vỡ sau 2 ngày sử dụng, không mua lại",
    "Màu sắc đẹp, đúng với mô tả, giá hợp lý",
    "Giao hàng chậm, đóng gói xấu, thất vọng",
    "Dùng tốt lắm, sẽ giới thiệu bạn bè, cảm ơn shop",
    "Hàng giả, không như hình, yêu cầu hoàn tiền",
]
labels = [1, 0, 1, 0, 1, 0]  # 1=positive, 0=negative

# Tiền xử lý
processed_texts = [preprocess_vietnamese(t) for t in texts]

# Bag of Words
bow_vectorizer = CountVectorizer(max_features=1000)
X_bow = bow_vectorizer.fit_transform(processed_texts)
print(f"BoW shape: {X_bow.shape}")
print(f"Vocabulary size: {len(bow_vectorizer.vocabulary_)}")

# TF-IDF — tốt hơn BoW trong hầu hết trường hợp
tfidf_vectorizer = TfidfVectorizer(
    max_features=1000,
    ngram_range=(1, 2),  # unigrams và bigrams
    sublinear_tf=True    # log(tf) thay vì tf
)
X_tfidf = tfidf_vectorizer.fit_transform(processed_texts)
print(f"TF-IDF shape: {X_tfidf.shape}")

Bước 3: Xây Dựng Pipeline Phân Loại

from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
from sklearn.model_selection import cross_val_score
import numpy as np

# Dữ liệu thực tế cần nhiều hơn 6 mẫu
# Đây là ví dụ cấu trúc — với dữ liệu thực hãy dùng ít nhất 100 mẫu/lớp

# Pipeline với TF-IDF + Logistic Regression
lr_pipeline = Pipeline([
    ('tfidf', TfidfVectorizer(max_features=5000, ngram_range=(1,2), sublinear_tf=True)),
    ('clf',   LogisticRegression(C=1.0, max_iter=1000, random_state=42))
])

# Pipeline với TF-IDF + LinearSVC (thường tốt hơn LR cho text classification)
svc_pipeline = Pipeline([
    ('tfidf', TfidfVectorizer(max_features=5000, ngram_range=(1,2), sublinear_tf=True)),
    ('clf',   LinearSVC(C=1.0, max_iter=2000, random_state=42))
])

# Huấn luyện và đánh giá (dùng dữ liệu thực với đủ mẫu)
X = processed_texts
y = labels

# Cross-validation
for name, pipeline in [('LR', lr_pipeline), ('SVC', svc_pipeline)]:
    scores = cross_val_score(pipeline, X, y, cv=3, scoring='f1_macro')
    print(f"{name}: F1 = {scores.mean():.3f} (+/- {scores.std():.3f})")

Bước 4: Phân Tích Cảm Xúc với BERT/HuggingFace

Với dữ liệu đủ lớn và yêu cầu độ chính xác cao, các mô hình Transformer (BERT, PhoBERT cho tiếng Việt) vượt trội hơn hẳn:

from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch

# PhoBERT — mô hình BERT tiền huấn luyện cho tiếng Việt
model_name = "vinai/phobert-base"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(
    model_name, num_labels=2
)

def predict_sentiment(text, tokenizer, model):
    """Dự đoán cảm xúc với PhoBERT."""
    # Tiền xử lý và tokenize
    inputs = tokenizer(
        text,
        return_tensors='pt',
        truncation=True,
        max_length=256,
        padding=True
    )
    with torch.no_grad():
        outputs = model(**inputs)

    probabilities = torch.softmax(outputs.logits, dim=1)
    pred_class = torch.argmax(probabilities).item()
    confidence = probabilities[0][pred_class].item()

    labels = {0: 'Tiêu cực', 1: 'Tích cực'}
    return labels[pred_class], confidence

# Test
text = "Sản phẩm chất lượng cao, giao hàng đúng hẹn!"
sentiment, conf = predict_sentiment(text, tokenizer, model)
print(f"Cảm xúc: {sentiment} (Độ tin cậy: {conf:.2%})")

Bước 5: Đánh Giá Mô Hình Đúng Cách

from sklearn.metrics import (classification_report, confusion_matrix,
                              roc_auc_score, roc_curve)
import matplotlib.pyplot as plt

# Với tập test đầy đủ
# y_true = labels thực
# y_pred = predictions
# y_prob = xác suất dự đoán (cho ROC curve)

def evaluate_model(y_true, y_pred, y_prob=None, class_names=['Tiêu cực', 'Tích cực']):
    print("Classification Report:")
    print(classification_report(y_true, y_pred, target_names=class_names))

    # Confusion Matrix
    cm = confusion_matrix(y_true, y_pred)
    plt.figure(figsize=(6, 5))
    import seaborn as sns
    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
                xticklabels=class_names, yticklabels=class_names)
    plt.title('Confusion Matrix')
    plt.ylabel('Thực Tế')
    plt.xlabel('Dự Đoán')
    plt.tight_layout()
    plt.show()

    if y_prob is not None:
        auc = roc_auc_score(y_true, y_prob[:, 1])
        print(f"ROC-AUC Score: {auc:.4f}")

Ứng Dụng Thực Tế

Sau khi có mô hình, đây là một số ứng dụng thực tế bạn có thể xây dựng:

  • Phân loại email: Spam vs. không spam, phân loại theo phòng ban, đánh dấu ưu tiên.
  • Phân tích review: Tự động phân loại đánh giá khách hàng trên Shopee, Tiki, Lazada.
  • Phân loại tin tức: Phân loại bài báo theo chủ đề (thể thao, kinh tế, giải trí…).
  • Hệ thống tag nội dung: Tự động gắn thẻ chủ đề cho bài viết blog hoặc sản phẩm.

NLP là cầu nối giữa ngôn ngữ con người và máy tính. Mỗi khi bạn đọc một thư viện tốt, gõ vào một thanh tìm kiếm hay nhận được gợi ý phù hợp — đằng sau đó là NLP. Học tốt lĩnh vực này mở ra vô số cơ hội trong thế giới dữ liệu ngày nay.

Enjoyed this article?

Get weekly insights on Tech, AI & Beauty — straight to your inbox.

Để lại bình luận

Your email address will not be published. Required fields are marked *