DEV Community

Hoàng Mạnh Khiêm
Hoàng Mạnh Khiêm

Posted on

THUẬT TOÁN PHÂN LOẠI NGƯỜI DÙNG

🎯 BÀI TOÁN

Có: 2,666 users, mỗi user vào các pages khác nhau (DealHot, Mission, Voucher,...)

Muốn: Chia users thành các nhóm có hành vi giống nhau

Ví dụ:

  • Nhóm 1: Thích săn deal (hay vào DealHot, Voucher)
  • Nhóm 2: Thích chơi mission (hay vào Mission, CreateMission)
  • Nhóm 3: Thích chat (hay vào ChatRoom, ReferralFriend)

I) K-MEANS - PHÂN NHÓM ĐƠN GIẢN NHẤT

💡 Ý tưởng chính

Giống như phân học sinh thành các nhóm học:

  1. Thầy giáo chọn 5 bạn làm nhóm trưởng (ngẫu nhiên)
  2. Các bạn còn lại tìm nhóm trưởng "giống mình nhất" để vào nhóm đó
  3. Nhóm trưởng mới = trung bình của các bạn trong nhóm
  4. Lặp lại bước 2-3 đến khi không ai đổi nhóm nữa

📖 Ví dụ thực tế

Từ data piggi_metrics.csv, lấy 7 users:

User 664402: Profile(3), UpdateProfile(1)                    → 4 lượt
User 581242: EmbeddedBrowser(1)                              → 1 lượt
User 665300: GetMissionPoint(1), Mission(2), Profile(1)      → 4 lượt
User 273471: Voucher(1), DealHot(1)                          → 2 lượt
User 184423: Profile(1), ReferralFriend(1)                   → 2 lượt
User 665302: Mission(1), CreateMission(1)                    → 2 lượt
User 121:    DealHot(1)                                      → 1 lượt
Enter fullscreen mode Exit fullscreen mode

Chuyển sang vector (đếm lượt vào từng page):

              Mission  DealHot  Profile  Voucher  Social
User 665300:    3        0        1        0        0
User 665302:    2        0        0        0        0
User 664402:    0        0        4        0        0
User 273471:    0        1        0        1        0
User 121:       0        1        0        0        0
User 184423:    0        0        1        0        1
User 581242:    0        0        0        0        0
Enter fullscreen mode Exit fullscreen mode

Chạy K-Means với k=3:

Bước 1: Chọn 3 nhóm trưởng ngẫu nhiên
  - Nhóm trưởng 1: User 665300 (Mission nhiều)
  - Nhóm trưởng 2: User 273471 (Deal)
  - Nhóm trưởng 3: User 664402 (Profile nhiều)

Bước 2: Các user tìm nhóm trưởng giống mình
  - User 665302 giống User 665300 → Nhóm 1 (Mission)
  - User 121 giống User 273471 → Nhóm 2 (Deal)
  - User 184423 giống User 664402 → Nhóm 3 (Profile/Social)
  - User 581242 (ít tương tác) → Nhóm 3

Bước 3: Tính nhóm trưởng mới
  - Nhóm 1: Mission trung bình cao
  - Nhóm 2: DealHot, Voucher trung bình cao
  - Nhóm 3: Profile, social features

Bước 4: Lặp lại cho đến khi hội tụ...
Enter fullscreen mode Exit fullscreen mode

Kết quả cuối:

  • Nhóm 1 (Mission Players): User 665300, 665302
  • Nhóm 2 (Deal Hunters): User 273471, 121
  • Nhóm 3 (Profile/Social Users): User 664402, 184423, 581242

✅ Ưu điểm

  • Nhanh - Chạy với 2,666 users trong vài giây
  • Đơn giản - Dễ hiểu, dễ code
  • Kết quả rõ ràng - Mỗi user chỉ thuộc 1 nhóm duy nhất

❌ Nhược điểm

  • Phải biết trước số nhóm (k) - Muốn chia thành mấy nhóm?
  • Nhạy với "outliers" - User lạ sẽ kéo nhóm lệch
  • Kết quả khác nhau mỗi lần chạy - Do chọn nhóm trưởng ngẫu nhiên

🎯 Khi nào dùng?

✅ Khi bạn biết muốn chia thành bao nhiêu nhóm (vd: 5 nhóm)
✅ Khi cần kết quả nhanh
✅ Khi users khá đồng đều (không có user quá lạ)


II) DBSCAN - TÌM NHÓM BẠN ĐÔNG ĐÚC

💡 Ý tưởng chính

Giống như tìm nhóm bạn trong lớp học:

  • Nếu bạn có ít nhất 5 người bạn thân (trong bán kính gần) → Bạn là "người nổi"
  • Bạn của "người nổi" → Cùng nhóm
  • Nếu bạn không có đủ 5 bạn thân và cũng không phải bạn của "người nổi" → Loner (outlier)

Không cần biết trước số nhóm!


📖 Ví dụ thực tế với data piggi_metrics.csv

Từ 21 dòng data đầu tiên, ta có:

User 665300: Mission(2), GetMissionPoint(1), Profile(1)      → Mission-focused
User 665302: Mission(1), CreateMission(1)                    → Mission-focused
User 200165: Mission(1)                                      → Mission-focused
  ↓ 3 users này "gần nhau" vì đều thích Mission

User 273471: Voucher(1), DealHot(1)                          → Deal-focused
User 121:    DealHot(1)                                      → Deal-focused
User 82777:  FlashsaleEmbedded(1)                            → Deal-focused
  ↓ 3 users này "gần nhau" vì đều thích săn deal

User 664402: Profile(3), UpdateProfile(1)                    → OUTLIER
  ↓ Chỉ vào Profile, không giống ai → Lẻ loi

User 581242: EmbeddedBrowser(1)                              → OUTLIER
User 294132: ChatRoom(1)                                     → OUTLIER
Enter fullscreen mode Exit fullscreen mode

DBSCAN tự động phát hiện:

Set parameters: eps=0.5, min_samples=3

Bước 1: Tìm vùng đông đúc
  - Vùng Mission: 3 users gần nhau → Nhóm 1 ✅
  - Vùng Deal: 3 users gần nhau → Nhóm 2 ✅

Bước 2: Đánh dấu outliers
  - User 664402: Không có đủ 3 neighbors → Outlier ⚠️
  - User 581242: Không thuộc nhóm nào → Outlier ⚠️
  - User 294132: ChatRoom độc lập → Outlier ⚠️
Enter fullscreen mode Exit fullscreen mode

Kết quả:

  • Nhóm 1 (Mission Players): User 665300, 665302, 200165
  • Nhóm 2 (Deal Hunters): User 273471, 121, 82777
  • Outliers: User 664402, 581242, 294132 (hành vi lạ, không thuộc nhóm chính)

✅ Ưu điểm

  • Không cần biết số nhóm trước - Tự động tìm
  • Tìm được outliers - User có hành vi lạ (VIP, bot, test accounts)
  • Nhóm hình dạng bất kỳ - Không bắt buộc hình tròn

❌ Nhược điểm

  • Khó chọn tham số - "Bao xa là gần?" "Bao nhiêu bạn là đủ đông?"
  • Chậm hơn K-Means - Với 2,666 users vẫn OK
  • Không tốt nếu mật độ khác nhau - Vùng đông ít khác biệt quá

🎯 Khi nào dùng?

✅ Khi KHÔNG biết có bao nhiêu nhóm
✅ Khi muốn tìm users lạ (VIP, bot)
✅ Khi các nhóm có kích thước/mật độ tương đương


III) GMM - MỖI NGƯỜI CÓ NHIỀU MẶT

💡 Ý tưởng chính

Khác với K-Means (mỗi user chỉ thuộc 1 nhóm), GMM cho phép:

User A có thể:

  • 60% là "Deal Lover"
  • 35% là "Mission Player"
  • 5% là "Social User"

Giống như một người có nhiều sở thích:

  • Bạn An: 70% thích bóng đá, 30% thích game
  • Bạn Bình: 50% thích bóng đá, 50% thích đọc sách

📖 Ví dụ thực tế với data piggi_metrics.csv

User 664402 từ data thực:

2026-05-20 15:56:44  →  Profile
2026-05-20 15:56:45  →  UpdateProfile
2026-05-20 15:56:46  →  Profile

Hành vi thực tế: Profile(3), UpdateProfile(1)
Enter fullscreen mode Exit fullscreen mode

Giả sử user này còn có thêm data:

- Profile: 15 lần
- Mission: 8 lần
- DealHot: 3 lần
Enter fullscreen mode Exit fullscreen mode

K-Means nói: User này thuộc nhóm "Profile User" (100%)

GMM nói: User này có nhiều mặt:

  • 60% Profile/Settings User (quan tâm cài đặt)
  • 35% Mission Player (thỉnh thoảng chơi mission)
  • 5% Deal Hunter (ít quan tâm deals)

Insight:
→ User này chủ yếu vào chỉnh sửa profile, NHƯNG cũng thích missions
Recommend: Personalization features + Mission notifications
→ Không nên spam Deal notifications vì chỉ 5% quan tâm


✅ Ưu điểm

  • Linh hoạt - User có thể thuộc nhiều nhóm
  • Realistic - Người thật thường có nhiều sở thích
  • Cung cấp xác suất - Biết độ tin cậy

❌ Nhược điểm

  • Phức tạp hơn - Khó hiểu hơn K-Means
  • Chậm hơn - Tính toán nhiều hơn
  • Vẫn cần biết số nhóm - Như K-Means

🎯 Khi nào dùng?

✅ Khi users có nhiều sở thích (không rõ ràng 1 nhóm)
✅ Khi cần recommendation đa dạng
✅ Khi muốn xác suất thay vì nhóm cứng


IV) PHÂN LOẠI THEO RFD - ĐÁNH GIÁ MỨC ĐỘ TƯƠNG TÁC

💡 Ý tưởng chính

Không phân loại theo "thích gì" mà phân loại theo "tương tác như thế nào":

3 tiêu chí:

  • R (Recency): Lần cuối vào app cách đây bao lâu?
  • F (Frequency): Vào app bao nhiêu lần?
  • D (Diversity): Vào bao nhiêu pages khác nhau?

📖 Ví dụ thực tế với data piggi_metrics.csv

Phân tích 3 users từ data thực:

User 665300:

Từ data: GetMissionPoint(1), Mission(2), Profile(1) trong ngày 2026-05-20

- Recency: 2026-05-20 (hôm nay = data mới nhất) → R = 5 ✅
- Frequency: 4 lượt trong data này → F = 3 (trung bình) ⚠️
- Diversity: 3 pages khác nhau (Mission, GetMissionPoint, Profile) → D = 3 ⚠️
→ Xếp hạng: 5-3-3 = "Potential Loyalist"
   (Active gần đây, nhưng chưa dùng nhiều features)
Enter fullscreen mode Exit fullscreen mode

User 664402:

Từ data: Profile(3), UpdateProfile(1) trong ngày 2026-05-20

- Recency: 2026-05-20 (hôm nay) → R = 5 ✅
- Frequency: 4 lượt → F = 3 ⚠️
- Diversity: 2 pages (Profile, UpdateProfile) → D = 2 ⚠️
→ Xếp hạng: 5-3-2 = "Loyal but Focused"
   (Active, nhưng chỉ quan tâm Profile features)
Enter fullscreen mode Exit fullscreen mode

User 581242:

Từ data: EmbeddedBrowser(1) trong ngày 2026-05-20

- Recency: 2026-05-20 (hôm nay) → R = 5 ✅
- Frequency: 1 lượt duy nhất → F = 1 ❌
- Diversity: 1 page → D = 1 ❌
→ Xếp hạng: 5-1-1 = "New User"
   (Mới vào lần đầu hoặc người dùng thụ động)
Enter fullscreen mode Exit fullscreen mode

Insight:

  • Tất cả đều active (R=5) vì data chỉ có 1 ngày (2026-05-20)
  • User 665300 explore nhiều nhất → Tiềm năng cao
  • User 664402 chỉ focus vào Profile → Cần khuyến khích dùng features khác
  • User 581242 mới vào → Cần onboarding

🎭 Các nhóm users

Nhóm Đặc điểm Action
Champions (5-5-5) Active, hay vào, explore nhiều VIP treatment, early access
Loyal Customers (5-5-2) Active, hay vào, nhưng chỉ thích vài tính năng Giữ chân, đừng thay đổi features họ thích
New Users (5-1-1) Mới vào lần đầu Onboarding, hướng dẫn
At Risk (2-4-3) Lâu không vào, nhưng từng active Gửi email "We miss you", tặng voucher
Lost (1-1-1) Đã bỏ app Win-back campaign, hoặc để yên

✅ Ưu điểm

  • Đơn giản - Chỉ 3 con số, dễ hiểu
  • Business-friendly - Marketing team hiểu ngay
  • Nhanh - Tính toán 2,666 users trong < 1 giây
  • Actionable - Biết ngay làm gì với từng nhóm

❌ Nhược điểm

  • Không nói user thích page nào - Chỉ nói mức độ tương tác
  • Quá đơn giản - Bỏ qua nhiều thông tin chi tiết
  • Cần data dài hạn - Recency cần ít nhất vài tuần data

🎯 Khi nào dùng?

✅ Khi cần phân loại nhanh để marketing
✅ Khi muốn kết quả dễ giải thích
KẾT HỢP với thuật toán khác để biết user thích gì


V) RULE-BASED - LẬP LUẬT THỦ CÔNG

💡 Ý tưởng chính

Bạn tự quy định luật, không dùng AI:

NẾU user vào DealHot > 30 lần
  → Gắn nhãn "Deal Lover"

NẾU user vào Mission > 20 lần
  → Gắn nhãn "Mission Player"

NẾU user không vào app > 30 ngày
  → Gắn nhãn "Churn Risk"
Enter fullscreen mode Exit fullscreen mode

Giống như thầy cô chấm điểm theo thang điểm cố định.


📖 Ví dụ thực tế với data piggi_metrics.csv

Áp dụng rules cho users thực:

Rule 1: Mission Player

IF count_Mission >= 2 THEN "mission_player"

User 665300: Mission(2) + GetMissionPoint(1) → Tổng 3 → ✅ "mission_player"
User 665302: Mission(1) + CreateMission(1) → Tổng 2 → ✅ "mission_player"
User 200165: Mission(1) → ❌ Không đủ
Enter fullscreen mode Exit fullscreen mode

Rule 2: Deal Hunter

IF (count_DealHot >= 1 OR count_Voucher >= 1) THEN "deal_hunter"

User 273471: DealHot(1) + Voucher(1) → ✅ "deal_hunter"
User 121: DealHot(1) → ✅ "deal_hunter"
User 82777: FlashsaleEmbedded(1) → ✅ "deal_hunter"
Enter fullscreen mode Exit fullscreen mode

Rule 3: Profile Focused

IF count_Profile >= 2 AND count_other_pages < 2 THEN "profile_focused"

User 664402: Profile(3) + UpdateProfile(1) → ✅ "profile_focused"
User 184423: Profile(1) → ❌ Không đủ
Enter fullscreen mode Exit fullscreen mode

Rule 4: Chuỗi hành vi (Sequence)

Từ data thực:
2026-05-20 15:56:44  User 664402  Profile
2026-05-20 15:56:45  User 664402  UpdateProfile
2026-05-20 15:56:46  User 664402  Profile

Rule: IF path = ["Profile" → "UpdateProfile" → "Profile"]
      THEN "edit_then_verify" (Sửa profile rồi check lại)
→ User 664402: ✅ Match pattern này
Enter fullscreen mode Exit fullscreen mode

Kết quả phân loại:

  • Mission Players: 665300, 665302
  • Deal Hunters: 273471, 121, 82777
  • Profile Focused: 664402
  • Uncategorized: 581242, 184423, 294132, 568861, 145593, 200165

🎯 Case Study

Công ty muốn tìm users "sắp mua hàng":

Rule: "Ready to Buy"
  IF (vào DealHot > 5 lần trong 3 ngày qua
      AND vào Voucher > 2 lần
      AND chưa Order trong 7 ngày qua)
  THEN gửi push notification "Flash Sale 50% - Chỉ 2 giờ!"
Enter fullscreen mode Exit fullscreen mode

→ Conversion rate tăng vì đúng timing!


✅ Ưu điểm

  • Dễ hiểu 100% - Ai cũng đọc được
  • Kiểm soát hoàn toàn - Bạn quyết định mọi thứ
  • Không cần training - Viết rule là xong
  • Giải thích được cho sếp - "Em làm theo logic này..."

❌ Nhược điểm

  • Không tự học - Không tìm ra patterns mới
  • Cần domain knowledge - Phải hiểu business sâu
  • Khó maintain - 100 rules sẽ rối loạn
  • Rules có thể conflict - Rule 1 nói A, Rule 2 nói B

🎯 Khi nào dùng?

✅ Khi business logic rõ ràng
✅ Khi cần giải thích cho non-tech team
✅ Khi bắt đầu (chưa có data để train ML)
KẾT HỢP với ML - ML tìm patterns, Rules finalize


VI) HIERARCHICAL - XÂY DỰNG CÂY GIA PHẢ

💡 Ý tưởng chính

Giống như vẽ cây gia phả:

                    Tất cả Users
                    /          \
            Active Users    Inactive Users
            /        \
    Deal Lovers   Mission Players
       /    \
   Heavy  Light
Enter fullscreen mode Exit fullscreen mode

Bắt đầu từ mỗi user = 1 nhóm riêng, merge dần các user giống nhau.


📖 Ví dụ thực tế với data piggi_metrics.csv

Lấy 6 users từ data thực:

User 665300: Mission(3), Profile(1)               → Mission-heavy
User 665302: Mission(1), CreateMission(1)         → Mission-heavy
User 273471: DealHot(1), Voucher(1)               → Deal-heavy
User 121:    DealHot(1)                           → Deal-heavy
User 664402: Profile(3), UpdateProfile(1)         → Profile-heavy
User 184423: Profile(1), ReferralFriend(1)        → Mixed
Enter fullscreen mode Exit fullscreen mode

Quá trình merge (từ dưới lên):

Ban đầu: [665300] [665302] [273471] [121] [664402] [184423]

Bước 1: 665300 và 665302 giống nhất (cùng Mission) → Merge
        [665300,665302] [273471] [121] [664402] [184423]

Bước 2: 273471 và 121 giống nhất (cùng Deal) → Merge
        [665300,665302] [273471,121] [664402] [184423]

Bước 3: 664402 và 184423 gần nhau (cùng Profile) → Merge
        [665300,665302] [273471,121] [664402,184423]

Bước 4: Mission group và Deal group merge
        [665300,665302,273471,121] [664402,184423]

Bước 5: Merge tất cả
        [665300,665302,273471,121,664402,184423]
Enter fullscreen mode Exit fullscreen mode

Dendrogram (cây phân cấp):

User:  665300  665302  273471  121  664402  184423
         |       |       |      |      |       |
         └───────┘       └──────┘      └───────┘
             │               │              │
             └───────────────┘              │
                     │                      │
                     └──────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Cắt cây ở độ cao khác nhau:

  • Cắt cao (2 nhóm):

    • [665300, 665302, 273471, 121] = Active Users
    • [664402, 184423] = Profile Users
  • Cắt trung bình (3 nhóm):

    • [665300, 665302] = Mission Players
    • [273471, 121] = Deal Hunters
    • [664402, 184423] = Profile Users
  • Cắt thấp (6 nhóm): Mỗi user riêng lẻ


📊 Dendrogram (Cây phân cấp)

User:  A    B    E    C    D
       |    |    |    |    |
       └────┘    |    └────┘
          │      │       │
          └──────┘       │
               │         │
               └─────────┘
Enter fullscreen mode Exit fullscreen mode

→ Nhìn vào cây, quyết định cắt ở đâu!


✅ Ưu điểm

  • Không cần biết số nhóm trước - Cắt ở đâu cũng được
  • Visualization đẹp - Dendrogram trực quan
  • Hiểu được hierarchy - Nhóm con, nhóm cha
  • Deterministic - Chạy lại kết quả giống nhau

❌ Nhược điểm

  • Chậm - Với > 10,000 users sẽ rất lâu
  • Không thể undo - Merge sai không rollback được
  • Memory lớn - Phải lưu toàn bộ relationships

🎯 Khi nào dùng?

✅ Khi muốn khám phá (exploratory analysis)
✅ Khi cần hiểu structure/hierarchy
✅ Khi data nhỏ-trung bình (< 5,000 users)
✅ Khi cần present cho leadership (dendrogram đẹp!)


VII) HDBSCAN - BẢN NÂNG CẤP CỦA DBSCAN

💡 Ý tưởng chính

DBSCAN nhưng thông minh hơn:

  • DBSCAN: "Bao xa là gần?" → 1 con số cố định
  • HDBSCAN: "Tự động điều chỉnh cho từng vùng"

Giống như:

  • DBSCAN: "Trong bán kính 5m có ≥ 5 người → nhóm bạn"
  • HDBSCAN: "Ở chỗ đông → 3m, ở chỗ vắng → 10m cũng OK"

📖 Ví dụ thực tế với data piggi_metrics.csv

Từ 21 dòng data, giả sử có thêm nhiều users tạo ra 2 vùng mật độ khác nhau:

Vùng đông đúc - Mission Players (10 users gần nhau):
  665300: Mission(3), Profile(1)
  665302: Mission(1), CreateMission(1)
  200165: Mission(1)
  ... + 7 users khác cũng thích Mission

Vùng thưa thớt - VIP/Diverse Users (3 users xa nhau):
  664402: Profile(3), UpdateProfile(1), DealHot(5), Mission(8), ChatRoom(2)
         → User đa dạng, vào nhiều thứ
  581242: EmbeddedBrowser(8), ChatRoom(5), Loyalty(3)
         → User đa dạng khác
  294132: ChatRoom(10), ReferralFriend(8), Mission(4)
         → User xã hội hóa
Enter fullscreen mode Exit fullscreen mode

DBSCAN với eps=0.5, min_samples=3:

✅ Tìm được vùng Mission (10 users đông đúc)
❌ Bỏ sót 3 VIP users (xa nhau, không đủ min_samples=3)
→ 3 VIP users bị gán là outliers (sai!)
Enter fullscreen mode Exit fullscreen mode

HDBSCAN tự động:

Bước 1: Phát hiện vùng Mission đông đúc
  → Tạo Cluster 1 với 10 users

Bước 2: Phát hiện 3 VIP users tuy xa nhau nhưng có pattern riêng
  → Tự điều chỉnh: "Ở vùng này, chỉ cần 2 users gần nhau cũng OK"
  → Tạo Cluster 2 với 3 VIP users

Bước 3: Các users lẻ loi thật sự (EmbeddedBrowser(1), ...) → Outliers
Enter fullscreen mode Exit fullscreen mode

Kết quả:

  • DBSCAN: 1 cluster (Mission) + 3 VIP bị nhầm outliers
  • HDBSCAN: 2 clusters (Mission + VIP) + outliers thật sự ✅

→ HDBSCAN thông minh hơn, tự thích nghi với mật độ khác nhau!


✅ Ưu điểm

  • Tự động hóa cao - Ít cần tune parameters
  • Tốt nhất cho density-based - State-of-the-art
  • Handle varied density - Mật độ khác nhau OK
  • Outlier scores - Cho điểm từ 0-1 (không chỉ yes/no)

❌ Nhược điểm

  • Phức tạp - Khó hiểu thuật toán
  • Cần thư viện riêng - Không có sẵn trong sklearn
  • Chậm hơn K-Means - Nhưng nhanh hơn DBSCAN

🎯 Khi nào dùng?

Thay thế DBSCAN - Better version
✅ Khi có nhóm đông/thưa khác nhau
✅ Khi muốn tự động hóa (ít tune)
Đề xuất cho production - Robust, chất lượng cao


📊 SO SÁNH BẰNG VÍ DỤ HẰNG NGÀY

Thuật toán Giống như... Khi nào dùng?
K-Means Chia lớp thành các tổ học Biết cần mấy nhóm, cần nhanh
DBSCAN Tìm nhóm bạn trong quán cafe đông người Tìm outliers, không biết số nhóm
GMM Phân loại người có nhiều sở thích User không rõ ràng 1 nhóm
RFD Xếp hạng khách hàng thân thiết Marketing, đơn giản, nhanh
Rule-Based Quy định của công ty Logic business rõ ràng
Hierarchical Vẽ cây gia phả Khám phá, visualization
HDBSCAN Tìm nhóm bạn thông minh (tự động) Production, chất lượng cao

Top comments (0)