Business Domain
“Phương trình” Retention: Các Mảnh Ghép Tạo Nên Sự Trung Thành Của User
Hãy xem Retention (Tỷ lệ giữ chân) là một kết quả (output) mà bạn hướng tới. Để đạt được kết quả này, sản phẩm phải tập trung cải thiện 3 yếu tố đầu vào (inputs) then chốt:
- Activation (Kích hoạt): Đây không chỉ là việc đăng ký tài khoản. Activation là hành trình ngắn đưa user từ “tò mò” đến khoảnh khắc “Aha!” – lần đầu tiên họ cảm nhận được giá trị thực sự của sản phẩm.
- Ví dụ: User tải App (tò mò), liên kết thành công ngân hàng (vượt qua rào cản ban đầu), và dùng voucher để thanh toán một ly cà phê miễn phí (khoảnh khắc “Aha!”). Họ đã được kích hoạt vì đã thấy App tiện lợi và có lợi.
- Engagement (Tương tác): Sau khoảnh khắc “Aha!”, user có quay lại không? Engagement đo lường mức độ và tần suất họ chủ động sử dụng các tính năng của App. Đây là thước đo cho thấy sản phẩm đang dần trở thành một thói quen.
- Ví dụ: Một user được coi là có tương tác tốt khi họ không chỉ dùng App để săn voucher, mà còn chủ động dùng để trả tiền điện, chuyển tiền cho bạn bè, mua vé xem phim.
- Resurrection (Hồi sinh): Không phải user nào cũng ở lại. Resurrection là nỗ lực để kéo những user đã “ngủ đông” (dormant) quay trở lại. Đây không phải là spam, mà là những lời mời gọi có giá trị, đúng thời điểm.
- Ví dụ: Gửi một voucher giảm giá tiền điện 50% cho một user đã không hoạt động 6 tháng, ngay trước kỳ đóng tiền điện của họ.
Bề Rộng & Chiều Sâu: Hai Mặt Của Sự Gắn Bó User
- Retention (Bề rộng – Breadth):
- Nó trả lời câu hỏi đơn giản: “Trong tháng qua, user có hoạt động hay không?”.
- Đây là một chỉ số nhị phân (Có/Không).
- Engagement (Chiều sâu – Depth):
- Nó trả lời câu hỏi sâu hơn: “Nếu họ được giữ chân, họ đã tích cực tương tác với sản phẩm như thế nào?”.
- Chỉ số này đo lường cường độ tương tác (số lần giao dịch, số tính năng sử dụng, giá trị giao dịch).
- Mối quan hệ cốt lõi:
- Một người dùng được giữ chân (retained) chưa chắc đã tương tác sâu (highly engaged) (ví dụ: 1 tháng chỉ mở app 1 lần).
- Nhưng một người dùng tương tác sâu gần như chắc chắn sẽ được giữ chân.
- Do đó, cải thiện Engagement là đòn bẩy mạnh mẽ nhất để tăng trưởng Retention bền vững.
Câu Chuyện Của Tèo Đầu To, Tý Đít Lép & Tủn Bụng Bự
Tèo Đầu To:
- Hành trình:
- Tèo, một người yêu công nghệ, nghe bạn bè giới thiệu và quyết định thử App.
- Tèo không chỉ tải app mà còn hoàn thành ngay bước liên kết ngân hàng (một rào cản lớn) vì tò mò về gói quà.
- Ngay chiều hôm đó, Tèo dùng App quét mã QR trả tiền cà phê, và voucher 50.000đ được tự động áp dụng. Giao dịch hoàn tất trong 3 giây.
- Phân tích dưới lăng kính Growth:
- Activation: Khoảnh khắc “Aha!” của Tèo rất rõ ràng: thanh toán không tiền mặt vừa nhanh, vừa có lợi. App đã thành công đưa Tèo qua luồng kích hoạt một cách trơn tru, biến sự tò mò thành trải nghiệm giá trị ngay lập tức.
- Engagement: App đã xuất sắc trong việc bủa vây Tèo bằng cả 3 vòng lặp thói quen:
- Vòng lặp tự nhiên (Organic): Nhu cầu trả tiền điện, nước, mua vé xem phim (triggers) đều được Tèo giải quyết bằng App (action) vì nó nhanh và tiện (reward).
- Vòng lặp được tạo ra (Manufactured): Thông báo đẩy “Hoàn tiền 50% vé xem phim Lật Mặt 7” (trigger) đã thúc đẩy Tèo thực hiện một hành động mà có thể anh không định làm, củng cố thêm sự gắn bó.
- Vòng lặp môi trường (Environment): Khi mua hàng trên Tiki, nút “Thanh toán bằng App” xuất hiện ngay đúng lúc Tèo cần (trigger), khiến việc chọn App để thanh toán trở thành một lựa chọn không cần suy nghĩ.
- Kết quả (Retention & Engagement): Tèo không chỉ đạt Bề rộng (Retention) vì anh có hoạt động, mà còn đạt Chiều sâu (Engagement) vượt trội với 25 giao dịch đa dạng.
- Bài học từ Tèo:
- Hành trình của Tèo cho thấy một kịch bản lý tưởng: luồng kích hoạt mượt mà, theo sau là sự kết hợp thông minh của các vòng lặp thói quen để biến user mới thành một user trung thành, có giá trị cao.
Tý Đít Lép:
- Hành trình:
- Thấy Tèo được lợi, Tý cũng tải App.
- Tý hơi ngần ngại ở bước liên kết ngân hàng vì lo ngại bảo mật, nhưng cuối cùng cũng hoàn thành để lấy voucher.
- Tý dùng voucher mua thẻ cào điện thoại thành công. Tuy nhiên, sau đó, anh gần như không mở lại app. Các thông báo khuyến mãi anh nhận được không liên quan đến nhu cầu của anh.
- Phân tích dưới lăng kính Growth:
- Activation: Tý đã được kích hoạt vì anh đã trải qua khoảnh khắc “Aha!” (mua thẻ cào được giảm giá). App đã thành công ở bước này.
- Engagement:
- App đã không thể xây dựng được bất kỳ vòng lặp thói quen nào với Tý.
- Thói quen dùng tiền mặt của Tý quá lớn, và các thông báo đẩy không được cá nhân hóa đã khiến Tý cảm thấy bị làm phiền thay vì được giúp đỡ. Chúng không trở thành một “trigger” hiệu quả.
- Kết quả (Retention & Engagement): Tý trở thành một người dùng rời bỏ (churned user). Chiều sâu tương tác của anh bằng không.
- Bài học từ Tý:
- App đã tốn chi phí để thu hút Tý, kích hoạt anh thành công, nhưng lại thất bại trong việc giữ chân vì không nuôi dưỡng được sự tương tác sau khoảnh khắc “Aha!”.
- Đây là một sự lãng phí nguồn lực, cho thấy tầm quan trọng của việc xây dựng Engagement ngay sau Activation.
Tủn Bụng Bự:
- Hành trình:
- Tủn đã cài App từ rất lâu, chỉ để nhận tiền Tèo chuyển một lần duy nhất rồi quên bẵng đi.
- Tủn là một người dùng ngủ đông (dormant user).
- Bỗng một ngày, gần đến kỳ đóng tiền điện, anh nhận được email từ App: “Tủn ơi, App nhớ bạn! Tặng riêng bạn voucher 100.000đ thanh toán hóa đơn điện.”
- Phân tích dưới lăng kính Growth:
- Resurrection: Đây là một chiến dịch hồi sinh hoàn hảo. Sự thành công đến từ 3 yếu tố:
- Đúng thời điểm (ngay khi nhu cầu phát sinh)
- Giá trị cao (voucher đủ lớn để phá vỡ sự ì)
- Cá nhân hóa (nhắm đúng nhu cầu thiết thực).
- Tái kích hoạt (Re-activation): Khi Tủn dùng voucher để trả tiền điện, anh đã trải qua một khoảnh khắc “Aha!” lần thứ hai. Anh được tái kích hoạt.
- Kết quả (Retention & Engagement): Tủn đã được hồi sinh (resurrected) thành công, chuyển từ trạng thái “dormant” sang “active“.
- Resurrection: Đây là một chiến dịch hồi sinh hoàn hảo. Sự thành công đến từ 3 yếu tố:
- Bài học từ Tủn:
- Đừng bao giờ từ bỏ người dùng cũ.
- Một chiến dịch Resurrection thông minh, dựa trên dữ liệu có thể mang họ trở lại.
- Thử thách tiếp theo là làm sao để giữ chân Tủn, áp dụng các bài học từ Tèo để xây dựng các vòng lặp thói quen cho anh, tránh để anh “ngủ đông” trở lại.
Tóm lại, để tăng trưởng bền vững, bạn không thể chỉ nhìn vào một con số Retention chung chung. Bạn phải liên tục trả lời các câu hỏi: Làm sao để có nhiều Tèo hơn? Làm sao để có ít Tý hơn? Và làm sao để tìm lại và giữ chân những người như Tủn?
Challenge SQL
Chỉ số MAU (User hoạt động hàng tháng) vẫn đang ổn, nhưng nó đang che giấu một sự thật:
- Bạn đang đốt tiền để thu hút nhiều user như ‘Tý Đít Lép’ – những user được kích hoạt thành công rồi rời bỏ ngay sau đó.
- Trong khi đó, bạn không biết mình có bao nhiêu ‘Tèo Đầu To’ và làm thế nào để tạo ra thêm những người như họ.
- Tệ hơn, bạn đang bỏ quên cả một mỏ vàng là những ‘Tủn Bụng Bự’ có thể được hồi sinh với chi phí thấp.
Ban lãnh đạo không cần những con số chung chung, cái họ cần là lượng hóa được những nhóm user này.
Viết truy vấn SQL Server để phân loại mỗi user (user_id) vào một trong các nhóm sau, dựa trên các chỉ số hành vi:
Các chỉ số hành vi cần tính cho mỗi người dùng:
recency_days: Số ngày kể từ lần giao dịch cuối cùng.frequency: Tổng số lượng giao dịch đã thực hiện.service_variety: Số lượng dịch vụ khác nhau đã sử dụng.user_age_days: Số ngày kể từ ngày đăng ký.max_inactivity_period: Khoảng thời gian không hoạt động (tính bằng ngày) dài nhất giữa hai lần giao dịch.
Định nghĩa các phân khúc user:
- Power Users (Giống Tèo):
- Giao dịch lần cuối trong vòng 30 ngày (
recency_days <= 30). - Có ít nhất 20 giao dịch (
frequency >= 20). - Đã sử dụng ít nhất 4 dịch vụ khác nhau (
service_variety >= 4).
- Giao dịch lần cuối trong vòng 30 ngày (
- Resurrected Users (Giống Tủn):
- Đã từng có một khoảng “ngủ đông” ít nhất 180 ngày (
max_inactivity_period >= 180). - Đã giao dịch trở lại trong vòng 30 ngày gần đây (
recency_days <= 30).
- Đã từng có một khoảng “ngủ đông” ít nhất 180 ngày (
- Churned Activated Users (Giống Tý):
- Đăng ký tài khoản chưa đầy 1 năm (
user_age_days < 365). - Chỉ có từ 1 đến 3 giao dịch (
frequency BETWEEN 1 AND 3). - Không có giao dịch nào trong hơn 90 ngày (
recency_days > 90).
- Đăng ký tài khoản chưa đầy 1 năm (
- New Active Users:
- Đăng ký tài khoản trong vòng 30 ngày (
user_age_days <= 30). - Đã có ít nhất 1 giao dịch (
frequency > 0).
- Đăng ký tài khoản trong vòng 30 ngày (
- At-Risk Users:
- Giao dịch lần cuối cách đây từ 91 đến 180 ngày (
recency_days BETWEEN 91 AND 180).
- Giao dịch lần cuối cách đây từ 91 đến 180 ngày (
- Casual Users:
- Không thuộc các nhóm trên nhưng có giao dịch trong vòng 90 ngày (
recency_days <= 90) và cófrequency > 0.
- Không thuộc các nhóm trên nhưng có giao dịch trong vòng 90 ngày (
- Dormant Users:
- Không có giao dịch nào trong hơn 180 ngày (
recency_days > 180).
- Không có giao dịch nào trong hơn 180 ngày (
- New Registered:
- Người dùng mới đăng ký nhưng chưa có bất kỳ giao dịch nào (
frequency = 0).
- Người dùng mới đăng ký nhưng chưa có bất kỳ giao dịch nào (
SQL Coding
DECLARE @today_date DATETIME = '2024-07-16';
WITH user_transaction_stats AS (
SELECT
u.user_id,
u.registration_date,
COUNT(t.transaction_id) AS frequency,
MIN(t.transaction_date) AS first_transaction_date,
MAX(t.transaction_date) AS last_transaction_date,
COUNT(DISTINCT t.service_id) AS service_variety
FROM users u
LEFT JOIN transactions t ON u.user_id = t.user_id
GROUP BY u.user_id, u.registration_date
),
user_inactivity_periods AS (
SELECT
user_id,
MAX(inactivity_days) AS max_inactivity_period
FROM (
SELECT
user_id,
DATEDIFF(day, LAG(transaction_date, 1, transaction_date) OVER (PARTITION BY user_id ORDER BY transaction_date), transaction_date) AS inactivity_days
FROM transactions
) AS inactivity_data
GROUP BY user_id
),
final_user_profile AS (
SELECT
s.user_id,
s.registration_date,
s.frequency,
s.service_variety,
DATEDIFF(day, s.last_transaction_date, @today_date) AS recency_days,
DATEDIFF(day, s.registration_date, @today_date) AS user_age_days,
DATEDIFF(day, s.registration_date, s.first_transaction_date) AS days_to_first_transaction,
ISNULL(i.max_inactivity_period, 0) AS max_inactivity_period
FROM user_transaction_stats s
LEFT JOIN user_inactivity_periods i ON s.user_id = i.user_id
)
SELECT
p.user_id,
CASE
WHEN p.recency_days <= 30 AND p.frequency >= 20 AND p.service_variety >= 4 THEN 'Power User'
WHEN p.max_inactivity_period >= 180 AND p.recency_days <= 30 THEN 'Resurrected User'
WHEN p.user_age_days < 365 AND p.frequency BETWEEN 1 AND 3 AND p.recency_days > 90 THEN 'Churned Activated User'
WHEN p.user_age_days <= 30 AND p.frequency > 0 THEN 'New Active User'
WHEN p.recency_days BETWEEN 91 AND 180 THEN 'At-Risk User'
WHEN p.recency_days <= 90 AND p.frequency > 0 THEN 'Casual User'
WHEN p.recency_days > 180 THEN 'Dormant User'
ELSE 'New Registered'
END AS user_segment
FROM final_user_profile p
ORDER BY p.user_id;
Tư Duy Code
Cách tiếp cận hiệu quả nhất cho các bài toán phân tích phức tạp là đi ngược từ kết quả cuối cùng.
- Đích đến: Phân loại mỗi
user_idvào một nhóm cụ thể. - Logic: Sử dụng một cấu trúc
CASE WHEN ... THEN ... ENDđể áp dụng các quy tắc phân loại. - Câu hỏi đặt ra: Để viết được các điều kiện
CASE WHEN, bạn cần những chỉ số (metrics) nào? - Các chỉ số cần thiết:
recency_days: Số ngày từ lần giao dịch cuối.frequency: Tổng số giao dịch.service_variety: Số lượng dịch vụ khác nhau đã dùng.user_age_days: “Tuổi” của tài khoản (tính từ ngày đăng ký).max_inactivity_period: Khoảng thời gian “ngủ đông” dài nhất.
- Vấn đề: Các chỉ số này không có sẵn trong cơ sở dữ liệu. Bạn phải tính toán chúng từ dữ liệu thô trong bảng
usersvàtransactions.
Lên kế hoạch tính toán từng chỉ số
recency_days: CầnMAX(transaction_date)của mỗi user.- Công thức:
DATEDIFF(day, MAX(transaction_date), @today_date)
- Công thức:
frequency: CầnCOUNT(transaction_id)của mỗi user.service_variety: CầnCOUNT(DISTINCT service_id)của mỗi user.user_age_days: Cầnregistration_datecủa mỗi user.- Công thức:
DATEDIFF(day, registration_date, @today_date)
- Công thức:
max_inactivity_period:- Logic: Đối với mỗi user, bạn cần so sánh ngày của mỗi giao dịch với ngày của giao dịch ngay trước đó.
- SQL: Window Function
LAG(). - Thực hiện:
- Sắp xếp các giao dịch của mỗi user theo ngày (
PARTITION BY user_id ORDER BY transaction_date). - Dùng
LAG(transaction_date, 1) OVER (...)để lấy ngày giao dịch trước đó. - Dùng
DATEDIFFđể tính khoảng cách (số ngày) giữa giao dịch hiện tại và giao dịch trước đó. - Cuối cùng, dùng
MAX()trên tất cả các khoảng cách đã tính để tìm ra khoảng nghỉ dài nhất.
- Sắp xếp các giao dịch của mỗi user theo ngày (
Cấu trúc truy vấn SQL với Common Table Expressions (CTEs)
Sử dụng CTEs giúp chia nhỏ bài toán, làm cho code trở nên rõ ràng, dễ đọc và dễ gỡ lỗi.
- CTE 1:
user_transaction_stats- Nhiệm vụ: Tính các chỉ số cơ bản.
- SQL:
LEFT JOINusersvàtransactions, sau đóGROUP BY user_idđể tínhfrequency,service_variety,last_transaction_date.
- CTE 2:
user_inactivity_periods- Nhiệm vụ: Tính riêng chỉ số phức tạp
max_inactivity_period. - SQL: Sử dụng
LAG()trong một subquery hoặc CTE lồng nhau, sau đóGROUP BY user_idđể tìmMAX()của các khoảng nghỉ.
- Nhiệm vụ: Tính riêng chỉ số phức tạp
- CTE 3:
final_user_profile- Nhiệm vụ: Gộp tất cả các chỉ số lại với nhau.
- SQL:
JOINkết quả từ CTE 1 và CTE 2. Thực hiện các phép tínhDATEDIFFcuối cùng để rarecency_daysvàuser_age_days. Kết quả của CTE này là một bảng ảo hoàn chỉnh, mỗi dòng là một user với đầy đủ các chỉ số hành vi.
- Truy vấn cuối cùng:
- Nhiệm vụ: Áp dụng các quy tắc phân loại.
- SQL:
SELECTtừfinal_user_profilevà sử dụngCASE WHENđể gán nhãn phân khúc cho từng user.
Các Logic Ẩn và Điểm Cần Lưu Ý
- Tầm quan trọng của thứ tự
CASE WHENCASE WHENsẽ trả về kết quả của điều kiện ĐÚNG đầu tiên nó gặp. Do đó, thứ tự phải đi từ cụ thể nhất đến chung chung nhất.- Ví dụ: Một
Power Usercũng thỏa mãn điều kiện củaCasual User. NếuWHEN Casual User...được đặt trước, tất cảPower Usersẽ bị phân loại sai. - Thứ tự đúng:
- Nhóm đặc biệt & giá trị cao:
Power User,Resurrected User. - Nhóm có điều kiện đặc thù:
Churned Activated User,New Active User. - Nhóm theo trạng thái:
At-Risk User. - Nhóm cho active user:
Casual User(phải đứng sau các nhóm active cụ thể khác). - Nhóm không hoạt động:
Dormant User. - Nhóm mặc định:
New Registered(dùngELSEđể bắt các trường hợp còn lại, chủ yếu là user chưa có giao dịch).
- Nhóm đặc biệt & giá trị cao:
- Xử lý
NULLvà các trường hợp biênLEFT JOINvsINNER JOIN: Phải dùngLEFT JOINtừuserssangtransactions. Nếu không, tất cả những user chưa từng giao dịch (New Registered) sẽ bị loại khỏi kết quả.recency_dayscho user mới: Đối với user chưa có giao dịch,last_transaction_datelàNULL, dẫn đếnrecency_dayscũng làNULL. Điều này là đúng và giúp họ không bị phân loại nhầm vào các nhóm active. Cuối cùng, họ sẽ được xử lý bởi mệnh đềELSE.max_inactivity_periodcho user có 0-1 giao dịch:- Những user này sẽ không có “khoảng nghỉ” nào, dẫn đến
max_inactivity_periodlàNULLsau khi join. ISNULL(i.max_inactivity_period, 0)là một bước xử lý cực kỳ quan trọng. Nó gán giá trị0cho những trường hợp này, đảm bảo các phép so sánh logic sau đó (ví dụmax_inactivity_period >= 180) hoạt động chính xác.
- Những user này sẽ không có “khoảng nghỉ” nào, dẫn đến
- Hàm
LAG()LAG(transaction_date, 1, transaction_date) OVER (...)- Tham số thứ ba (
transaction_date) là giá trị mặc định. KhiLAGđược áp dụng cho giao dịch đầu tiên của một user, không có giao dịch nào “trước đó”. Thay vì trả vềNULL, nó sẽ trả về chính ngày giao dịch đó. DATEDIFFgiữa một ngày và chính nó là0. Điều này đảm bảo giao dịch đầu tiên không tạo ra một khoảng nghỉ, giúp logic tính toán luôn đúng.
Với mô hình Challenge-based Learning, bạn sẽ không chỉ học Business Domain, mà được giải các bài toán như trong doanh nghiệp, rèn tư duy phân tích và tạo Portfolio ngay trong các khóa học phân tích dữ liệu thực chiến. Inbox mình TẠI ĐÂY nếu bạn muốn đăng ký nhé!
