{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"competition","sourceId":31254,"databundleVersionId":3103714},{"sourceType":"datasetVersion","sourceId":16428526,"datasetId":10530584,"databundleVersionId":17425910},{"sourceType":"datasetVersion","sourceId":15880486,"datasetId":9869115,"databundleVersionId":16833966},{"sourceType":"kernelVersion","sourceId":310187812}],"dockerImageVersionId":31286,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install implicit","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install implicit[cuda] --upgrade","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport gc\nimport pandas as pd\nimport numpy as np\nimport pyarrow.dataset as ds\nfrom tqdm import tqdm\n\n# Đường dẫn file candidate production của cậu\nPARQUET_FILE = \"/kaggle/input/datasets/dannywannafly/candidate/train_candidates.parquet\"\n\nprint(\"==============================================================================\")\nprint(\"PUMPING UP PRODUCTION INSIGHTS: KIỂM TOÁN QUY MÔ TOÀN CỤC (1.37 TRIỆU USERS)\")\nprint(\"==============================================================================\\n\")\n\nif not os.path.exists(PARQUET_FILE):\n    print(f\"[LỖI] Không tìm thấy file tại đường dẫn: {PARQUET_FILE}\")\nelse:\n    print(\"[*] Đang thiết lập cấu trúc Stream dữ liệu qua PyArrow Dataset...\")\n    # Tải dataset dưới dạng lazy evaluation (chỉ đọc metadata, chưa nạp vào RAM)\n    dataset = ds.dataset(PARQUET_FILE, format=\"parquet\")\n    \n    # Chỉ bóc tách các trường thông tin phục vụ phân tích phễu để tối ưu hóa bộ nhớ\n    required_columns = [\n        \"customer_id\", \"candidate_rank\", \"candidate_score\", \n        \"is_als\", \"is_bpr\", \"is_attr\", \"is_segment\"\n    ]\n    \n    # Khởi tạo các biến tích lũy toàn cục\n    total_candidates_in_top300 = 0\n    non_heuristic_hits_top300 = 0\n    \n    # Tập hợp lưu trữ ID khách hàng bằng Set để tính chính xác số user duy nhất\n    all_unique_users = set()\n    \n    # Bộ đếm độc lập phân bổ cho từng tầng phễu trong Top 300 mặt tiền\n    funnel_counts = {\n        \"Heuristics (Gốc)\": 0,\n        \"ALS_TimeDecay\": 0,\n        \"BPR\": 0,\n        \"Attribute\": 0,\n        \"MicroSegment\": 0,\n        \"Popular (Vét đáy)\": 0\n    }\n    \n    # Tạo Scanner với batch_size lớn (10 triệu dòng một lần quét) để tăng tốc độ I/O\n    scanner = dataset.scanner(columns=required_columns, batch_size=10_000_000)\n    \n    print(\"[*] Tiến trình quét luồng dữ liệu lớn bắt đầu...\")\n    for batch in tqdm(scanner.to_batches(), desc=\"Đang xử lý các khối dữ liệu khổng lồ\"):\n        # Chuyển đổi khối dữ liệu nhỏ sang Pandas để xử lý vector nhanh\n        df_chunk = batch.to_pandas()\n        \n        # 🚀 BƯỚC KHÓA CHỐT: Lọc lấy các ứng viên thực tế nằm trong khung TOP 300 mặt tiền\n        df_top300 = df_chunk[df_chunk[\"candidate_rank\"] <= 300].copy()\n        \n        # Giải phóng chunk gốc ngay lập tức để tiết kiệm không gian RAM\n        del df_chunk\n        \n        if df_top300.empty:\n            continue\n            \n        # Cập nhật tập hợp khách hàng xuất hiện trong lô này\n        all_unique_users.update(df_top300[\"customer_id\"].unique())\n        total_candidates_in_top300 += len(df_top300)\n        \n        # Trích xuất các mảng Boolean nhằm tối ưu hóa tốc độ đếm tính toán\n        is_als = df_top300[\"is_als\"].values == 1\n        is_bpr = df_top300[\"is_bpr\"].values == 1\n        is_attr = df_top300[\"is_attr\"].values == 1\n        is_seg = df_top300[\"is_segment\"].values == 1\n        \n        # Định nghĩa item thuộc phễu Heuristics khi có điểm thô tích lũy > 0\n        is_heur = df_top300[\"candidate_score\"].values > 0 \n        \n        # Định nghĩa item thuần Popular (Vét đáy): Không có vết tương tác và không thuộc phễu AI nào\n        is_pop = (~is_heur) & (~is_als) & (~is_bpr) & (~is_attr) & (~is_seg)\n        \n        # Tính tổng số sản phẩm KHÔNG do phễu Heuristics vớt được (Năng lực thực sự của AI)\n        non_heur_mask = ~is_heur\n        non_heuristic_hits_top300 += non_heur_mask.sum()\n        \n        # Cộng dồn số liệu trực tiếp bằng phép tính numpy sum tăng tốc\n        funnel_counts[\"Heuristics (Gốc)\"] += is_heur.sum()\n        funnel_counts[\"ALS_TimeDecay\"] += is_als.sum()\n        funnel_counts[\"BPR\"] += is_bpr.sum()\n        funnel_counts[\"Attribute\"] += is_attr.sum()\n        funnel_counts[\"MicroSegment\"] += is_seg.sum()\n        funnel_counts[\"Popular (Vét đáy)\"] += is_pop.sum()\n        \n        # Triệt tiêu các biến trung gian và gọi Garbage Collector dọn rác RAM chủ động\n        del df_top300, is_als, is_bpr, is_attr, is_seg, is_heur, is_pop; gc.collect()\n\n    # Tính toán tổng số lượng khách hàng thực tế quét được\n    total_users_analyzed = len(all_unique_users)\n    del all_unique_users; gc.collect()\n\n    # ============================================================================\n    # IN KẾT QUẢ ĐÁNH GIÁ SỐ LIỆU TOÀN CỤC TRÊN 1.37 TRIỆU USERS\n    # ============================================================================\n    print(\"\\n\" + \"=\"*85)\n    print(\"BÁO CÁO THỐNG KÊ TOÀN CỤC: NĂNG LỰC ĐÁNH CHIẾM MẶT TIỀN CỦA KHỐI THUẬT TOÁN AI\")\n    print(\"=\"*85)\n    print(f\"[*] Tổng số lượng Người dùng thực tế được quét: {total_users_analyzed:,} users\")\n    print(f\"[*] Tổng sản phẩm nằm trong vùng cắt chiến lược Top 300: {total_candidates_in_top300:,} dòng\")\n    \n    avg_cands_per_user = total_candidates_in_top300 / max(1, total_users_analyzed)\n    print(f\"[*] Số lượng ứng viên trung bình hệ thống cấp cho mỗi user: {avg_cands_per_user:.1f} món\")\n    \n    global_non_heur_pct = (non_heuristic_hits_top300 / total_candidates_in_top300) * 100\n    print(f\"[*] Sản phẩm KHÔNG thuộc phễu Heuristic lọt vào Top 300: {non_heuristic_hits_top300:,} món ({global_non_heur_pct:.2f}%)\")\n    print(f\"    => KẾT LUẬN THỰC CHIẾN: AI và Phân khúc ngách đã chiếm giữ {global_non_heur_pct:.2f}% không gian mặt tiền toàn hệ thống!\")\n    \n    print(\"\\n[-] CHI TIẾT TỶ LỆ PHÂN BỔ DIỆN TÍCH CỦA CÁC TẦNG PHỄU (MẪU CÓ TRÙNG LẶP):\")\n    print(\"-\" * 85)\n    for funnel_name, count in funnel_counts.items():\n        funnel_pct = (count / total_candidates_in_top300) * 100\n        print(f\"    + Tầng phễu [{funnel_name:<19}]: Chiếm {funnel_pct:>6.2f}% diện tích hiển thị ({count:,} ứng viên)\")\n        \n    print(\"Kết quả này chứng minh cấu trúc Thác nước (Waterfall) tự thích nghi\")\n    print(\"=\"*85)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-30T16:46:21.580872Z","iopub.execute_input":"2026-03-30T16:46:21.581645Z","execution_failed":"2026-03-30T16:47:40.976Z"}},"outputs":[],"execution_count":null}]}