Một nhóm xây bộ phân loại ticket có thể có nhiều câu hỏi từ cùng khách hàng. Chia ngẫu nhiên từng dòng dễ đưa những câu gần giống nhau vào cả tập huấn luyện và tập kiểm tra. Khi đó, điểm đánh giá chưa chắc phản ánh khả năng phục vụ khách hàng mới.
Bài này dành cho developer đang chuẩn bị dữ liệu thử nghiệm AI. Mục tiêu là kiểm tra ranh giới giữa các nhóm, chưa phải chọn mô hình hay tính accuracy. Các nguyên tắc được đối chiếu tài liệu scikit-learn ngày 27/10/2026; ví dụ chỉ dùng thư viện chuẩn Python, không cần cài scikit-learn.
1. Chọn đơn vị cần giữ độc lập
Hãy viết câu hỏi đánh giá trước khi chọn tỷ lệ chia. Nếu sản phẩm cần xử lý tổ chức chưa từng gặp, organization_id có thể là nhóm phù hợp. Nếu bạn muốn đánh giá trên tài liệu mới, các chunk thuộc cùng tài liệu nên được xem xét cùng nhau. Với nhiều bản sửa của một câu hỏi, ID câu hỏi gốc hữu ích hơn ID từng bản sửa.
Đây là quyết định theo dữ liệu của bạn. Không phải mọi dự án đều phải chia theo khách hàng: bài toán dự báo lần liên hệ tiếp theo của khách cũ có thể cần một ranh giới theo thời gian. Chọn nhầm nhóm vẫn có thể tạo một phép đo không phù hợp, dù chương trình không báo lỗi.
2. Thấy vấn đề bằng sáu dòng dữ liệu giả
Chạy đoạn sau bằng Python 3.9 trở lên. Mỗi khách hàng có hai ticket; nhãn và nội dung thật không cần xuất hiện trong ví dụ này.
rows = [
{"id": "t1", "customer": "a"},
{"id": "t2", "customer": "a"},
{"id": "t3", "customer": "b"},
{"id": "t4", "customer": "b"},
{"id": "t5", "customer": "c"},
{"id": "t6", "customer": "c"},
]
def groups(part):
return {row["customer"] for row in part}
bad_train, bad_test = rows[::2], rows[1::2]
print(sorted(groups(bad_train) & groups(bad_test)))
Kết quả là ['a', 'b', 'c']. Hai tập không có ticket trùng ID nhưng vẫn chứa cùng ba khách hàng. Ví dụ cố ý chia dòng chẵn/lẻ để vấn đề dễ thấy; nó không đo xác suất trùng nhóm của một thuật toán chia ngẫu nhiên.
3. Chia bằng một danh sách nhóm được giữ lại
Nối đoạn này sau ví dụ trên. Chúng ta chọn khách c làm nhóm kiểm tra cố định để minh họa, không chọn nhóm dựa trên điểm mô hình.
test_customers = {"c"}
train = [r for r in rows if r["customer"] not in test_customers]
test = [r for r in rows if r["customer"] in test_customers]
assert train and test
assert groups(train).isdisjoint(groups(test))
train_ids = {r["id"] for r in train}
test_ids = {r["id"] for r in test}
assert train_ids.isdisjoint(test_ids)
assert len(train_ids | test_ids) == len(rows)
print(len(train), len(test), sorted(groups(test)))
Kết quả mong đợi là 4 2 ['c']. Các assertion kiểm tra hai ranh giới khác nhau: nhóm không giao nhau và bản ghi không giao nhau. Kiểm tra tổng số ID còn giúp phát hiện trường hợp bỏ sót dữ liệu trong fixture này; với dữ liệu thật, kiểm tra ID đầu vào duy nhất trước khi chia.
Nếu dùng scikit-learn, GroupShuffleSplit nhận thông tin nhóm khi chia. Lưu ý test_size của công cụ này tính theo số nhóm, không phải số dòng. Một khách có nhiều ticket có thể khiến tỷ lệ dòng khác xa tỷ lệ nhóm bạn chọn. Đừng sửa tỷ lệ bằng cách chuyển riêng vài ticket của khách đó sang phía còn lại.
4. Lưu kế hoạch chia cùng phiên bản dữ liệu
Một lần đánh giá cần có khả năng tái lập. Bạn có thể lưu danh sách ID nhóm, ID bản ghi và mã phiên bản dataset vào một file nội bộ. Không ghi dữ liệu cá nhân vào repository công khai chỉ để tiện chạy lại.
Khi thêm dữ liệu mới, đối chiếu file kế hoạch thay vì tự chia lại mọi dòng rồi so điểm với lần cũ. Nếu đổi thành phần test, hãy coi đó là một phiên bản đánh giá khác. Cùng tên metric không làm hai tập kiểm tra khác nhau trở nên tương đương.
Kiểm tra thêm trước khi huấn luyện
- Tìm bản sao hoặc nội dung gần giống thuộc hai ID nhóm khác nhau.
- Đếm số nhóm, số dòng và phân bố nhãn ở mỗi tập; tập test có thể quá nhỏ hoặc thiếu một lớp.
- Chỉ học các bước tiền xử lý có tham số từ train, rồi áp dụng sang test.
- Dùng validation để điều chỉnh cách làm; giữ test dành cho đánh giá đã định trước.
Chia nhóm không tự xử lý rò rỉ từ tương lai, nhãn xuất hiện trong feature hoặc việc chỉnh prompt theo đáp án test. Các lỗi đó cần kiểm tra riêng.
Giới hạn của ví dụ
Fixture sáu dòng đã được chạy bằng Python trong lượt biên tập. Nó chứng minh các assertion và cách giữ nhóm, không chứng minh mô hình tốt hơn. Bài chưa huấn luyện mô hình, chạy splitter của scikit-learn hoặc đo thay đổi chất lượng. Hãy bắt đầu bằng một bộ dữ liệu nhỏ có thể kiểm tra tay, rồi mới mở rộng quy trình.


