Bài 10: Phân tích Review & Đánh giá Khách hàng
Mục tiêu bài học
🎯 Sau bài này, bạn sẽ có thể:
- Phân tích phân bố rating và phát hiện pattern đánh giá bất thường
- Đánh giá chất lượng sản phẩm dựa trên review score và volume
- Phân tích mối quan hệ giữa review, seller performance và customer behavior
- Xây dựng hệ thống cảnh báo chất lượng dựa trên review data
- Đưa ra actionable insights từ voice of customer
Thuật ngữ quan trọng
📖 Thuật ngữ Review Analytics
| Thuật ngữ | Giải thích | Ví dụ |
|---|---|---|
| Rating Distribution | Phân bố điểm đánh giá | 5⭐: 45%, 4⭐: 25%, 3⭐: 15%... |
| Review Rate | Tỷ lệ đơn hàng có review | 35% đơn hàng được đánh giá |
| Sentiment Score | Điểm cảm xúc tổng hợp | 4.3/5.0 trung bình |
| J-curve Distribution | Phân bố hình chữ J (nhiều 5⭐ và 1⭐) | Pattern phổ biến trong e-commerce |
| Review Velocity | Tốc độ nhận review theo thời gian | 500 reviews/tuần |
| Response Time | Thời gian từ mua đến review | Trung bình 7 ngày |
| Net Promoter Score (NPS) | Chỉ số đo lường sự hài lòng | NPS = %Promoter - %Detractor |
| Review Helpfulness | Mức độ hữu ích của review | Được vote helpful bởi users khác |
Kiểm tra thuật ngữ
Câu hỏi: J-curve Distribution trong review có nghĩa là gì? Tại sao đây là pattern phổ biến trong e-commerce?
Trả lời: J-curve Distribution là phân bố có nhiều rating cực (5⭐ và 1⭐), ít rating trung bình (2-3⭐), tạo hình chữ J khi vẽ biểu đồ. Pattern này phổ biến vì khách hàng có xu hướng chỉ viết review khi rất hài lòng hoặc rất không hài lòng — những người trung lập thường không đánh giá.
Tổng quan dữ liệu Review
📊 Bảng fact_reviews trong ShopVN
Bảng fact_reviews chứa 120,000+ reviews từ khách hàng, liên kết với đơn hàng, sản phẩm và seller.
Review Data Model
Review Rate — Tỷ lệ đánh giá
1-- Tỷ lệ đơn hàng có review2SELECT 3 COUNT(DISTINCT r.order_id) AS reviewed_orders,4 COUNT(DISTINCT o.order_id) AS total_delivered_orders,5 ROUND(6 COUNT(DISTINCT r.order_id) * 100.0 / 7 COUNT(DISTINCT o.order_id), 18 ) AS review_rate_pct9FROM fact_orders o10LEFT JOIN fact_reviews r ON o.order_id = r.order_id11WHERE o.order_status = 'delivered';E-commerce Việt Nam trung bình có review rate 25-40%. Tỷ lệ cao hơn thường nhờ chương trình khuyến khích review (xu/coin) hoặc reminder tự động.
Phân bố Rating & Pattern
📊 Rating Distribution Analysis
Rating Distribution Patterns
Phân bố tổng thể
1-- Phân bố rating tổng thể2SELECT 3 review_score,4 COUNT(*) AS review_count,5 ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 1) AS pct,6 REPEAT('█', COUNT(*) * 50 / MAX(COUNT(*)) OVER()) AS bar_chart7FROM fact_reviews8GROUP BY review_score9ORDER BY review_score DESC;| Rating | % điển hình | Ý nghĩa |
|---|---|---|
| ⭐⭐⭐⭐⭐ (5) | 40-50% | Rất hài lòng — Promoters |
| ⭐⭐⭐⭐ (4) | 20-25% | Hài lòng — Passive |
| ⭐⭐⭐ (3) | 10-15% | Trung bình — Passive |
| ⭐⭐ (2) | 5-8% | Không hài lòng — Detractor |
| ⭐ (1) | 8-12% | Rất tệ — Detractor |
Rating theo thời gian (Trend Analysis)
1-- Rating trend theo tháng2SELECT 3 DATE_TRUNC('month', review_date) AS review_month,4 COUNT(*) AS total_reviews,5 ROUND(AVG(review_score), 2) AS avg_rating,6 ROUND(7 COUNT(CASE WHEN review_score >= 4 THEN 1 END) * 100.0 / 8 COUNT(*), 19 ) AS satisfaction_rate,10 ROUND(11 COUNT(CASE WHEN review_score <= 2 THEN 1 END) * 100.0 / 12 COUNT(*), 113 ) AS complaint_rate14FROM fact_reviews15GROUP BY DATE_TRUNC('month', review_date)16ORDER BY review_month;Thời gian phản hồi — Review Response Time
1-- Thời gian từ delivery đến review2SELECT 3 CASE 4 WHEN r.review_date - o.delivered_date <= 1 THEN '0-1 ngày'5 WHEN r.review_date - o.delivered_date <= 3 THEN '2-3 ngày'6 WHEN r.review_date - o.delivered_date <= 7 THEN '4-7 ngày'7 WHEN r.review_date - o.delivered_date <= 14 THEN '8-14 ngày'8 ELSE '15+ ngày'9 END AS response_time,10 COUNT(*) AS review_count,11 ROUND(AVG(review_score), 2) AS avg_rating12FROM fact_reviews r13JOIN fact_orders o ON r.order_id = o.order_id14WHERE o.delivered_date IS NOT NULL15GROUP BY 16 CASE 17 WHEN r.review_date - o.delivered_date <= 1 THEN '0-1 ngày'18 WHEN r.review_date - o.delivered_date <= 3 THEN '2-3 ngày'19 WHEN r.review_date - o.delivered_date <= 7 THEN '4-7 ngày'20 WHEN r.review_date - o.delivered_date <= 14 THEN '8-14 ngày'21 ELSE '15+ ngày'22 END23ORDER BY avg_rating DESC;Review sớm (0-1 ngày) thường có rating cao hơn — khách hàng hài lòng review nhanh. Review muộn (15+ ngày) thường có rating thấp — khách hàng cần thời gian "tích tụ" sự không hài lòng trước khi phàn nàn.
Phân tích Review theo Sản phẩm
🏷️ Product Quality từ Review Data
Rating theo Category
1-- Rating trung bình theo category2SELECT 3 p.category,4 COUNT(r.review_id) AS total_reviews,5 ROUND(AVG(r.review_score), 2) AS avg_rating,6 ROUND(7 COUNT(CASE WHEN r.review_score = 5 THEN 1 END) * 100.0 / 8 COUNT(*), 19 ) AS five_star_pct,10 ROUND(11 COUNT(CASE WHEN r.review_score <= 2 THEN 1 END) * 100.0 / 12 COUNT(*), 113 ) AS low_rating_pct,14 ROUND(AVG(r.delivery_rating), 2) AS avg_delivery_rating15FROM fact_reviews r16JOIN dim_product p ON r.product_id = p.product_id17GROUP BY p.category18ORDER BY avg_rating DESC;Sản phẩm có vấn đề (Low Rating Alert)
1-- Sản phẩm có rating thấp và volume review cao (cần xử lý)2SELECT 3 p.product_id,4 p.product_name,5 p.category,6 p.sub_category,7 COUNT(r.review_id) AS review_count,8 ROUND(AVG(r.review_score), 2) AS avg_rating,9 ROUND(10 COUNT(CASE WHEN r.review_score <= 2 THEN 1 END) * 100.0 / 11 COUNT(*), 112 ) AS complaint_pct13FROM fact_reviews r14JOIN dim_product p ON r.product_id = p.product_id15GROUP BY p.product_id, p.product_name, p.category, p.sub_category16HAVING COUNT(r.review_id) >= 10 -- Đủ sample size17 AND AVG(r.review_score) < 3.5 -- Rating thấp18ORDER BY review_count DESC19LIMIT 20;Product Rating vs Sales Performance
1-- Mối quan hệ giữa rating và doanh số2WITH product_metrics AS (3 SELECT 4 p.product_id,5 p.category,6 ROUND(AVG(r.review_score), 1) AS avg_rating,7 COUNT(DISTINCT r.order_id) AS review_orders,8 SUM(oi.price) AS total_revenue9 FROM dim_product p10 JOIN fact_reviews r ON p.product_id = r.product_id11 JOIN fact_order_items oi ON r.order_id = oi.order_id 12 AND r.product_id = oi.product_id13 GROUP BY p.product_id, p.category14)15SELECT 16 CASE 17 WHEN avg_rating >= 4.5 THEN '⭐ 4.5-5.0 (Excellent)'18 WHEN avg_rating >= 4.0 THEN '⭐ 4.0-4.4 (Good)'19 WHEN avg_rating >= 3.5 THEN '⭐ 3.5-3.9 (Average)'20 WHEN avg_rating >= 3.0 THEN '⭐ 3.0-3.4 (Below Avg)'21 ELSE '⭐ < 3.0 (Poor)'22 END AS rating_tier,23 COUNT(*) AS product_count,24 ROUND(AVG(total_revenue), 0) AS avg_revenue_per_product,25 ROUND(SUM(total_revenue), 0) AS total_revenue26FROM product_metrics27GROUP BY 28 CASE 29 WHEN avg_rating >= 4.5 THEN '⭐ 4.5-5.0 (Excellent)'30 WHEN avg_rating >= 4.0 THEN '⭐ 4.0-4.4 (Good)'31 WHEN avg_rating >= 3.5 THEN '⭐ 3.5-3.9 (Average)'32 WHEN avg_rating >= 3.0 THEN '⭐ 3.0-3.4 (Below Avg)'33 ELSE '⭐ < 3.0 (Poor)'34 END35ORDER BY rating_tier DESC;Đừng kết luận ngay rằng "rating cao = bán nhiều". Có thể sản phẩm bán ít nên chỉ khách trung thành mua và đánh giá cao. Luôn xét cùng review volume và total orders.
Phân tích Review theo Seller
🏪 Seller Quality Assessment từ Reviews
Seller Rating Scorecard
1-- Seller review scorecard2SELECT 3 s.seller_id,4 s.seller_name,5 s.seller_type,6 COUNT(r.review_id) AS total_reviews,7 ROUND(AVG(r.review_score), 2) AS avg_product_rating,8 ROUND(AVG(r.delivery_rating), 2) AS avg_delivery_rating,9 ROUND(10 COUNT(CASE WHEN r.review_score = 5 THEN 1 END) * 100.0 / 11 COUNT(*), 112 ) AS five_star_pct,13 ROUND(14 COUNT(CASE WHEN r.review_score <= 2 THEN 1 END) * 100.0 / 15 COUNT(*), 116 ) AS complaint_pct,17 -- NPS proxy18 ROUND(19 (COUNT(CASE WHEN r.review_score >= 4 THEN 1 END) - 20 COUNT(CASE WHEN r.review_score <= 2 THEN 1 END)) * 100.0 / 21 COUNT(*), 122 ) AS nps_proxy23FROM fact_reviews r24JOIN dim_seller s ON r.seller_id = s.seller_id25GROUP BY s.seller_id, s.seller_name, s.seller_type26HAVING COUNT(r.review_id) >= 2027ORDER BY avg_product_rating DESC;Rating Gap: Product vs Delivery
1-- So sánh product rating vs delivery rating theo seller2WITH seller_ratings AS (3 SELECT 4 s.seller_id,5 s.seller_name,6 s.seller_type,7 ROUND(AVG(r.review_score), 2) AS product_rating,8 ROUND(AVG(r.delivery_rating), 2) AS delivery_rating,9 COUNT(*) AS review_count10 FROM fact_reviews r11 JOIN dim_seller s ON r.seller_id = s.seller_id12 GROUP BY s.seller_id, s.seller_name, s.seller_type13 HAVING COUNT(*) >= 2014)15SELECT 16 seller_name,17 seller_type,18 product_rating,19 delivery_rating,20 ROUND(product_rating - delivery_rating, 2) AS rating_gap,21 CASE 22 WHEN product_rating - delivery_rating > 0.5 23 THEN '⚠️ Delivery kém hơn Product'24 WHEN delivery_rating - product_rating > 0.5 25 THEN '✅ Delivery tốt hơn Product'26 ELSE '↔️ Tương đương'27 END AS gap_assessment,28 review_count29FROM seller_ratings30ORDER BY ABS(product_rating - delivery_rating) DESC31LIMIT 15;Gap dương lớn (product > delivery): Sản phẩm tốt nhưng giao hàng yếu — cần cải thiện logistics.
Gap âm lớn (delivery > product): Giao nhanh nhưng sản phẩm kém — cần kiểm soát chất lượng nguồn hàng.
Seller Rating Trend (Cải thiện hay Suy giảm?)
1-- Rating trend theo quý cho từng seller type2SELECT 3 s.seller_type,4 DATE_TRUNC('quarter', r.review_date) AS review_quarter,5 COUNT(r.review_id) AS review_count,6 ROUND(AVG(r.review_score), 2) AS avg_rating,7 ROUND(AVG(r.delivery_rating), 2) AS avg_delivery_rating8FROM fact_reviews r9JOIN dim_seller s ON r.seller_id = s.seller_id10GROUP BY s.seller_type, DATE_TRUNC('quarter', r.review_date)11ORDER BY s.seller_type, review_quarter;Hệ thống cảnh báo chất lượng
🚨 Quality Alert System
Review-based Alert System
Cảnh báo sản phẩm rating giảm đột ngột
1-- Phát hiện sản phẩm có rating giảm mạnh so với tháng trước2WITH monthly_rating AS (3 SELECT 4 r.product_id,5 p.product_name,6 p.category,7 DATE_TRUNC('month', r.review_date) AS month,8 AVG(r.review_score) AS avg_rating,9 COUNT(*) AS review_count10 FROM fact_reviews r11 JOIN dim_product p ON r.product_id = p.product_id12 GROUP BY r.product_id, p.product_name, p.category, 13 DATE_TRUNC('month', r.review_date)14 HAVING COUNT(*) >= 5 -- Đủ sample15),16rating_change AS (17 SELECT 18 *,19 LAG(avg_rating) OVER(20 PARTITION BY product_id ORDER BY month21 ) AS prev_month_rating,22 LAG(review_count) OVER(23 PARTITION BY product_id ORDER BY month24 ) AS prev_month_reviews25 FROM monthly_rating26)27SELECT 28 product_name,29 category,30 month,31 ROUND(prev_month_rating, 2) AS prev_rating,32 ROUND(avg_rating, 2) AS current_rating,33 ROUND(avg_rating - prev_month_rating, 2) AS rating_change,34 review_count,35 CASE 36 WHEN avg_rating - prev_month_rating <= -1.0 THEN '🔴 CRITICAL DROP'37 WHEN avg_rating - prev_month_rating <= -0.5 THEN '🟡 WARNING'38 ELSE '🟢 NORMAL'39 END AS alert_level40FROM rating_change41WHERE prev_month_rating IS NOT NULL42AND avg_rating - prev_month_rating <= -0.543ORDER BY rating_change ASC44LIMIT 20;Cảnh báo seller chất lượng kém
1-- Sellers cần intervention2SELECT 3 s.seller_id,4 s.seller_name,5 s.seller_type,6 COUNT(r.review_id) AS total_reviews,7 ROUND(AVG(r.review_score), 2) AS avg_rating,8 ROUND(9 COUNT(CASE WHEN r.review_score <= 2 THEN 1 END) * 100.0 / 10 COUNT(*), 111 ) AS complaint_rate,12 CASE 13 WHEN AVG(r.review_score) < 3.0 AND COUNT(*) >= 50 14 THEN '🔴 SUSPEND REVIEW'15 WHEN AVG(r.review_score) < 3.5 AND COUNT(*) >= 30 16 THEN '🟡 WARNING LETTER'17 WHEN COUNT(CASE WHEN r.review_score <= 2 THEN 1 END) * 100.0 / 18 COUNT(*) > 30 19 THEN '🟠 HIGH COMPLAINT'20 ELSE '🟢 OK'21 END AS action_required22FROM fact_reviews r23JOIN dim_seller s ON r.seller_id = s.seller_id24GROUP BY s.seller_id, s.seller_name, s.seller_type25HAVING AVG(r.review_score) < 3.5 26 OR (COUNT(CASE WHEN r.review_score <= 2 THEN 1 END) * 100.0 / COUNT(*) > 30)27ORDER BY avg_rating ASC;Customer Satisfaction Insights
💡 Từ Review đến Actionable Insights
Satisfaction theo phân khúc khách hàng
1-- Review behavior theo customer segment (kết hợp RFM)2WITH customer_rfm AS (3 SELECT 4 customer_id,5 NTILE(4) OVER(ORDER BY MAX(order_date) DESC) AS recency_q,6 NTILE(4) OVER(ORDER BY COUNT(DISTINCT order_id)) AS frequency_q,7 NTILE(4) OVER(ORDER BY SUM(total_amount)) AS monetary_q8 FROM fact_orders9 WHERE order_status = 'delivered'10 GROUP BY customer_id11),12customer_segment AS (13 SELECT 14 customer_id,15 CASE 16 WHEN recency_q <= 2 AND frequency_q >= 3 AND monetary_q >= 3 17 THEN 'Champions'18 WHEN recency_q <= 2 AND frequency_q >= 2 19 THEN 'Loyal'20 WHEN recency_q <= 2 AND frequency_q = 1 21 THEN 'New Customers'22 WHEN recency_q >= 3 AND frequency_q >= 3 23 THEN 'At Risk'24 ELSE 'Others'25 END AS segment26 FROM customer_rfm27)28SELECT 29 cs.segment,30 COUNT(r.review_id) AS total_reviews,31 ROUND(AVG(r.review_score), 2) AS avg_rating,32 ROUND(AVG(r.delivery_rating), 2) AS avg_delivery_rating,33 ROUND(34 COUNT(CASE WHEN r.review_score >= 4 THEN 1 END) * 100.0 / 35 COUNT(*), 136 ) AS satisfaction_rate37FROM fact_reviews r38JOIN customer_segment cs ON r.customer_id = cs.customer_id39GROUP BY cs.segment40ORDER BY avg_rating DESC;First Purchase vs Repeat Purchase Review
1-- So sánh rating giữa đơn đầu tiên và đơn lặp lại2WITH customer_orders AS (3 SELECT 4 o.customer_id,5 o.order_id,6 ROW_NUMBER() OVER(7 PARTITION BY o.customer_id ORDER BY o.order_date8 ) AS order_sequence9 FROM fact_orders o10 WHERE o.order_status = 'delivered'11)12SELECT 13 CASE 14 WHEN co.order_sequence = 1 THEN 'First Purchase'15 WHEN co.order_sequence = 2 THEN '2nd Purchase'16 WHEN co.order_sequence = 3 THEN '3rd Purchase'17 WHEN co.order_sequence <= 5 THEN '4th-5th Purchase'18 ELSE '6+ Purchases'19 END AS purchase_order,20 COUNT(r.review_id) AS review_count,21 ROUND(AVG(r.review_score), 2) AS avg_rating,22 ROUND(AVG(r.delivery_rating), 2) AS avg_delivery_rating23FROM fact_reviews r24JOIN customer_orders co ON r.order_id = co.order_id25GROUP BY 26 CASE 27 WHEN co.order_sequence = 1 THEN 'First Purchase'28 WHEN co.order_sequence = 2 THEN '2nd Purchase'29 WHEN co.order_sequence = 3 THEN '3rd Purchase'30 WHEN co.order_sequence <= 5 THEN '4th-5th Purchase'31 ELSE '6+ Purchases'32 END33ORDER BY MIN(co.order_sequence);Thông thường, first purchase có rating trung bình hoặc thấp hơn (kỳ vọng chưa được calibrate), trong khi repeat customers có rating cao hơn (đã biết chất lượng, chỉ mua khi hài lòng). Nếu pattern ngược lại → có vấn đề về consistency.
Tổng kết & Bài tập
📝 Tóm tắt bài học
Những điểm chính:
- Rating Distribution: Hiểu J-curve pattern, theo dõi trend theo thời gian
- Product Quality: Phát hiện sản phẩm có vấn đề qua rating thấp + volume cao
- Seller Assessment: Đánh giá seller qua product rating, delivery rating, và gap analysis
- Alert System: Xây dựng cảnh báo tự động dựa trên rating thresholds và trend
- Customer Insights: Kết hợp review data với RFM, purchase sequence để hiểu behavior
💡 Self-check Questions:
- Rating trung bình 4.5 có luôn nghĩa là sản phẩm tốt không? (Hint: xét review count)
- Khi nào nên dùng median thay vì mean cho rating analysis?
- Delivery rating thấp hơn product rating cho thấy điều gì?
