{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\n\n# =====================================================================\n# BƯỚC 0: ĐỌC DỮ LIỆU\n# =====================================================================\nfile_transactions = '/kaggle/input/competitions/h-and-m-personalized-fashion-recommendations/transactions_train.csv'\nfile_articles = '/kaggle/input/competitions/h-and-m-personalized-fashion-recommendations/articles.csv'\n\n# Giao dịch\ndf = pd.read_csv(file_transactions)\ndf['t_dat'] = pd.to_datetime(df['t_dat'])\n\n# Thông tin sản phẩm\narticles_df = pd.read_csv(\n    file_articles,\n    usecols=['article_id', 'index_name']\n)\n\n# =====================================================================\n# BƯỚC 1: TÍNH THỜI GIAN TRUNG BÌNH QUAY LẠI MUA CỦA TỪNG SẢN PHẨM\n# =====================================================================\nprint(\"Đang tính khoảng cách ngày mua lại của từng sản phẩm...\")\n\ndf = df.sort_values(\n    by=['customer_id', 'article_id', 't_dat']\n)\n\ndf['days_between_purchases'] = (\n    df.groupby(['customer_id', 'article_id'])['t_dat']\n      .diff()\n      .dt.days\n)\n\nrepeat_purchases = df[df['days_between_purchases'] > 0]\n\nproduct_avg_days = (\n    repeat_purchases\n    .groupby('article_id')['days_between_purchases']\n    .mean()\n    .reset_index(name='Ngay_Mua_Lai_Trung_Binh_SP')\n)\n\n# =====================================================================\n# BƯỚC 2: TÍNH TỶ LỆ MUA LẠI CỦA TỪNG SẢN PHẨM\n# =====================================================================\nprint(\"Đang tính tỷ lệ mua lại của từng sản phẩm...\")\n\ncustomer_art_orders = (\n    df.groupby(['article_id', 'customer_id'])['t_dat']\n      .nunique()\n      .reset_index(name='order_count')\n)\n\ncustomer_art_orders['is_repeat'] = (\n    customer_art_orders['order_count'] >= 2\n)\n\nproduct_rpr = (\n    customer_art_orders\n    .groupby('article_id')\n    .agg(\n        Tong_Khach_Mua_SP=('customer_id', 'count'),\n        Khach_Quay_Lai_Mua_SP=('is_repeat', 'sum')\n    )\n    .reset_index()\n)\n\nproduct_rpr['Ty_Le_Mua_Lai_Cung_SP_%'] = (\n    product_rpr['Khach_Quay_Lai_Mua_SP']\n    / product_rpr['Tong_Khach_Mua_SP']\n) * 100\n\n# =====================================================================\n# BƯỚC 3: GỘP THÔNG TIN SẢN PHẨM\n# =====================================================================\nprint(\"Đang tổng hợp dữ liệu sản phẩm theo danh mục...\")\n\nproduct_metrics = pd.merge(\n    product_rpr,\n    product_avg_days,\n    on='article_id',\n    how='left'\n)\n\nproduct_metrics = pd.merge(\n    product_metrics,\n    articles_df,\n    on='article_id',\n    how='left'\n)\n\n# =====================================================================\n# BƯỚC 4: THỐNG KÊ THEO DANH MỤC\n# =====================================================================\ncategory_summary = (\n    product_metrics\n    .groupby('index_name')\n    .agg(\n        Tong_Khach_Mua_DanhMuc=('Tong_Khach_Mua_SP', 'sum'),\n        Tong_Khach_Quay_Lai_DanhMuc=('Khach_Quay_Lai_Mua_SP', 'sum'),\n        Ngay_Quay_Lai_Mua_Cung_SP_Binh_Quan=('Ngay_Mua_Lai_Trung_Binh_SP', 'mean'),\n        Tong_So_Luong_San_Pham_Trong_DanhMuc=('article_id', 'count')\n    )\n    .reset_index()\n)\n\ncategory_summary['Ty_Le_Mua_Lai_Cung_SP_Phan_Tram'] = (\n    category_summary['Tong_Khach_Quay_Lai_DanhMuc']\n    / category_summary['Tong_Khach_Mua_DanhMuc']\n) * 100\n\n# Sắp xếp giảm dần theo tỷ lệ mua lại\ncategory_summary = category_summary.sort_values(\n    by='Ty_Le_Mua_Lai_Cung_SP_Phan_Tram',\n    ascending=False\n).reset_index(drop=True)\n\n# =====================================================================\n# BƯỚC 5: HIỂN THỊ KẾT QUẢ\n# =====================================================================\nprint(\"\\n--- THỐNG KÊ MUA LẠI THEO DANH MỤC ---\")\n\nprint(\n    category_summary[\n        [\n            'index_name',\n            'Ty_Le_Mua_Lai_Cung_SP_Phan_Tram',\n            'Ngay_Quay_Lai_Mua_Cung_SP_Binh_Quan',\n            'Tong_So_Luong_San_Pham_Trong_DanhMuc'\n        ]\n    ]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-17T16:03:16.280912Z","iopub.execute_input":"2026-06-17T16:03:16.281232Z","iopub.status.idle":"2026-06-17T16:04:58.057616Z","shell.execute_reply.started":"2026-06-17T16:03:16.281212Z","shell.execute_reply":"2026-06-17T16:04:58.056153Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport seaborn as sns\n\n# 1. Cấu hình giao diện và kích thước biểu đồ\nsns.set_theme(style=\"whitegrid\")\nplt.figure(figsize=(12, 7))\n\n# 2. Vẽ biểu đồ cột ngang (Horizontal Bar Chart)\nax = sns.barplot(\n    x='Ty_Le_Mua_Lai_Cung_SP_Phan_Tram', \n    y='index_name', \n    data=category_summary, \n    palette='Blues_r'  # Màu sắc chuyển từ đậm đến nhạt\n)\n\n# 3. Thêm hiển thị số liệu phần trăm cụ thể ở cuối mỗi cột\nfor p in ax.patches:\n    width = p.get_width()\n    ax.text(\n        width + 0.05,          # Vị trí X (đẩy sang phải một chút so với cột)\n        p.get_y() + p.get_height() / 2, # Vị trí Y (ở giữa cột)\n        f'{width:.2f}%',       # Định dạng hiển thị số thập phân\n        va='center', \n        fontsize=10, \n        fontweight='bold'\n    )\n\n# 4. Thiết lập tiêu đề và nhãn các trục\nplt.title('TỶ LỆ MUA LẠI CÙNG SẢN PHẨM THEO DANH MỤC', fontsize=14, fontweight='bold', pad=20)\nplt.xlabel('Tỷ lệ mua lại (%)', fontsize=12, fontweight='bold')\nplt.ylabel('Danh mục', fontsize=12, fontweight='bold')\n\n# Hạn chế việc chữ bị cắt tràn viền\nplt.tight_layout()\n\n# 5. Hiển thị biểu đồ\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-17T16:12:09.764801Z","iopub.execute_input":"2026-06-17T16:12:09.765100Z","iopub.status.idle":"2026-06-17T16:12:11.070388Z","shell.execute_reply.started":"2026-06-17T16:12:09.765077Z","shell.execute_reply":"2026-06-17T16:12:11.069504Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nprint(\"Đang tải dữ liệu từ cả 3 bảng...\")\n# Đường dẫn đã chuẩn hóa theo cấu hình thư mục của bạn\npath_transactions = '/kaggle/input/competitions/h-and-m-personalized-fashion-recommendations/transactions_train.csv'\npath_customers = '/kaggle/input/competitions/h-and-m-personalized-fashion-recommendations/customers.csv'\npath_articles = '/kaggle/input/competitions/h-and-m-personalized-fashion-recommendations/articles.csv'\n\n# Chỉ đọc các cột thực sự cần thiết để tiết kiệm RAM tối đa\ndf_trans = pd.read_csv(path_transactions, usecols=['customer_id', 'article_id'])\ndf_cust = pd.read_csv(path_customers, usecols=['customer_id', 'age'])\ndf_art = pd.read_csv(path_articles, usecols=['article_id', 'index_name'])\n\nprint(\"Đang tiến hành gộp dữ liệu (Merge)...\")\n# Gộp giao dịch với thông tin khách hàng để lấy tuổi\ndf_merged = pd.merge(df_trans, df_cust, on='customer_id', how='left')\n# Gộp tiếp với thông tin sản phẩm để lấy danh mục khách hàng mục tiêu\ndf_merged = pd.merge(df_merged, df_art, on='article_id', how='left')\n\nprint(\"Đang phân nhóm tuổi và tính toán bảng tỷ lệ...\")\n# Định nghĩa các khoảng tuổi\nbins = [15, 30, 40, 50, 100]\nlabels = ['16 - 30 tuổi', '31 - 40 tuổi', '41 - 50 tuổi', 'Trên 50 tuổi']\ndf_merged['Nhom_Tuoi'] = pd.cut(df_merged['age'], bins=bins, labels=labels)\n\n# Tạo bảng chéo tính TỶ LỆ PHẦN TRĂM (%) TRÊN TOÀN BỘ HỆ THỐNG (Tổng cả bảng = 100%)\n# Nếu bạn muốn tính tỷ lệ riêng trong nội bộ từng nhóm tuổi, hãy đổi thành normalize='columns'\npivot_matrix = pd.crosstab(\n    index=df_merged['index_name'], \n    columns=df_merged['Nhom_Tuoi'], \n    normalize='all' \n) * 100\n\nprint(\"\\n--- BẢNG TỶ LỆ ĐƠN HÀNG (%) GIỮA DANH MỤC VÀ NHÓM TUỔI ---\")\nprint(pivot_matrix.round(2))\n\n# =====================================================================\n# TRỰC QUAN HÓA BẰNG HEATMAP\n# =====================================================================\nprint(\"\\nĐang vẽ biểu đồ nhiệt (Heatmap)...\")\nplt.figure(figsize=(12, 8))\n\n# Vẽ biểu đồ nhiệt với bảng màu YlGnBu (Vàng - Xanh lá - Xanh dương) trực quan\nsns.heatmap(\n    pivot_matrix, \n    annot=True,          # Hiển thị số liệu lên từng ô\n    fmt=\".2f\",           # Định dạng số thập phân (2 chữ số)\n    cmap=\"YlGnBu\",       # Màu sắc chuyển từ nhạt (thấp) đến đậm (cao)\n    linewidths=0.5,      # Đường kẻ mảnh phân tách các ô\n    cbar_kws={'label': 'Tỷ lệ % trên tổng đơn hàng'}\n)\n\n# Tinh chỉnh tiêu đề và nhãn các trục để không bị lỗi đè chữ\nplt.title('BẢNG NHIỆT PHÂN TÍCH ĐƠN HÀNG THEO NHÓM TUỔI VÀ DANH MỤC', fontsize=14, fontweight='bold', pad=20)\nplt.xlabel('Nhóm tuổi khách hàng', fontsize=12, fontweight='bold', labelpad=10)\nplt.ylabel('Danh mục sản phẩm', fontsize=12, fontweight='bold', labelpad=10)\nplt.xticks(rotation=0) # Giữ chữ trục X nằm ngang cho dễ đọc\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-17T16:36:51.943122Z","iopub.execute_input":"2026-06-17T16:36:51.943388Z","iopub.status.idle":"2026-06-17T16:37:32.945816Z","shell.execute_reply.started":"2026-06-17T16:36:51.943368Z","shell.execute_reply":"2026-06-17T16:37:32.944743Z"}},"outputs":[],"execution_count":null}]}