{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":31254,"databundleVersionId":3103714,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np \nimport pandas as pd\nfrom pandasql import sqldf\n\nfrom itertools import combinations\nfrom collections import Counter\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n# Thiết lập style đồ thị (nền trắng, grid trắng, bố cục tự động).\nplt.style.use('seaborn-white')\nsns.set_style(\"whitegrid\")\nsns.despine()\nplt.rc(\"figure\", autolayout=True)\nplt.rc(\"axes\", labelweight=\"bold\", labelsize=\"large\", titleweight=\"bold\", titlesize=14, titlepad=10)\n\nimport matplotlib as mpl\n\nmpl.rcParams['axes.spines.left'] = False\nmpl.rcParams['axes.spines.right'] = False\nmpl.rcParams['axes.spines.top'] = False\nmpl.rcParams['axes.spines.bottom'] = False\nplt.rcParams[\"font.weight\"] = \"bold\"\nplt.rcParams[\"axes.labelweight\"] = \"bold\"","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:33:13.618202Z","iopub.execute_input":"2025-05-30T19:33:13.618500Z","iopub.status.idle":"2025-05-30T19:33:15.187494Z","shell.execute_reply.started":"2025-05-30T19:33:13.618473Z","shell.execute_reply":"2025-05-30T19:33:15.186361Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_a = pd.read_csv(\"/kaggle/input/h-and-m-personalized-fashion-recommendations/articles.csv\")\ndf_t = pd.read_csv(\"/kaggle/input/h-and-m-personalized-fashion-recommendations/transactions_train.csv\")\ndf_c = pd.read_csv(\"/kaggle/input/h-and-m-personalized-fashion-recommendations/customers.csv\")\n\n# Xóa cột 'postal_code' khỏi DataFrame\ndf_c = df_c.drop(columns=['postal_code'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:33:15.188546Z","iopub.execute_input":"2025-05-30T19:33:15.189094Z","iopub.status.idle":"2025-05-30T19:34:16.802529Z","shell.execute_reply.started":"2025-05-30T19:33:15.189059Z","shell.execute_reply":"2025-05-30T19:34:16.801254Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tính tổng tiền chi tiêu của mỗi khách hàng.\ndf_cust_prices = df_t[[\"customer_id\", \"price\"]].groupby(\"customer_id\").sum()\ndf_cust_prices.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:16.803639Z","iopub.execute_input":"2025-05-30T19:34:16.804009Z","iopub.status.idle":"2025-05-30T19:34:31.780078Z","shell.execute_reply.started":"2025-05-30T19:34:16.803974Z","shell.execute_reply":"2025-05-30T19:34:31.778887Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tính số lượng món hàng đã mua của mỗi khách hàng\ndf_cust_qty = df_t[[\"customer_id\", \"article_id\"]].groupby(\"customer_id\").count()\ndf_cust_qty.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:31.783184Z","iopub.execute_input":"2025-05-30T19:34:31.783516Z","iopub.status.idle":"2025-05-30T19:34:46.055736Z","shell.execute_reply.started":"2025-05-30T19:34:31.783490Z","shell.execute_reply":"2025-05-30T19:34:46.054855Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Kết hợp tổng tiền chi tiêu và số lượng sản phẩm mua thành một bảng.\ncust_qty_price = pd.merge(df_cust_prices, df_cust_qty, on='customer_id', how='inner')\ncust_qty_price.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:46.056783Z","iopub.execute_input":"2025-05-30T19:34:46.057048Z","iopub.status.idle":"2025-05-30T19:34:46.574543Z","shell.execute_reply.started":"2025-05-30T19:34:46.057026Z","shell.execute_reply":"2025-05-30T19:34:46.573494Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Ghép thêm thông tin chi tiết về khách hàng vào bảng đã tổng hợp.\ncust_details = pd.merge(cust_qty_price, df_c, on='customer_id', how='inner')\ncust_details.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:46.575969Z","iopub.execute_input":"2025-05-30T19:34:46.576806Z","iopub.status.idle":"2025-05-30T19:34:47.620043Z","shell.execute_reply.started":"2025-05-30T19:34:46.576777Z","shell.execute_reply":"2025-05-30T19:34:47.619177Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Gán nhóm tuổi cho từng khách hàng để phân tích dễ hơn.\ncust_details['age_groups'] = pd.cut(cust_details['age'], bins=[16, 20, 30, 40,50, 60, 70, float('Inf')], labels=['16-20', '20-30','30-40','40-50','50-60','60-70' , '70+'])\n\n# Gán nhóm \"Unknown\" cho các dòng bị NaN ở age\ncust_details['age_groups'] = cust_details['age_groups'].cat.add_categories('Unknown')\ncust_details['age_groups'] = cust_details['age_groups'].fillna('Unknown')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:47.620915Z","iopub.execute_input":"2025-05-30T19:34:47.621170Z","iopub.status.idle":"2025-05-30T19:34:47.683753Z","shell.execute_reply.started":"2025-05-30T19:34:47.621150Z","shell.execute_reply":"2025-05-30T19:34:47.682653Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tổng số khách hàng mỗi nhóm tuổi\nage_counts = cust_details.groupby('age_groups').agg(total_customers=('customer_id', 'count')).reset_index()\n\n# Số khách hàng ACTIVE mỗi nhóm tuổi\nactive_counts = (\n    cust_details[cust_details['club_member_status'] == 'ACTIVE']\n    .groupby('age_groups')\n    .agg(active_customers=('customer_id', 'count'))\n    .reset_index()\n)\n\n# Gộp lại\nage_summary = pd.merge(age_counts, active_counts, on='age_groups', how='left')\nage_summary['active_customers'] = age_summary['active_customers'].fillna(0).astype(int)\n\nage_summary_melted = age_summary.melt(\n    id_vars='age_groups',\n    value_vars=['total_customers', 'active_customers'],\n    var_name='Type', value_name='Count'\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:47.684851Z","iopub.execute_input":"2025-05-30T19:34:47.685185Z","iopub.status.idle":"2025-05-30T19:34:48.336319Z","shell.execute_reply.started":"2025-05-30T19:34:47.685112Z","shell.execute_reply":"2025-05-30T19:34:48.335030Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(12, 6))\ng = sns.barplot(data=age_summary_melted, x='age_groups', y='Count', hue='Type',\n                palette={'total_customers': '#4c72b0', 'active_customers': '#55a868'}, )\n\nplt.title(\"Customer Count and ACTIVE Count by Age Group\", fontsize=18, fontweight='bold')\nplt.xlabel(\"Age Group\", fontsize=14, fontweight='bold')\nplt.ylabel(\"Number of Customers\", fontsize=14, fontweight='bold')\nplt.legend(title='Customer Type')\nplt.grid(axis='y', linestyle='--', alpha=0.5)\n\n# Thêm số lượng trên đầu cột\nfor container in g.containers:\n    g.bar_label(container, fmt='%.0f', fontsize=10, padding=3)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:48.337523Z","iopub.execute_input":"2025-05-30T19:34:48.337881Z","iopub.status.idle":"2025-05-30T19:34:48.823498Z","shell.execute_reply.started":"2025-05-30T19:34:48.337854Z","shell.execute_reply":"2025-05-30T19:34:48.822420Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---\n# Nhóm tuổi nào mua nhiều sản phẩm nhất?","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(8,5))\nplt.title(\"Purchased quantity by age group\\n\", fontweight=\"bold\", size=18)\ng = sns.barplot(x=\"age_groups\", y=\"Purchased Quantity(%)\", data=cust_details.groupby(\"age_groups\")[\"article_id\"].sum() \\\n            .transform(lambda x: (x / x.sum() * 100)).rename('Purchased Quantity(%)').reset_index(), palette=\"Blues_r\", edgecolor=\"black\")\nplt.xlabel(\"Age Group\",fontweight=\"bold\", size=14)\nplt.ylabel(\"Purchased Quantity (%)\",fontweight=\"bold\", size=14)\nfor container in g.containers:\n    g.bar_label(container, padding = 5, fmt='%.1f', fontsize=10, color=\"black\")\nplt.grid(axis=\"y\",color = 'grey', linestyle = '--', linewidth = 0.5)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:48.824582Z","iopub.execute_input":"2025-05-30T19:34:48.824872Z","iopub.status.idle":"2025-05-30T19:34:49.219671Z","shell.execute_reply.started":"2025-05-30T19:34:48.824849Z","shell.execute_reply":"2025-05-30T19:34:49.218463Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---\n# Nhóm tuổi nào mang lại nhiều doanh thu cho hãng?","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(8,5))\nplt.title(\"Company Earnings by age group\\n\", fontweight=\"bold\", size=18)\ng = sns.barplot(x=\"age_groups\", y=\"earning(%)\", data=cust_details.groupby(\"age_groups\")[\"price\"].sum() \\\n            .transform(lambda x: (x / x.sum() * 100)).rename('earning(%)').reset_index(), palette=\"Blues_r\",edgecolor=\"black\")\nplt.xlabel(\"Age Group\",fontweight=\"bold\", size=14)\nplt.ylabel(\"Earnings (%)\",fontweight=\"bold\", size=14)\nfor container in g.containers:\n    g.bar_label(container, padding = 5, fmt='%.1f', fontsize=10, color=\"black\")\nplt.grid(axis=\"y\",color = 'grey', linestyle = '--', linewidth = 0.5)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:49.220692Z","iopub.execute_input":"2025-05-30T19:34:49.220989Z","iopub.status.idle":"2025-05-30T19:34:49.608795Z","shell.execute_reply.started":"2025-05-30T19:34:49.220967Z","shell.execute_reply":"2025-05-30T19:34:49.607674Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---\n# Những khách hàng tích cực theo dõi tin tức thời trang có mua nhiều hơn không?","metadata":{}},{"cell_type":"code","source":"# So sánh số lượng mua giữa các nhóm theo dõi/thường xuyên/thỉnh thoảng/không theo dõi.\nplt.figure(figsize=(9,5))\nplt.title(\"Purchased quantity by Fashion News Frequency by Age Group\\n\", fontweight=\"bold\", size=18)\ng = sns.barplot(x=\"fashion_news_frequency\", y=\"Purchased Quantity(%)\", data=cust_details.groupby(\"fashion_news_frequency\")[\"article_id\"].sum() \\\n            .transform(lambda x: (x / x.sum() * 100)).rename('Purchased Quantity(%)').reset_index(), palette={'Monthly' : 'gray', 'NONE': '#4c72b0', 'Regularly': '#55a868'}, edgecolor=\"black\")\nplt.xlabel(\"Fashion News Frequency\",fontweight=\"bold\", size=14)\nplt.ylabel(\"Purchased Quantity (%)\",fontweight=\"bold\", size=14)\nfor container in g.containers:\n    g.bar_label(container, padding = 5, fmt='%.3f', fontsize=10, color=\"black\")\nplt.grid(axis=\"y\",color = 'grey', linestyle = '--', linewidth = 0.5)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:49.609765Z","iopub.execute_input":"2025-05-30T19:34:49.610067Z","iopub.status.idle":"2025-05-30T19:34:49.994010Z","shell.execute_reply.started":"2025-05-30T19:34:49.610038Z","shell.execute_reply":"2025-05-30T19:34:49.992949Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_qty_by_age_news = (\n    cust_details\n    .groupby(['age_groups', 'fashion_news_frequency'])['article_id']\n    .count()\n    .reset_index()\n    .rename(columns={'article_id': 'purchased_qty'})\n)\ndf_qty_by_age_news = df_qty_by_age_news[df_qty_by_age_news['fashion_news_frequency'].isin(['Regularly', 'NONE'])]\ndf_qty_by_age_news['pct'] = df_qty_by_age_news.groupby('age_groups')['purchased_qty'].transform(lambda x: (x / x.sum()) * 100)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:49.998229Z","iopub.execute_input":"2025-05-30T19:34:49.999098Z","iopub.status.idle":"2025-05-30T19:34:50.157681Z","shell.execute_reply.started":"2025-05-30T19:34:49.999061Z","shell.execute_reply":"2025-05-30T19:34:50.156617Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(14, 7))\ng = sns.barplot(\n    data=df_qty_by_age_news,\n    x='age_groups',\n    y='pct',\n    hue='fashion_news_frequency',\n    palette={'Regularly': '#55a868', 'NONE': '#4c72b0'}\n)\n\nplt.title(\"Purchased Quantity (%) by Fashion News Frequency & Age Group\", fontsize=18, fontweight='bold')\nplt.xlabel(\"Age Group\", fontsize=14, fontweight='bold')\nplt.ylabel(\"Purchased Quantity (%)\", fontsize=14, fontweight='bold')\nplt.legend(title='Fashion News Frequency', fontsize=12, title_fontsize=12)\nplt.grid(axis='y', linestyle='--', alpha=0.7)\n\n# ✅ Thêm số % trên từng cột\nfor container in g.containers:\n    g.bar_label(container, fmt='%.1f%%', fontsize=10, padding=3, color='black')\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:50.158725Z","iopub.execute_input":"2025-05-30T19:34:50.158984Z","iopub.status.idle":"2025-05-30T19:34:50.677989Z","shell.execute_reply.started":"2025-05-30T19:34:50.158963Z","shell.execute_reply":"2025-05-30T19:34:50.676875Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tỉ lệ người theo dõi theo từng nhóm tuổi\nx, y = 'age_groups', 'fashion_news_frequency'\ndf_age_news = cust_details.groupby(x)[y].value_counts(normalize=True)\ndf_age_news = df_age_news.mul(100)\ndf_age_news = df_age_news.rename('percent(%)').reset_index()\ndf_age_news = df_age_news[df_age_news[\"fashion_news_frequency\"].isin([\"Regularly\",\"NONE\"])]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:50.679235Z","iopub.execute_input":"2025-05-30T19:34:50.679645Z","iopub.status.idle":"2025-05-30T19:34:50.840786Z","shell.execute_reply.started":"2025-05-30T19:34:50.679614Z","shell.execute_reply":"2025-05-30T19:34:50.839643Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(13,6))\nplt.title(\"Fashion News Frequency by age group\\n\",fontweight=\"bold\", size=18)\ng=sns.barplot(x=\"age_groups\", y=\"percent(%)\",data=df_age_news, hue=\"fashion_news_frequency\", palette={'Regularly': '#55a868', 'NONE': '#4c72b0'})\nplt.xlabel(\"Age group\",fontweight=\"bold\", size=14)\nplt.ylabel(\"Percentage (%)\",fontweight=\"bold\", size=14)\nfor container in g.containers:\n    g.bar_label(container, padding = 5, fmt='%.1f%%', fontsize=10, color=\"black\")\nplt.grid(axis='y', linestyle='--', alpha=0.7)\nplt.legend(title='News Frequency',bbox_to_anchor=(1.0, 1.0), ncol=1, fancybox=True, shadow=True, fontsize=12,title_fontsize=13)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:50.841662Z","iopub.execute_input":"2025-05-30T19:34:50.842056Z","iopub.status.idle":"2025-05-30T19:34:51.334675Z","shell.execute_reply.started":"2025-05-30T19:34:50.842024Z","shell.execute_reply":"2025-05-30T19:34:51.333621Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---\n# Trạng thái thành viên câu lạc bộ có ảnh hưởng đến số lượng mua của cá nhân không?","metadata":{}},{"cell_type":"code","source":"cust_details[\"club_member_status\"].value_counts(normalize=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:51.335996Z","iopub.execute_input":"2025-05-30T19:34:51.336511Z","iopub.status.idle":"2025-05-30T19:34:51.440467Z","shell.execute_reply.started":"2025-05-30T19:34:51.336477Z","shell.execute_reply":"2025-05-30T19:34:51.439410Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Trung bình số hàng mua cho từng nhóm: ACTIVE, LEFT CLUB, PRE-CREATE\ncust_details.groupby(\"club_member_status\")[\"article_id\"].sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:51.441653Z","iopub.execute_input":"2025-05-30T19:34:51.442042Z","iopub.status.idle":"2025-05-30T19:34:51.582632Z","shell.execute_reply.started":"2025-05-30T19:34:51.442011Z","shell.execute_reply":"2025-05-30T19:34:51.581401Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"The average quantity of purchased products by the customers is {:.0f} products \".format(cust_details[\"article_id\"].mean()))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:51.584118Z","iopub.execute_input":"2025-05-30T19:34:51.584512Z","iopub.status.idle":"2025-05-30T19:34:51.593599Z","shell.execute_reply.started":"2025-05-30T19:34:51.584486Z","shell.execute_reply":"2025-05-30T19:34:51.592475Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"The average quantity of purchased products by the ACTIVE customers is {:.0f} products \".format(cust_details.groupby(\"club_member_status\")[\"article_id\"].mean()[\"ACTIVE\"]))\nprint(\"The average quantity of purchased products by the LEFT-CLUB customers is {:.0f} products \".format(cust_details.groupby(\"club_member_status\")[\"article_id\"].mean()[\"LEFT CLUB\"]))\nprint(\"The average quantity of purchased products by the PRE-CREATE customers is {:.0f} products \".format(cust_details.groupby(\"club_member_status\")[\"article_id\"].mean()[\"PRE-CREATE\"]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:51.594726Z","iopub.execute_input":"2025-05-30T19:34:51.595014Z","iopub.status.idle":"2025-05-30T19:34:52.014963Z","shell.execute_reply.started":"2025-05-30T19:34:51.594994Z","shell.execute_reply":"2025-05-30T19:34:52.014050Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(9,5))\nplt.title(\"Average Purchased Quantity by Club Member Status\\n\", fontweight=\"bold\", size=18)\ng = sns.barplot(x=\"club_member_status\", y=\"article_id\", data=cust_details.groupby(\"club_member_status\")[\"article_id\"].mean().astype(int).reset_index(), palette=\"Blues_r\", edgecolor=\"black\")\nplt.axhline(y = cust_details[\"article_id\"].mean(), color = 'r', linestyle = '-', linewidth = 0.5)\nplt.text(0.76, 23.7, 'Mean Purchased Quantity: {:.0f}'.format(cust_details[\"article_id\"].mean()), size=10, color=\"red\",fontweight=\"bold\")\nplt.xlabel(\"Club Member Status\",fontweight=\"bold\", size=14)\nplt.ylabel(\"Average Purchased Quantity\",fontweight=\"bold\", size=14)\nfor container in g.containers:\n    g.bar_label(container, padding = 5, fmt='%.0f', fontsize=10, color=\"black\")\nplt.grid(axis=\"y\",color = 'grey', linestyle = '--', linewidth = 0.5)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:52.015849Z","iopub.execute_input":"2025-05-30T19:34:52.016115Z","iopub.status.idle":"2025-05-30T19:34:52.421988Z","shell.execute_reply.started":"2025-05-30T19:34:52.016093Z","shell.execute_reply":"2025-05-30T19:34:52.420926Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(9,5))\nplt.title(\"Median Purchased Quantity by Club Member Status\\n\", fontweight=\"bold\", size=18)\ng = sns.barplot(x=\"club_member_status\", y=\"article_id\", data=cust_details.groupby(\"club_member_status\")[\"article_id\"].median().reset_index(), palette=\"Blues_r\", edgecolor=\"black\")\nplt.axhline(y = cust_details[\"article_id\"].median(), color = 'r', linestyle = '-', linewidth = 0.5)\nplt.text(0.76, 9.3, 'Median Purchased Quantity: {:.2f}'.format(cust_details[\"article_id\"].median()), size=10, color=\"red\",fontweight=\"bold\")\nplt.xlabel(\"Club Member Status\",fontweight=\"bold\", size=14)\nplt.ylabel(\"Median Purchaed Quantity\",fontweight=\"bold\", size=14)\nfor container in g.containers:\n    g.bar_label(container, padding = 5, fmt='%.0f', fontsize=10, color=\"black\")\nplt.grid(axis=\"y\",color = 'grey', linestyle = '--', linewidth = 0.5)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:52.423460Z","iopub.execute_input":"2025-05-30T19:34:52.423730Z","iopub.status.idle":"2025-05-30T19:34:52.880598Z","shell.execute_reply.started":"2025-05-30T19:34:52.423709Z","shell.execute_reply":"2025-05-30T19:34:52.879476Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"----\n","metadata":{}},{"cell_type":"code","source":"# Đếm số lượng theo index_name\nindex_counts = df_a['index_name'].value_counts().reset_index()\nindex_counts.columns = ['index_name', 'count']\n\n# Vẽ biểu đồ ngang\nplt.figure(figsize=(15, 7))\nax = sns.barplot(data=index_counts, y='index_name', x='count', palette='Blues_r')\n\n# Tiêu đề & nhãn trục\nplt.title('Number of Articles by Index Name', fontsize=18, fontweight='bold')\nax.set_xlabel('Count by Index Name', fontsize=12)\nax.set_ylabel('Index Name', fontsize=12)\n\n# Hiện số lượng ở đầu bên phải mỗi thanh\nfor container in ax.containers:\n    ax.bar_label(container, fmt='%.0f', label_type='edge', fontsize=10, padding=5)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:52.881564Z","iopub.execute_input":"2025-05-30T19:34:52.881821Z","iopub.status.idle":"2025-05-30T19:34:53.301312Z","shell.execute_reply.started":"2025-05-30T19:34:52.881801Z","shell.execute_reply":"2025-05-30T19:34:53.299933Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Baby/Children     4  \n# Ladieswear        1\n# Divided           2\n# Menswear          3\n# Sport             26\n\n# Merge thêm index_group_no vào giao dịch\ndf_t = df_t.merge(df_a[['article_id', 'index_group_no']], on='article_id', how='left')\n\n# Giữ lại chỉ sản phẩm thuộc nhóm nam/nữ (Menswear: 3, Ladieswear: 1)\ntrans_gender = df_t[df_t['index_group_no'].isin([1, 3])]\n\n# Gom nhóm và gán nhóm phổ biến nhất\nfrom collections import Counter\n\ncustomer_index_group = trans_gender.groupby('customer_id')['index_group_no'].agg(list).reset_index()\ncustomer_index_group['gender_calc'] = customer_index_group['index_group_no'].apply(lambda x: Counter(x).most_common(1)[0][0])\n\n# Gộp vào bảng khách hàng\ndf_c = df_c.merge(customer_index_group[['customer_id', 'gender_calc']], on='customer_id', how='left')\ndf_c['gender_calc'] = df_c['gender_calc'].fillna(0).astype('int8')  # 0: không xác định","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:34:53.302642Z","iopub.execute_input":"2025-05-30T19:34:53.303019Z","iopub.status.idle":"2025-05-30T19:35:39.230360Z","shell.execute_reply.started":"2025-05-30T19:34:53.302990Z","shell.execute_reply":"2025-05-30T19:35:39.229183Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Đếm số lượng theo giới tính\ngender_counts = df_c['gender_calc'].value_counts().sort_index()\ngender_labels = ['Unidentified', 'Female (1)', 'Male (3)']\n\n# Chuẩn bị dữ liệu phần trăm\ngender_percent = gender_counts / gender_counts.sum()\n\n# Vẽ biểu đồ tròn\nplt.figure(figsize=(6, 6))\nplt.pie(\n    gender_percent.values,\n    labels=gender_labels[:len(gender_percent)],\n    autopct='%1.1f%%',\n    startangle=90,\n    colors=['lightgrey', '#FFB6C1', '#87CEFA'],  # xám, hồng, xanh\n    wedgeprops=dict(edgecolor='k')\n)\n\nplt.title(\"Customer Gender Distribution (Predicted)\", fontsize=14, fontweight='bold')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:35:39.231585Z","iopub.execute_input":"2025-05-30T19:35:39.231856Z","iopub.status.idle":"2025-05-30T19:35:39.413004Z","shell.execute_reply.started":"2025-05-30T19:35:39.231835Z","shell.execute_reply":"2025-05-30T19:35:39.411989Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_t = df_t.merge(df_a[['article_id', 'index_group_name']], on='article_id', how='left')\ndf_t = df_t.merge(cust_details[['customer_id', 'age_groups']], on='customer_id', how='left')\n\n# Tạo bảng tổng hợp số lượng sản phẩm mua theo nhóm tuổi và nhóm sản phẩm\nage_group_pref = (\n    df_t.groupby(['age_groups', 'index_group_name'])['article_id']\n    .count()\n    .reset_index()\n    .rename(columns={'article_id': 'purchased_count'})\n)\nplt.figure(figsize=(16, 7))\nsns.barplot(\n    data=age_group_pref,\n    x='age_groups',\n    y='purchased_count',\n    hue='index_group_name',\n    palette='tab10'\n)\n\nplt.title(\"Purchase Behavior by Age Group and Product Category\", fontsize=18, fontweight='bold')\nplt.xlabel(\"Age Group\", fontsize=14)\nplt.ylabel(\"Number of Items Purchased\", fontsize=14)\nplt.legend(title='Product Category', bbox_to_anchor=(1.02, 1), loc='upper left')\nplt.grid(axis='y', linestyle='--', alpha=0.5)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:35:39.413968Z","iopub.execute_input":"2025-05-30T19:35:39.414240Z","iopub.status.idle":"2025-05-30T19:36:27.270849Z","shell.execute_reply.started":"2025-05-30T19:35:39.414219Z","shell.execute_reply":"2025-05-30T19:36:27.269633Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---\n# Khách hàng hay mua những màu nào, và kết hợp màu nào với nhau?","metadata":{}},{"cell_type":"code","source":"df_t = df_t.merge(df_a[['article_id', 'prod_name', 'colour_group_name']], on='article_id', how='left')\n\n# Đếm tổng số sản phẩm theo màu đã mua\ncolor_counts = (\n    df_t.groupby('colour_group_name')['article_id']\n    .count()\n    .reset_index()\n    .rename(columns={'article_id': 'count'})\n    .sort_values(by='count', ascending=False)\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:36:27.272067Z","iopub.execute_input":"2025-05-30T19:36:27.272446Z","iopub.status.idle":"2025-05-30T19:36:38.389958Z","shell.execute_reply.started":"2025-05-30T19:36:27.272420Z","shell.execute_reply":"2025-05-30T19:36:38.388705Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"color_map = {\n    'Black': '#000000',\n    'White': '#FFFFFF',\n    'Dark Blue': '#00008B',\n    'Light Beige': '#D8CAB8',\n    'Blue': '#0000FF',\n    'Beige': '#F5F5DC',\n    'Light Blue': '#ADD8E6',\n    'Light Pink': '#FFB6C1',\n    'Off White': '#F8F8FF',\n    'Grey': '#808080'\n}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:36:38.391104Z","iopub.execute_input":"2025-05-30T19:36:38.391440Z","iopub.status.idle":"2025-05-30T19:36:38.397624Z","shell.execute_reply.started":"2025-05-30T19:36:38.391417Z","shell.execute_reply":"2025-05-30T19:36:38.396299Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Lấy top 10 màu phổ biến\ntop_colors = color_counts.head(10).copy()\n\n# Tạo danh sách mã màu đúng theo thứ tự\ntop_colors_palette = [color_map.get(c, 'lightgrey') for c in top_colors['colour_group_name']]\n\n# Vẽ biểu đồ\nplt.figure(figsize=(14, 6))\nsns.barplot(data=top_colors, x='colour_group_name', y='count', palette=top_colors_palette, edgecolor=\"black\")\n\nplt.title(\"Top 10 Most Frequently Purchased Colors\", fontsize=16, fontweight='bold')\nplt.xlabel(\"Color Group\")\nplt.ylabel(\"Purchase Count\")\nplt.xticks(rotation=45)\nplt.grid(axis='y', linestyle='--', alpha=0.5)\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:36:38.398689Z","iopub.execute_input":"2025-05-30T19:36:38.399001Z","iopub.status.idle":"2025-05-30T19:36:38.767216Z","shell.execute_reply.started":"2025-05-30T19:36:38.398971Z","shell.execute_reply":"2025-05-30T19:36:38.766078Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tập hợp các màu một khách hàng từng mua\ncolor_combinations = (\n    df_t.groupby('customer_id')['colour_group_name']\n    .apply(lambda x: list(set(x.dropna())))\n    .apply(lambda x: list(combinations(sorted(x), 2)))  # tạo cặp tổ hợp màu\n)\n\n# Đếm tổ hợp màu phổ biến\ncolor_pair_counter = Counter([pair for sublist in color_combinations for pair in sublist])\ncommon_color_pairs = pd.DataFrame(color_pair_counter.most_common(10), columns=['Color Pair', 'Count'])\n\n# Hiển thị\nprint(common_color_pairs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:36:38.768312Z","iopub.execute_input":"2025-05-30T19:36:38.768726Z","iopub.status.idle":"2025-05-30T19:39:52.724100Z","shell.execute_reply.started":"2025-05-30T19:36:38.768696Z","shell.execute_reply":"2025-05-30T19:39:52.723058Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tạo dữ liệu\npairs = common_color_pairs.copy()\npairs['Color A'] = pairs['Color Pair'].apply(lambda x: x[0])\npairs['Color B'] = pairs['Color Pair'].apply(lambda x: x[1])\npairs['Label'] = pairs['Color A'] + ' & ' + pairs['Color B']\n\n# Vẽ dotplot\nfig, ax = plt.subplots(figsize=(10, 6))\n\nfor i, row in pairs.iterrows():\n    y = len(pairs) - 1 - i  # từ trên xuống\n    # Vẽ 2 dấu chấm\n    ax.scatter(0.5, y, s=500, color=color_map.get(row['Color A'], 'gray'), edgecolor='k')\n    ax.scatter(1.5, y, s=500, color=color_map.get(row['Color B'], 'gray'), edgecolor='k')\n    # Ghi số lượng\n    ax.text(2.1, y, f\"{row['Count']:,}\", va='center', fontsize=11)\n\n# Cấu hình trục\nax.set_yticks(range(len(pairs))[::-1])\nax.set_yticklabels(pairs['Label'])\nax.set_xticks([0.5, 1.5])\nax.set_xticklabels(['Color A', 'Color B'])\nax.set_xlim(0, 2.5)\nax.set_title(\"Top 10 Most Frequently Co-Purchased Color Pairs\", fontsize=16, fontweight='bold')\nax.set_xlabel(\"Colors in Pair\")\nax.set_ylabel(\"Color Pair\")\nax.grid(axis='y', linestyle='--', alpha=0.4)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:42:24.877457Z","iopub.execute_input":"2025-05-30T19:42:24.877835Z","iopub.status.idle":"2025-05-30T19:42:25.309772Z","shell.execute_reply.started":"2025-05-30T19:42:24.877809Z","shell.execute_reply":"2025-05-30T19:42:25.308729Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"---\n# Top sản phẩm thường được mua với số lượng lớn trong một lần giao dịch","metadata":{}},{"cell_type":"code","source":"# Mỗi giao dịch là tổ hợp: customer_id + t_dat + article_id\ndf_t['cnt_articles'] = df_t.groupby(['customer_id', 't_dat', 'article_id'])['article_id'].transform('count')\n# Loại bỏ trùng dòng, chỉ lấy 1 dòng cho mỗi giao dịch sản phẩm\narticle_freq = (\n    df_t[['customer_id', 't_dat', 'article_id', 'cnt_articles']]\n    .drop_duplicates()\n    .groupby('article_id')['cnt_articles']\n    .sum()\n    .reset_index()\n    .sort_values(by='cnt_articles', ascending=False)\n)\ntop_articles = article_freq.merge(df_a[['article_id', 'prod_name']], on='article_id', how='left')\ntop_articles = top_articles.drop_duplicates(subset='article_id').head(10)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:39:53.169528Z","iopub.execute_input":"2025-05-30T19:39:53.169784Z","iopub.status.idle":"2025-05-30T19:40:55.322903Z","shell.execute_reply.started":"2025-05-30T19:39:53.169765Z","shell.execute_reply":"2025-05-30T19:40:55.321765Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(12, 6))\nax = sns.barplot(\n    data=top_articles,\n    y='prod_name',\n    x='cnt_articles',\n    palette='Blues_r',\n    ci=None \n)\nplt.title(\"Top 10 Most Frequently Bulk-Purchased Products\", fontsize=16, fontweight='bold')\nplt.xlabel(\"Total Quantity Purchased\")\nplt.ylabel(\"Product Name\")\nfor container in ax.containers:\n    ax.bar_label(container, fmt='%.0f', fontsize=10, padding=3)\nplt.grid(axis='x', linestyle='--', alpha=0.5)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T19:40:55.324084Z","iopub.execute_input":"2025-05-30T19:40:55.325066Z","iopub.status.idle":"2025-05-30T19:40:55.693798Z","shell.execute_reply.started":"2025-05-30T19:40:55.325022Z","shell.execute_reply":"2025-05-30T19:40:55.692685Z"}},"outputs":[],"execution_count":null}]}