{"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":"gpu","dataSources":[{"sourceType":"competition","sourceId":7391,"databundleVersionId":44328}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:02:32.339385Z","iopub.execute_input":"2026-05-12T19:02:32.339676Z","iopub.status.idle":"2026-05-12T19:02:33.317057Z","shell.execute_reply.started":"2026-05-12T19:02:32.339652Z","shell.execute_reply":"2026-05-12T19:02:33.316407Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install py7zr","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:02:35.937367Z","iopub.execute_input":"2026-05-12T19:02:35.938179Z","iopub.status.idle":"2026-05-12T19:02:41.453830Z","shell.execute_reply.started":"2026-05-12T19:02:35.938147Z","shell.execute_reply":"2026-05-12T19:02:41.452698Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import py7zr\nimport os\n\ninput_path = \"/kaggle/input/competitions/favorita-grocery-sales-forecasting/\"\nextract_path = \"/kaggle/working/data/\"\n\nos.makedirs(extract_path, exist_ok=True)\n\nfiles = [\n    \"train.csv.7z\",\n    \"test.csv.7z\",\n    \"stores.csv.7z\",\n    \"items.csv.7z\",\n    \"oil.csv.7z\",\n    \"transactions.csv.7z\",\n    \"holidays_events.csv.7z\",\n    \"sample_submission.csv.7z\"\n]\n\nfor f in files:\n    with py7zr.SevenZipFile(input_path + f, mode='r') as z:\n        z.extractall(path=extract_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:02:43.456839Z","iopub.execute_input":"2026-05-12T19:02:43.457651Z","iopub.status.idle":"2026-05-12T19:04:03.511876Z","shell.execute_reply.started":"2026-05-12T19:02:43.457616Z","shell.execute_reply":"2026-05-12T19:04:03.510962Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nsns.set(style=\"whitegrid\")\n\ndata_path = \"/kaggle/working/data/\"\n\ntrain = pd.read_csv(data_path + \"train.csv\", parse_dates=['date'])\ntest = pd.read_csv(data_path + \"test.csv\", parse_dates=['date'])\nstores = pd.read_csv(data_path + \"stores.csv\")\nitems = pd.read_csv(data_path + \"items.csv\")\noil = pd.read_csv(data_path + \"oil.csv\", parse_dates=['date'])\ntransactions = pd.read_csv(data_path + \"transactions.csv\", parse_dates=['date'])\nholidays = pd.read_csv(data_path + \"holidays_events.csv\", parse_dates=['date'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:04:03.513251Z","iopub.execute_input":"2026-05-12T19:04:03.513605Z","iopub.status.idle":"2026-05-12T19:05:25.004184Z","shell.execute_reply.started":"2026-05-12T19:04:03.513581Z","shell.execute_reply":"2026-05-12T19:05:25.003511Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def reduce_mem_usage(df):\n    for col in df.columns:\n        if df[col].dtype != 'object':\n            df[col] = pd.to_numeric(df[col], downcast='float')\n    return df\n\ntrain = reduce_mem_usage(train)\n\n# Sampling for EDA\nsample_df = train.sample(2_000_000, random_state=42)\n\nsample_df['date'] = pd.to_datetime(sample_df['date'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:05:25.005275Z","iopub.execute_input":"2026-05-12T19:05:25.005748Z","iopub.status.idle":"2026-05-12T19:05:49.544233Z","shell.execute_reply.started":"2026-05-12T19:05:25.005716Z","shell.execute_reply":"2026-05-12T19:05:49.543603Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Data cleaning**","metadata":{}},{"cell_type":"code","source":"sample_df['onpromotion'] = sample_df['onpromotion'].fillna(False)\nsample_df['unit_sales'] = sample_df['unit_sales'].clip(lower=0)\nsample_df['log_sales'] = np.log1p(sample_df['unit_sales'])\n\n# FEATURE TIME\nsample_df['dow'] = sample_df['date'].dt.dayofweek\nsample_df['month'] = sample_df['date'].dt.month\nsample_df['year'] = sample_df['date'].dt.year","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:05:49.545594Z","iopub.execute_input":"2026-05-12T19:05:49.546005Z","iopub.status.idle":"2026-05-12T19:05:50.105586Z","shell.execute_reply.started":"2026-05-12T19:05:49.545979Z","shell.execute_reply":"2026-05-12T19:05:50.104738Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Basic Overview**","metadata":{}},{"cell_type":"code","source":"train.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:08:09.756243Z","iopub.execute_input":"2026-05-12T19:08:09.757117Z","iopub.status.idle":"2026-05-12T19:08:09.771059Z","shell.execute_reply.started":"2026-05-12T19:08:09.757086Z","shell.execute_reply":"2026-05-12T19:08:09.770183Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.describe()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:08:19.951572Z","iopub.execute_input":"2026-05-12T19:08:19.952395Z","iopub.status.idle":"2026-05-12T19:08:37.969133Z","shell.execute_reply.started":"2026-05-12T19:08:19.952367Z","shell.execute_reply":"2026-05-12T19:08:37.968536Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.isnull().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:08:37.970218Z","iopub.execute_input":"2026-05-12T19:08:37.970581Z","iopub.status.idle":"2026-05-12T19:08:44.207955Z","shell.execute_reply.started":"2026-05-12T19:08:37.970556Z","shell.execute_reply":"2026-05-12T19:08:44.207209Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Train**","metadata":{}},{"cell_type":"markdown","source":"## **Target Distribution**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(10,5))\nsns.histplot(sample_df['unit_sales'], bins=100)\nplt.title(\"Raw Sales Distribution\")\n\nplt.figure(figsize=(10,5))\nsns.histplot(sample_df['log_sales'], bins=100)\nplt.title(\"Log Sales Distribution\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:10:22.434255Z","iopub.execute_input":"2026-05-12T19:10:22.435105Z","iopub.status.idle":"2026-05-12T19:10:25.589918Z","shell.execute_reply.started":"2026-05-12T19:10:22.435074Z","shell.execute_reply":"2026-05-12T19:10:25.589204Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Sales Over Time**","metadata":{}},{"cell_type":"code","source":"sales = train.groupby('date')['unit_sales'].sum().reset_index()\n\nsales['date'] = pd.to_datetime(sales['date'])\n\nplt.figure(figsize=(12,6))\n\nplt.plot(sales['date'], sales['unit_sales'], alpha=0.3, label='Raw Sales')\n\nsales['rolling_30'] = sales['unit_sales'].rolling(30, center=True, min_periods=1).mean()\nplt.plot(sales['date'], sales['rolling_30'], color='red', linewidth=2, label='30-day Trend')\n\nplt.legend()\nplt.title(\"Sales Trend\", fontsize=14, fontweight='bold')\nplt.xlabel(\"Date\")\nplt.ylabel(\"Total Unit Sales\")\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:10:25.591202Z","iopub.execute_input":"2026-05-12T19:10:25.591424Z","iopub.status.idle":"2026-05-12T19:10:28.848923Z","shell.execute_reply.started":"2026-05-12T19:10:25.591402Z","shell.execute_reply":"2026-05-12T19:10:28.848202Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy tổng doanh số có xu hướng tăng dần theo thời gian từ năm 2013 đến 2017. Đường 30-day rolling mean (màu đỏ) giúp làm mượt dữ liệu và cho thấy rõ xu hướng tăng trưởng dài hạn của doanh số. Ngoài ra, dữ liệu xuất hiện nhiều đợt biến động mạnh và các spike doanh số lớn, đặc biệt trong giai đoạn từ 2015 trở đi. Biên độ dao động của doanh số cũng ngày càng lớn theo thời gian, cho thấy mức độ biến động của thị trường tăng lên đáng kể.\n\nĐiều này phản ánh rằng hệ thống bán lẻ đang phát triển theo thời gian với nhu cầu tiêu dùng ngày càng tăng. Tuy nhiên, doanh số không tăng một cách ổn định mà chịu ảnh hưởng mạnh bởi nhiều yếu tố như:\n- Seasonal events (lễ, tết, cuối năm)\n- Promotion \n- Thói quen mua sắm theo thời điểm\n- Các yếu tố kinh tế bên ngoài\n\nCác đỉnh tăng trưởng lớn có thể đại diện cho các giai đoạn cao điểm tiêu dùng hoặc các chiến dịch khuyến mãi quy mô lớn. Đặc biệt, từ năm 2015 trở đi, rolling trend tăng nhanh hơn cho thấy doanh nghiệp có thể đã mở rộng hệ thống cửa hàng hoặc tăng trưởng mạnh về lượng khách hàng.\n\nBiểu đồ cho thấy dữ liệu mang đặc trưng rõ rệt của bài toán time-series forecasting:\n- Có trend dài hạn (long-term trend)\n- Có seasonality\n- Có volatility cao\n- Có temporal dependency\n\nĐiều này cho thấy việc chỉ sử dụng dữ liệu gốc sẽ không đủ để mô hình học tốt. **Cần tạo thêm các temporal features như:** day_of_week, month, year, lag features, rolling mean, rolling std\n\nNgoài ra, do variance tăng theo thời gian, các mô hình boosting như: XGBoost, LightGBM, CatBoost sẽ phù hợp hơn linear models truyền thống. Insight này cũng cho thấy việc sử dụng random split là không phù hợp vì có thể gây data leakage trong bài toán forecasting.\n\n**Từ góc nhìn kinh doanh** xu hướng doanh số tăng dần theo thời gian cùng với mức độ biến động ngày càng lớn cho thấy nhu cầu tiêu dùng của khách hàng không ổn định mà thay đổi mạnh theo từng giai đoạn. Điều này giúp doanh nghiệp có thể chủ động dự đoán các thời điểm cao điểm mua sắm để chuẩn bị hàng tồn kho, tối ưu logistics và phân bổ nhân sự phù hợp theo mùa. Đồng thời, doanh nghiệp cũng có thể xây dựng các chiến lược promotion hiệu quả hơn trong những giai đoạn doanh số thấp nhằm kích thích nhu cầu tiêu dùng. Bên cạnh đó, mức volatility tăng mạnh theo thời gian cho thấy tầm quan trọng của một hệ thống forecasting chính xác để hạn chế tình trạng thiếu hàng trong mùa cao điểm, giảm tồn kho dư thừa và tối ưu doanh thu tổng thể.","metadata":{}},{"cell_type":"code","source":"sales['rolling_7'] = sales['unit_sales'].rolling(7).mean()\nsales['rolling_30'] = sales['unit_sales'].rolling(30).mean()\n\nplt.figure(figsize=(14,6))\nplt.plot(sales['date'], sales['rolling_7'], label='7-day')\nplt.plot(sales['date'], sales['rolling_30'], label='30-day')\nplt.legend()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:10:32.687406Z","iopub.execute_input":"2026-05-12T19:10:32.688100Z","iopub.status.idle":"2026-05-12T19:10:32.879350Z","shell.execute_reply.started":"2026-05-12T19:10:32.688066Z","shell.execute_reply":"2026-05-12T19:10:32.878616Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **Seasonality Analysis**","metadata":{}},{"cell_type":"code","source":"pivot = sample_df.pivot_table(\n    index='dow',\n    columns='month',\n    values='unit_sales',\n    aggfunc='mean'\n)\n\npivot.index = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']\npivot.columns = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']\n\nplt.figure(figsize=(12,6))\nsns.heatmap(pivot, annot=True, fmt=\".2f\", cmap=\"coolwarm\")\n\nplt.title(\"Seasonality Heatmap\", fontsize=14, fontweight='bold')\nplt.ylabel(\"Day of Week\")\nplt.xlabel(\"Month\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:10:36.238539Z","iopub.execute_input":"2026-05-12T19:10:36.239194Z","iopub.status.idle":"2026-05-12T19:10:36.738865Z","shell.execute_reply.started":"2026-05-12T19:10:36.239164Z","shell.execute_reply":"2026-05-12T19:10:36.738095Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ heatmap cho thấy doanh số có tính seasonality rất rõ rệt theo cả ngày trong tuần và các tháng trong năm. Chủ nhật là ngày có doanh số cao nhất gần như xuyên suốt toàn bộ năm, với giá trị dao động từ khoảng 9.59 đến 11.65, trong đó tháng 12 đạt mức cao nhất toàn bộ heatmap với 11.65. Ngược lại, các ngày giữa tuần như Thứ Năm thường có doanh số thấp hơn đáng kể, chỉ dao động quanh mức 6.67 - 8.73. Điều này cho thấy nhu cầu mua sắm của khách hàng tăng mạnh vào cuối tuần, đặc biệt là Chủ nhật khi người tiêu dùng có nhiều thời gian hơn cho hoạt động mua sắm và tiêu dùng.\n\nNgoài ra, **tháng 12 nổi bật** với mức doanh số tăng mạnh ở hầu hết các ngày trong tuần, ví dụ:\n- Monday tăng lên 9.67\n- Wednesday đạt 10.08\n- Friday đạt 9.70\n- Saturday đạt 10.19\n- Sunday đạt đỉnh 11.65\n\nSo với các tháng thông thường chỉ dao động quanh mức 7 đến 9, đây là mức tăng rất đáng kể, phản ánh ảnh hưởng mạnh của mùa lễ hội, cuối năm và các chiến dịch promotion lớn. Insight này cho thấy dữ liệu tồn tại đồng thời:\n- weekly seasonality (chu kỳ theo tuần)\n- annual seasonality (chu kỳ theo năm)\n\nĐối với forecasting model, đây là tín hiệu rất quan trọng vì nếu mô hình không học được các seasonal patterns này thì sai số dự báo ở các giai đoạn cao điểm sẽ tăng mạnh. **Do đó cần xây dựng các feature như: day_of_week, is_weekend, month, holiday season, cyclical encoding để giúp mô hình học tốt hơn hành vi tiêu dùng theo thời gian.**\n\n**Từ góc nhìn kinh doanh** heatmap cho thấy doanh nghiệp cần đặc biệt chú trọng vào các giai đoạn cuối tuần và cuối năm – thời điểm nhu cầu mua sắm tăng mạnh nhất. Điều này giúp doanh nghiệp chủ động chuẩn bị hàng tồn kho, tối ưu chuỗi cung ứng và tăng cường nhân sự tại các thời điểm cao điểm nhằm tránh tình trạng thiếu hàng hoặc quá tải vận hành. Đồng thời, insight này cũng hỗ trợ xây dựng các chiến lược marketing và promotion theo mùa hiệu quả hơn, đặc biệt trong tháng 12 khi sức mua của khách hàng đạt mức cao nhất trong năm.","metadata":{}},{"cell_type":"markdown","source":"## **Promotion Analysis**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(8, 6))\nax1 = sns.countplot(x='onpromotion', data=train)\nfor container in ax1.containers:\n    ax1.bar_label(container, fmt='%.0f', padding=3)\nplt.title(\"Promotion Distribution\", fontsize=14, fontweight='bold')\nplt.xlabel(\"OnPromotion\")\nplt.ylabel(\"Unit Sales\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:20:47.465557Z","iopub.execute_input":"2026-05-12T19:20:47.466552Z","iopub.status.idle":"2026-05-12T19:23:32.234346Z","shell.execute_reply.started":"2026-05-12T19:20:47.466511Z","shell.execute_reply":"2026-05-12T19:23:32.233519Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy phần lớn doanh số đến từ các sản phẩm không có khuyến mãi (OnPromotion = False). Cụ thể, tổng unit_sales của nhóm không promotion đạt khoảng 117,686,418 trong khi nhóm có promotion chỉ đạt khoảng 7,810,622. Điều này cho thấy doanh số từ các sản phẩm không được khuyến mãi cao gấp hơn 15 lần so với nhóm có promotion.\n\nTuy nhiên, điều này không đồng nghĩa promotion không hiệu quả. Trên thực tế, số lượng sản phẩm hoặc số ngày không promotion trong dữ liệu lớn hơn rất nhiều so với các trường hợp có promotion, nên tổng doanh số tự nhiên sẽ cao hơn. Điều quan trọng là promotion vẫn tạo ra các demand spikes đáng kể trong những thời điểm cụ thể và đóng vai trò kích thích hành vi mua sắm của khách hàng.\n\nBiểu đồ phản ánh rằng hoạt động promotion chỉ được áp dụng cho một phần nhỏ sản phẩm hoặc trong các giai đoạn nhất định, thay vì triển khai đại trà trên toàn hệ thống. Điều này cho thấy doanh nghiệp đang sử dụng promotion như một chiến lược tối ưu doanh thu có chọn lọc nhằm:\n- tăng nhu cầu ngắn hạn\n- kích cầu cho một số nhóm sản phẩm\n- thúc đẩy doanh số trong các giai đoạn thấp điểm\n\nĐối với forecasting model, onpromotion là feature rất quan trọng vì dù số lượng promotion không lớn, nhưng chúng có thể tạo ra biến động doanh số mạnh trong ngắn hạn. Nếu mô hình bỏ qua feature này, khả năng dự báo các spike doanh số sẽ giảm đáng kể, đặc biệt trong các mùa campaign hoặc dịp lễ. Do đó, cần xây dựng thêm các promotion-related features như: số ngày promotion liên tiếp, promotion intensity, rolling promotion count, interaction giữa promotion và holiday.\n\n**Từ góc nhìn kinh doanh** giúp doanh nghiệp hiểu rằng promotion không cần xuất hiện thường xuyên để tạo tác động lớn lên hành vi tiêu dùng. Việc triển khai promotion đúng thời điểm và đúng nhóm sản phẩm có thể giúp tối ưu doanh thu, tăng lượng khách hàng và cải thiện hiệu quả bán hàng mà không cần giảm giá trên diện rộng.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(8, 6))\nax2 = sns.boxplot(x='onpromotion', y='unit_sales', data=train)\nplt.title(\"Promotion Impact\", fontsize=14, fontweight='bold')\nplt.xlabel(\"OnPromotion\")\nplt.ylabel(\"Unit Sales\")\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_item = train['item_nbr'].sample(1).iloc[0]\nsub = sample_df[sample_df['item_nbr'] == sample_item]\n\nplt.figure(figsize=(12,6))\nsns.scatterplot(x='date', y='unit_sales', hue='onpromotion', data=sub)\nplt.title(f\"Sales Trend for Item {sample_item}\", fontsize=14, fontweight='bold')\nplt.show()","metadata":{"trusted":true,"execution":{"execution_failed":"2026-05-12T09:54:41.183Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"promo_df = sample_df.merge(items[['item_nbr', 'family']], on='item_nbr', how='left')\n\nfamily_promo = promo_df.groupby(['family', 'onpromotion'], as_index=False)['unit_sales'].mean()\n\ntop_family = promo_df.groupby('family', as_index=False)['unit_sales'].sum() \\\n                     .sort_values('unit_sales', ascending=False) \\\n                     .head(15)\n\nfamily_promo_top = family_promo[family_promo['family'].isin(top_family['family'])]\n\nfamily_promo_pivot = family_promo_top.pivot(index='family', columns='onpromotion', values='unit_sales')\n\nprint(family_promo_pivot)\n\nplt.figure(figsize=(12,6))\nsns.heatmap(family_promo_pivot, cmap='RdYlGn', annot=True, fmt='.2f')\nplt.title('Average Sales by Family and Promotion Status', fontsize=14, fontweight='bold')\nplt.xlabel('On Promotion')\nplt.ylabel('Family')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:15:09.296765Z","iopub.execute_input":"2026-05-12T19:15:09.297540Z","iopub.status.idle":"2026-05-12T19:15:10.457190Z","shell.execute_reply.started":"2026-05-12T19:15:09.297507Z","shell.execute_reply":"2026-05-12T19:15:10.456517Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Promotion không xuất hiện thường xuyên, nhưng mỗi lần xuất hiện lại có khả năng làm tăng doanh số trung bình khá mạnh ở nhiều nhóm sản phẩm.**","metadata":{}},{"cell_type":"markdown","source":"Biểu đồ heatmap cho thấy promotion có tác động khác nhau lên từng nhóm sản phẩm (family), tuy nhiên phần lớn các nhóm đều ghi nhận mức doanh số trung bình cao hơn khi được khuyến mãi (On Promotion = True). Một số nhóm sản phẩm có mức tăng trưởng rất mạnh khi áp dụng promotion, nổi bật như:\n- BEVERAGES tăng từ 11.91 lên 21.93 (~84%)\n- PRODUCE tăng từ 16.31 lên 21.81\n- FROZEN FOODS tăng từ 8.48 lên 14.22\n- GROCERY I tăng từ 7.34 lên 12.51\n- CLEANING tăng mạnh từ 5.57 lên 9.39\n\nĐiều này cho thấy các nhóm sản phẩm tiêu dùng nhanh và thiết yếu phản ứng rất mạnh với các chương trình promotion. Người tiêu dùng có xu hướng mua tích trữ nhiều hơn khi các mặt hàng thực phẩm, đồ uống hoặc hàng tiêu dùng được giảm giá.\n\nNgược lại, một số nhóm có mức thay đổi nhỏ hoặc gần như không tăng đáng kể, ví dụ:\n- DAIRY chỉ tăng nhẹ từ 7.19 lên 7.34\n- DELI tăng từ 5.80 lên 6.11\n- PREPARED FOODS gần như không đổi, thậm chí giảm nhẹ từ 11.11 xuống 10.86\n\nCó thể thấy không phải tất cả các nhóm sản phẩm đều hưởng lợi giống nhau từ promotion. Một số nhóm có nhu cầu ổn định tự nhiên nên promotion không tạo khác biệt lớn, trong khi các nhóm tiêu dùng nhanh có độ nhạy giá cao hơn nhiều.\n\nĐối với forecasting model, đây là insight rất quan trọng vì nó cho thấy tồn tại sự tương tác mạnh giữa family và onpromotion. Do đó, nếu chỉ sử dụng feature promotion đơn lẻ mà không kết hợp với family, mô hình có thể bỏ lỡ nhiều tín hiệu quan trọng. Vì vậy nên **tạo thêm các interaction features như: family x promotion, promotion intensity theo family, rolling promotion effect theo family** để giúp mô hình học chính xác hơn hành vi tiêu dùng của từng nhóm sản phẩm.\n\n**Từ góc nhìn kinh doanh** giúp doanh nghiệp xác định nhóm sản phẩm nào phản ứng mạnh nhất với promotion để tối ưu ngân sách marketing và chiến lược giảm giá. Thay vì triển khai promotion đại trà, doanh nghiệp có thể tập trung vào các nhóm có mức tăng trưởng doanh số cao như BEVERAGES, PRODUCE hoặc FROZEN FOODS nhằm tối đa hóa hiệu quả doanh thu và lợi nhuận.","metadata":{}},{"cell_type":"markdown","source":"## **External Factors**","metadata":{}},{"cell_type":"code","source":"daily_sales = sample_df.groupby('date')['unit_sales'].sum().reset_index()\n\ndaily_sales['date'] = pd.to_datetime(daily_sales['date'])\noil_use = oil.copy()\noil_use['date'] = pd.to_datetime(oil_use['date'])\noil_use = oil_use.rename(columns={'dcoilwtico': 'oil_price'})\n\ndaily_sales_oil = daily_sales.merge(\n    oil_use[['date', 'oil_price']],\n    on='date',\n    how='left'\n)\n\n# Xử lý các ngày giá dầu bị thiếu (do cuối tuần/lễ) bằng nội suy\ndaily_sales_oil['oil_price'] = daily_sales_oil['oil_price'].interpolate()\n\nfig, axis_left = plt.subplots(figsize=(14, 6))\n\nsns.lineplot(data=daily_sales_oil, x='date', y='unit_sales', ax=axis_left, color='blue', label='Total Sales')\naxis_left.set_ylabel('Total Sales', color='blue')\naxis_left.tick_params(axis='y', labelcolor='blue')\n\naxis_right = axis_left.twinx()\nsns.lineplot(data=daily_sales_oil, x='date', y='oil_price', ax=axis_right, color='red', label='Oil Price')\naxis_right.set_ylabel('Oil Price', color='red')\naxis_right.tick_params(axis='y', labelcolor='red')\n\nplt.title('Daily Sales and Oil Price Over Time', fontsize=14, fontweight='bold')\nplt.show()\n\ncorr = daily_sales_oil['unit_sales'].corr(daily_sales_oil['oil_price'])\nprint(f\"Correlation coefficient: {corr:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:17:25.694555Z","iopub.execute_input":"2026-05-12T19:17:25.695315Z","iopub.status.idle":"2026-05-12T19:17:26.010489Z","shell.execute_reply.started":"2026-05-12T19:17:25.695285Z","shell.execute_reply":"2026-05-12T19:17:26.009911Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy xu hướng biến động giữa doanh số bán hàng (unit_sales) và giá dầu (oil_price) trong giai đoạn 2013 - 2017. Giá dầu (đường đỏ) giảm rất mạnh từ khoảng 100 USD vào năm 2014 xuống gần 30 USD vào đầu năm 2016, sau đó dao động quanh mức 40 - 50 USD trong các năm tiếp theo. Trong khi đó, tổng doanh số bán hàng (đường xanh) lại có xu hướng tăng dần theo thời gian, từ khoảng 300,000 - 500,000 trong năm 2013 lên mức thường xuyên dao động quanh 700,000 - 1,000,000 units vào giai đoạn 2016 - 2017.\n\nĐiều đáng chú ý là khi giá dầu giảm mạnh trong giai đoạn 2014 - 2016, doanh số bán hàng không giảm theo mà ngược lại còn tăng lên đáng kể. Ví dụ:\n- Năm 2014: giá dầu vẫn quanh mức 90 - 100 USD, doanh số chủ yếu dao động dưới 700,000.\n- Đầu năm 2016: giá dầu giảm xuống gần 30 USD, trong khi doanh số nhiều thời điểm vượt 1 triệu.\n\nĐiều này cho thấy mối quan hệ giữa giá dầu và doanh số bán lẻ không phải là tương quan tuyến tính trực tiếp. Giá dầu có thể ảnh hưởng gián tiếp đến nền kinh tế thông qua:\n- chi phí vận chuyển\n- lạm phát\n- sức mua người tiêu dùng\n- mức chi tiêu hộ gia đình\n\nKhi giá dầu giảm mạnh:\n- chi phí vận hành và vận chuyển có thể giảm\n- giá hàng hóa ổn định hơn\n- người tiêu dùng có thể tăng chi tiêu\n\n-> từ đó hỗ trợ tăng trưởng doanh số bán lẻ\n\nNgược lại, khi giá dầu tăng mạnh:\n- áp lực chi phí logistics tăng\n- giá hàng hóa tăng theo\n- sức mua thị trường có thể suy giảm\n\n-> tạo ảnh hưởng tiêu cực lên hoạt động bán lẻ trong dài hạn.\n\nTuy nhiên, doanh số bán lẻ còn chịu tác động mạnh hơn từ: seasonality, promotion, holidays, tăng trưởng hệ thống cửa hàng, và hành vi tiêu dùng theo thời gian.\n\nInsight này cho thấy trong bài toán forecasting, oil_price nên được xem là một external feature hỗ trợ giúp mô hình học được các biến động kinh tế dài hạn thay vì là yếu tố quyết định trực tiếp doanh số.\n\nTừ góc nhìn kinh doanh cho thấy doanh nghiệp không chỉ cần theo dõi dữ liệu bán hàng nội bộ mà còn phải quan tâm đến các yếu tố kinh tế bên ngoài như giá dầu. Biến động mạnh của oil price có thể ảnh hưởng trực tiếp đến: chi phí logistics, chuỗi cung ứng, giá thành sản phẩm, và chiến lược pricing. Việc hiểu được mối quan hệ giữa giá dầu và hành vi tiêu dùng sẽ giúp doanh nghiệp:\n- tối ưu kế hoạch nhập hàng\n- dự báo chi phí vận hành\n- xây dựng chiến lược giá phù hợp\n- chủ động thích ứng với các biến động kinh tế trong dài hạn","metadata":{}},{"cell_type":"code","source":"item_sales_full = train.groupby('item_nbr')['unit_sales'].sum().reset_index()\n\ndf_combined_full = item_sales_full.merge(items[['item_nbr', 'family']], on='item_nbr', how='left')\n\nfamily_sales = df_combined_full.groupby('family')['unit_sales'].mean().sort_values(ascending=False)\n\ntop_families = family_sales.head(10).sort_values(ascending=True)\n\nplt.figure(figsize=(10, 6))\nax = top_families.plot(kind='barh')\n\nfor container in ax.containers:\n    ax.bar_label(container, fmt='%.2f', padding=5)\n\nplt.title(\"Top 10 Families by Average Unit Sales\", fontsize=14, fontweight='bold')\nplt.xlabel(\"Average Unit Sales\")\nplt.ylabel(\"Family\")                      \nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:12:28.868846Z","iopub.execute_input":"2026-05-12T19:12:28.869259Z","iopub.status.idle":"2026-05-12T19:12:31.601067Z","shell.execute_reply.started":"2026-05-12T19:12:28.869231Z","shell.execute_reply":"2026-05-12T19:12:31.600392Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy doanh số trung bình phân bố không đồng đều giữa các nhóm sản phẩm và tập trung mạnh vào các mặt hàng thực phẩm thiết yếu. Trong đó, nhóm POULTRY có doanh số trung bình cao nhất với khoảng 590,296 cao vượt trội so với các nhóm còn lại. Đứng thứ hai là PRODUCE với khoảng 400,996 tiếp theo là: EGGS: ~ 380,202, MEATS: ~ 370,077, BEVERAGES: ~ 359,176. Trong khi đó, các nhóm như: DELI (~ 264,949), GROCERY I (~ 266,249), DAIRY (~ 266,476)\ncó mức doanh số trung bình thấp hơn đáng kể. Chênh lệch giữa nhóm cao nhất (POULTRY) và nhóm thấp nhất trong top 10 (DELI) lên tới hơn 325,000 cho thấy nhu cầu tiêu dùng giữa các nhóm sản phẩm khác nhau rất lớn.\n\nPhản ánh rõ hành vi tiêu dùng trong ngành bán lẻ: các sản phẩm thực phẩm tươi sống và thiết yếu như thịt gia cầm, rau củ, trứng và thịt có nhu cầu ổn định và tần suất mua cao hơn nhiều so với các nhóm sản phẩm khác. Đây là những mặt hàng phục vụ nhu cầu sinh hoạt hàng ngày nên có tốc độ quay vòng lớn và đóng vai trò quan trọng trong tổng doanh thu hệ thống bán lẻ. Ngoài ra, các nhóm như: POULTRY, PRODUCE, MEATS không chỉ có doanh số cao mà còn thường nhạy cảm với: seasonality, holiday demand, biến động giá cả thị trường. Ví dụ:\n- nhu cầu thịt và thực phẩm tươi sống thường tăng mạnh vào cuối tuần hoặc dịp lễ\n- rau củ và thực phẩm thiết yếu có mức tiêu thụ ổn định quanh năm\n- đồ uống (BEVERAGES) dễ tăng mạnh trong mùa nóng hoặc các campaign promotion\n\nĐối với forecasting model, thấy feature family có vai trò cực kỳ quan trọng vì mỗi nhóm sản phẩm có: mức cầu khác nhau, volatility khác nhau, seasonal pattern khác nhau, và mức độ phản ứng với promotion khác nhau. Nếu mô hình không phân biệt hành vi giữa các family, forecasting accuracy sẽ giảm đáng kể, đặc biệt ở các nhóm có demand cao như POULTRY hoặc PRODUCE. Do đó cần:\n- encoding family features\n- tạo interaction giữa family và promotion\n- xây dựng lag features riêng theo từng family\n- thậm chí huấn luyện specialized models cho các nhóm sản phẩm lớn\n\nNgoài ra, biểu đồ cũng cho thấy dữ liệu có khả năng tồn tại hiện tượng demand imbalance giữa các nhóm sản phẩm. Các family có doanh số quá lớn có thể chi phối loss function của mô hình, khiến model học thiên lệch về các nhóm bán chạy và dự báo kém cho các nhóm nhỏ hơn. Đây là lý do cần cân nhắc: weighted loss, log transformation, hoặc hierarchical forecasting.\n\n**Từ góc nhìn kinh doanh** biểu đồ cho thấy các nhóm thực phẩm thiết yếu như POULTRY, PRODUCE, EGGS và MEATS đang đóng vai trò cốt lõi trong doanh thu của hệ thống bán lẻ, với doanh số trung bình cao vượt trội so với các nhóm sản phẩm khác. Điều này cho thấy nhu cầu tiêu dùng của khách hàng tập trung mạnh vào các mặt hàng phục vụ sinh hoạt hằng ngày, vì vậy doanh nghiệp cần ưu tiên quản lý tồn kho, chuỗi cung ứng và forecasting cho các nhóm sản phẩm này để tránh thiếu hàng trong các giai đoạn nhu cầu cao. Đồng thời, việc mỗi nhóm sản phẩm có mức doanh số và hành vi tiêu dùng khác nhau cũng giúp doanh nghiệp xây dựng chiến lược marketing và promotion phù hợp hơn cho từng nhóm thay vì triển khai đồng loạt, từ đó tối ưu doanh thu, chi phí vận hành và hiệu quả kinh doanh tổng thể.","metadata":{}},{"cell_type":"code","source":"# 1. Tính tổng số giao dịch của toàn hệ thống theo từng ngày từ bảng transactions\ndaily_tx = transactions.groupby('date')['transactions'].sum().reset_index()\n\n# 2. Lấy danh sách ngày lễ (loại bỏ các ngày bị trùng lặp)\nholiday_dates = holidays[['date']].drop_duplicates()\nholiday_dates['is_holiday'] = 'Holiday'\n\n# 3. Gộp bảng giao dịch với bảng ngày lễ\ntx_holiday_check = daily_tx.merge(holiday_dates, on='date', how='left')\n\n# 4. Những ngày không khớp trúng ngày lễ sẽ được điền là 'Normal Day'\ntx_holiday_check['is_holiday'] = tx_holiday_check['is_holiday'].fillna('Normal Day')\n\nplt.figure(figsize=(10, 6))\n\nsns.barplot(\n    data=tx_holiday_check, \n    x='is_holiday', \n    y='transactions', \n    hue='is_holiday',\n    errorbar=None, \n    alpha=0.3, \n    palette='Set2',\n    legend=False\n)\n\n# Rải tất cả các ngày thực tế thành các hạt chấm (Mỗi chấm là 1 ngày)\nsns.stripplot(\n    data=tx_holiday_check, \n    x='is_holiday', \n    y='transactions', \n    hue='is_holiday',\n    jitter=0.25, \n    size=4, \n    alpha=0.5, \n    palette='Set2',\n    legend=False\n)\n\nsystem_mean = tx_holiday_check['transactions'].mean()\nplt.axhline(system_mean, color='red', linestyle='--', alpha=0.6, label='System Average')\n\nplt.title(\"Supermarket Traffic Normal Days vs Holidays\", fontsize=14, fontweight='bold')\nplt.xlabel(\"Day Type\")\nplt.ylabel(\"Total System-wide Transactions\") \n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:12:36.334640Z","iopub.execute_input":"2026-05-12T19:12:36.335063Z","iopub.status.idle":"2026-05-12T19:12:36.551189Z","shell.execute_reply.started":"2026-05-12T19:12:36.335033Z","shell.execute_reply":"2026-05-12T19:12:36.550614Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy số lượng giao dịch trong siêu thị giữa ngày thường và ngày lễ có sự khác biệt khá rõ về mức độ biến động. Mặc dù giá trị trung bình của hai nhóm không chênh lệch quá lớn và đều dao động quanh mức 80,000 - 85,000 transactions, nhưng các ngày lễ (Holiday) xuất hiện nhiều điểm giao dịch đột biến hơn đáng kể. Cụ thể:\n- Ở ngày thường (Normal Day), phần lớn giao dịch tập trung trong khoảng 70,000 - 100,000 transactions và ít xuất hiện các giá trị cực lớn.\n- Trong khi đó, ở ngày lễ (Holiday), ngoài vùng giao dịch phổ biến khoảng 75,000 - 95,000, còn xuất hiện nhiều spike lớn vượt: 120,000 transactions, 140,000 transactions, thậm chí gần 170,000 transactions. Điều này cho thấy ngày lễ không nhất thiết làm tăng mạnh mức giao dịch trung bình toàn hệ thống, nhưng lại làm tăng đáng kể volatility và khả năng xuất hiện các demand spikes bất thường.\n\nPhản ánh hành vi mua sắm của người tiêu dùng trong các dịp đặc biệt: khách hàng có xu hướng mua sắm tập trung, mua tích trữ, hoặc tăng chi tiêu trước và trong các kỳ nghỉ.\n\nTuy nhiên, không phải tất cả ngày lễ đều tạo ra lưu lượng khách cao giống nhau, dẫn đến phân phối transactions trong nhóm Holiday phân tán mạnh hơn so với ngày thường.\n\nĐối với forecasting model, đây là biểu đồ rất quan trọng vì nó cho thấy feature holiday có thể không tạo ra mức tăng trung bình lớn, nhưng lại ảnh hưởng mạnh đến: variance, volatility, và extreme demand events. Nếu mô hình không học được holiday effects, khả năng dự báo trong các giai đoạn cao điểm sẽ giảm đáng kể và dễ dẫn đến sai số lớn ở các spike transactions. Vì vậy cần: encode holiday features, phân loại holiday type, tạo feature days_before_holiday, và kết hợp holiday với promotion hoặc weekend features.\n\n**Từ góc nhìn kinh doanh** cho thấy doanh nghiệp cần đặc biệt chú trọng đến khả năng xử lý các đợt tăng đột biến lưu lượng khách trong ngày lễ thay vì chỉ tập trung vào mức trung bình doanh số. Các giai đoạn holiday có thể tạo ra áp lực lớn lên: tồn kho, nhân sự, quầy thanh toán, logistics, và chuỗi cung ứng. Do đó, doanh nghiệp cần chuẩn bị hàng hóa, tăng cường nhân sự vận hành và tối ưu hệ thống cung ứng trước các dịp lễ lớn nhằm tránh tình trạng quá tải hoặc thiếu hàng. Đồng thời, việc hiểu được mức độ biến động của traffic trong ngày lễ cũng giúp doanh nghiệp xây dựng các chiến lược promotion và phân bổ nguồn lực hiệu quả hơn cho từng mùa cao điểm tiêu dùng.","metadata":{}},{"cell_type":"code","source":"# Bước 1: Tính tổng doanh số theo từng NGÀY trên bảng train gốc\n# Lệnh này nén 125 triệu dòng về còn ~1,700 dòng, cực kỳ nhẹ!\ndaily_sales_full = train.groupby('date')['unit_sales'].sum().reset_index()\n\n# Đảm bảo cột date của cả hai bảng ở cùng định dạng datetime trước khi merge\ndaily_sales_full['date'] = pd.to_datetime(daily_sales_full['date'])\nholidays['date'] = pd.to_datetime(holidays['date'])\n\n# Bước 2: Chỉ lấy các cột cần thiết từ bảng holidays và loại bỏ các dòng trùng ngày \n# (Tránh việc một ngày có nhiều lễ làm phóng đại doanh số)\nholiday_types = holidays[['date', 'type']].drop_duplicates(subset=['date'])\n\n# Bước 3: Merge bảng doanh số ngày với bảng loại ngày lễ\ndf_holiday_type = daily_sales_full.merge(holiday_types, on='date', how='inner')\n\n# Bước 4: Gom nhóm theo 'type' (Loại ngày lễ) để tính doanh số trung bình\nholiday_type_sales = df_holiday_type.groupby('type')['unit_sales'].mean().sort_values(ascending=False)\n\n# Bước 5: Trực quan hóa biểu đồ cột (Bar chart) giống hệt cấu trúc của bạn\nplt.figure(figsize=(10, 5))\nax = holiday_type_sales.plot(kind='bar')\n\n# Dán nhãn số liệu lên đầu mỗi cột\nfor container in ax.containers:\n    ax.bar_label(container, fmt='%.2f', padding=5)\n\nplt.title('Average Daily Sales by Holiday Type', fontsize=14, fontweight='bold')\nplt.xlabel('Holiday Type')\nplt.ylabel('Average Daily Sales')\nplt.xticks(rotation=0) \nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:12:40.687851Z","iopub.execute_input":"2026-05-12T19:12:40.688283Z","iopub.status.idle":"2026-05-12T19:12:43.849375Z","shell.execute_reply.started":"2026-05-12T19:12:40.688253Z","shell.execute_reply":"2026-05-12T19:12:43.848625Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy doanh số trung bình hằng ngày thay đổi đáng kể theo từng loại ngày lễ. Trong đó, nhóm Additional có doanh số cao nhất với khoảng 864,924, tiếp theo là:\n- Transfer: ~831,744\n- Bridge: ~796,110\n- Event: ~754,171\n\nTrong khi đó Holiday chỉ đạt khoảng 628,011 và Work Day thấp nhất với khoảng 596,530. Điều này cho thấy không phải tất cả các ngày lễ đều tác động giống nhau đến hành vi mua sắm của khách hàng. Các loại ngày như Additional, Transfer hay Bridge thường tạo ra mức doanh số cao hơn rất nhiều so với ngày làm việc thông thường, với mức chênh lệch lên tới gần 270,000 giữa Additional và Work Day.\n\nBiểu đồ này phản ánh rằng người tiêu dùng có xu hướng tăng mạnh hoạt động mua sắm trong các giai đoạn nghỉ kéo dài hoặc các ngày nghỉ được nối lịch (bridge/transfer holidays). Khi có thêm thời gian nghỉ, khách hàng thường: mua sắm tích trữ, tăng chi tiêu cho thực phẩm và nhu yếu phẩm hoặc chuẩn bị cho các dịp tụ họp và lễ hội. Đặc biệt, nhóm Additional đạt doanh số cao nhất cho thấy các ngày nghỉ bổ sung có thể kích thích nhu cầu tiêu dùng mạnh hơn cả holiday thông thường. Điều này có thể đến từ việc người tiêu dùng tận dụng các kỳ nghỉ dài để mua sắm nhiều hơn hoặc các doanh nghiệp thường triển khai promotion mạnh trong các giai đoạn này.\n\nĐối với forecasting model, biểu đồ cho thấy feature holiday_type mang rất nhiều thông tin quan trọng thay vì chỉ sử dụng biến nhị phân đơn giản như: holiday = True/False. Mỗi loại holiday tạo ra mức ảnh hưởng khác nhau lên doanh số, vì vậy việc encode chi tiết: Additional, Transfer, Bridge, Event, Holiday sẽ giúp mô hình học tốt hơn seasonal demand patterns và giảm sai số dự báo trong các dịp đặc biệt.\n\n**Từ góc nhìn kinh doanh** giúp doanh nghiệp xác định rõ các giai đoạn có tiềm năng doanh thu cao nhất để chủ động chuẩn bị hàng tồn kho, tăng cường logistics và phân bổ nhân sự phù hợp. Đồng thời, doanh nghiệp cũng có thể tận dụng các ngày Additional hoặc Transfer để triển khai promotion và chiến dịch marketing nhằm tối đa hóa doanh thu, vì đây là những thời điểm khách hàng có xu hướng chi tiêu mạnh hơn đáng kể so với ngày làm việc thông thường.","metadata":{}},{"cell_type":"code","source":"# 1. Đảm bảo cột 'date' của tất cả các bảng phụ đều ở định dạng Datetime chuẩn\noil['date'] = pd.to_datetime(oil['date'])\ntransactions['date'] = pd.to_datetime(transactions['date'])\n\n# 2. Aggregate theo ngày từ bảng train gốc\ndaily = train.groupby('date').agg({\n    'unit_sales': 'sum',\n    'onpromotion': 'sum'\n}).reset_index()\n\n# SỬA LỖI: Ép cột 'date' của bảng daily về lại định dạng ngày tháng chuẩn giống bảng oil\ndaily['date'] = pd.to_datetime(daily['date'])\n\n# 3. Merge thêm bảng oil\ndaily = daily.merge(\n    oil[['date', 'dcoilwtico']],\n    on='date',\n    how='left'\n)\n\n# 4. Tính toán và merge thêm bảng transactions\ntrans_daily = transactions.groupby('date')['transactions'].sum().reset_index()\ntrans_daily['date'] = pd.to_datetime(trans_daily['date']) # Đảm bảo đồng bộ định dạng\n\ndaily = daily.merge(\n    trans_daily,\n    on='date',\n    how='left'\n)\n\n# 5. Điền giá trị trống cho giá dầu (Dùng .ffill() thay cho fillna(method='ffill'))\ndaily['dcoilwtico'] = daily['dcoilwtico'].ffill()\n\n# 6. Vẽ Ma trận tương quan (Correlation matrix) chuẩn của bạn\ncorr = daily[['unit_sales', 'onpromotion', 'transactions', 'dcoilwtico']].corr()\n\nplt.figure(figsize=(8,6))\nsns.heatmap(\n    corr,\n    annot=True,\n    cmap='coolwarm',\n    fmt='.2f'\n)\n\nplt.title('Correlation Heatmap', fontsize=14, fontweight='bold')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:12:48.621041Z","iopub.execute_input":"2026-05-12T19:12:48.621325Z","iopub.status.idle":"2026-05-12T19:13:01.210987Z","shell.execute_reply.started":"2026-05-12T19:12:48.621301Z","shell.execute_reply":"2026-05-12T19:13:01.210093Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ correlation heatmap cho thấy mối quan hệ giữa các yếu tố chính ảnh hưởng đến doanh số bán hàng trong hệ thống bán lẻ. Trong đó, **transactions có tương quan dương mạnh nhất với doanh số với hệ số khoảng 0.68**, cho thấy số lượng giao dịch tăng thường đi kèm với doanh số tăng. Điều này phản ánh rằng lưu lượng khách hàng là một trong những yếu tố tác động trực tiếp và mạnh nhất đến hiệu quả bán hàng của hệ thống siêu thị. \n\nBên cạnh đó, **onpromotion cũng có tương quan dương khá mạnh với unit_sales ở mức khoảng 0.57**, cho thấy các chương trình promotion có khả năng thúc đẩy doanh số đáng kể. Biểu dồ này phù hợp với các phân tích trước đó khi nhiều nhóm sản phẩm ghi nhận mức tăng doanh số rõ rệt trong các giai đoạn có khuyến mãi. Điều này chứng minh promotion là một công cụ kích cầu rất quan trọng trong hoạt động bán lẻ.\n\nNgược lại, biến dcoilwtico (giá dầu) lại có tương quan âm khá mạnh với unit_sales (~ -0.63)\nvà onpromotion (~ -0.62). Điều này cho thấy khi giá dầu tăng, doanh số và hoạt động promotion có xu hướng giảm. Từ góc nhìn kinh doanh, điều này có thể phản ánh ảnh hưởng gián tiếp của giá dầu đến: chi phí vận chuyển, chi phí logistics, giá hàng hóa và sức mua của người tiêu dùng. Khi giá dầu tăng cao, áp lực chi phí vận hành và lạm phát có thể khiến doanh nghiệp giảm cường độ promotion hoặc người tiêu dùng thắt chặt chi tiêu hơn, từ đó làm giảm doanh số bán hàng.\n\nNgoài ra, transactions và onpromotion chỉ có tương quan khoảng 0.20, cho thấy promotion không nhất thiết làm tăng mạnh số lượng khách hàng đến siêu thị mà có thể chủ yếu làm tăng giá trị mua sắm hoặc số lượng sản phẩm trên mỗi giao dịch. Đây là một insight rất quan trọng vì nó cho thấy promotion có thể đang tác động nhiều hơn đến hành vi chi tiêu của khách hàng hiện tại thay vì thu hút thêm lượng lớn khách hàng mới.\n\nĐối với forecasting model, biểu đồ này cho thấy: transactions, onpromotion và dcoilwtico đều là các feature quan trọng cần được giữ lại trong pipeline vì chúng mang tín hiệu khác nhau về hành vi tiêu dùng và điều kiện thị trường. Trong đó:\n- transactions phản ánh nhu cầu thực tế\n- promotion phản ánh hoạt động kích cầu\n- oil price phản ánh yếu tố kinh tế vĩ mô bên ngoài.\n\n**Từ góc nhìn kinh doanh** giúp doanh nghiệp hiểu rõ hơn đâu là các yếu tố ảnh hưởng mạnh nhất đến doanh số để tối ưu chiến lược vận hành. Việc tăng traffic khách hàng và triển khai promotion hiệu quả có thể tạo tác động trực tiếp đến tăng trưởng doanh thu. Đồng thời, doanh nghiệp cũng cần theo dõi các biến động kinh tế như giá dầu để chủ động điều chỉnh chiến lược pricing, logistics và marketing nhằm giảm thiểu rủi ro trong các giai đoạn thị trường biến động mạnh.","metadata":{}},{"cell_type":"markdown","source":"# **Item Analysis**","metadata":{"execution":{"iopub.status.busy":"2026-05-04T07:36:55.780526Z","iopub.status.idle":"2026-05-04T07:36:55.780827Z","shell.execute_reply.started":"2026-05-04T07:36:55.780682Z","shell.execute_reply":"2026-05-04T07:36:55.780699Z"}}},{"cell_type":"code","source":"items.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:07.831558Z","iopub.execute_input":"2026-05-12T19:13:07.832682Z","iopub.status.idle":"2026-05-12T19:13:07.842886Z","shell.execute_reply.started":"2026-05-12T19:13:07.832646Z","shell.execute_reply":"2026-05-12T19:13:07.841870Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"colName = \"family\"\n\nsns.set_theme(style=\"whitegrid\")\nval = items[colName].value_counts().sort_values(ascending=False)\nsumm = val.sum() \n\nplt.figure(figsize=(10, 15))\n\nax = sns.countplot(data=items, y=colName, palette=\"pastel\", hue=\"perishable\", order=val.index)\n\n# Vòng lặp xử lý từng nhóm cột (not perishable và perishable)\nfor container in ax.containers:\n    # Tính % trực tiếp cho từng cột dựa trên chiều rộng (get_width)\n    # Thêm điều kiện 'if v > 0' để tránh hiển thị 0.0% ở những cột trống\n    labels = [f'{(v / summ * 100):.2f}%' if (v := p.get_width()) > 0 else '' for p in container]\n    \n    # Gán nhãn bằng list labels vừa tạo\n    ax.bar_label(container, labels=labels, padding=3, fontsize=9)\n\nplt.legend([\"not perishable\", \"perishable\"], loc='lower right')\nplt.title(\"Distribution of Perishable Items\", fontsize=14, fontweight='bold')\nplt.xlabel(\"Count\")\nplt.ylabel(colName)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:10.276165Z","iopub.execute_input":"2026-05-12T19:13:10.276498Z","iopub.status.idle":"2026-05-12T19:13:10.828245Z","shell.execute_reply.started":"2026-05-12T19:13:10.276453Z","shell.execute_reply":"2026-05-12T19:13:10.827659Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy sự phân bố giữa các nhóm sản phẩm dễ hỏng (perishable) và không dễ hỏng (not perishable) trong hệ thống bán lẻ là rất không đồng đều. Nhóm **GROCERY I chiếm tỷ trọng lớn nhất với khoảng 32.54% tổng số sản phẩm**, vượt xa tất cả các nhóm còn lại và chủ yếu thuộc nhóm không dễ hỏng. \n\nTiếp theo là: BEVERAGES (~ 14.95%), CLEANING (~ 10.88%) đây đều là các nhóm sản phẩm có thời gian bảo quản dài và nhu cầu tiêu dùng ổn định. Điều này phản ánh rằng phần lớn danh mục sản phẩm của hệ thống bán lẻ tập trung vào các mặt hàng tiêu dùng thường xuyên, có vòng đời dài và ít rủi ro hư hỏng. \n\nTrong khi đó, các nhóm sản phẩm dễ hỏng như: PRODUCE (~ 7.46%), DAIRY (~ 5.90%), MEATS, POULTRY, SEAFOOD chiếm tỷ trọng nhỏ hơn đáng kể nhưng lại mang đặc điểm kinh doanh hoàn toàn khác. Đây là các nhóm sản phẩm có:\nshelf-life ngắn, demand volatility cao và rủi ro tồn kho lớn hơn nhiều so với non-perishable items. \n\nMặc dù tỷ trọng không quá lớn, các nhóm perishable lại thường đóng vai trò rất quan trọng trong doanh thu và trải nghiệm khách hàng vì đây là các mặt hàng thiết yếu được mua thường xuyên.\n\nBiểu đồ này phản ánh rõ sự khác biệt trong chiến lược vận hành giữa hai loại sản phẩm: \n- Non-perishable items giúp duy trì nguồn doanh thu ổn định và dễ quản lý tồn kho.\n- Perishable items yêu cầu forecasting chính xác hơn vì chỉ cần dự báo sai một lượng nhỏ cũng có thể dẫn đến: thiếu hàng, hư hỏng hoặc lãng phí tồn kho rất lớn.\n\nĐối với forecasting model, feature perishable là cực kỳ quan trọng vì hành vi bán hàng giữa hai nhóm sản phẩm này khác nhau rõ rệt. Các sản phẩm perishable thường: nhạy cảm hơn với holidays, promotion, thời tiết và seasonality. Ngoài ra, demand của nhóm này thường biến động mạnh hơn theo ngày và có độ decay cao hơn nếu tồn kho quá lâu. Điều này cho thấy mô hình forecasting cần:\n- phân biệt rõ perishable/non-perishable\n- xây dựng lag features riêng\n- áp dụng weighted training cho nhóm perishable vì sai số dự báo ở các sản phẩm này gây tổn thất kinh doanh lớn hơn.\n\n**Từ góc nhìn kinh doanh** giúp doanh nghiệp hiểu rằng mặc dù nhóm non-perishable chiếm phần lớn danh mục sản phẩm và mang lại sự ổn định trong vận hành, nhưng các sản phẩm perishable mới là nhóm cần được quản lý chặt chẽ nhất trong forecasting và supply chain. Doanh nghiệp cần tối ưu replenishment cycle, tồn kho, logistics lạnh và promotion timing cho các nhóm sản phẩm dễ hỏng nhằm giảm waste, hạn chế stock - out và tối đa hóa lợi nhuận. Đồng thời, việc hiểu rõ tỷ trọng từng family cũng giúp doanh nghiệp phân bổ nguồn lực và chiến lược vận hành phù hợp hơn cho từng nhóm sản phẩm trong hệ thống bán lẻ.","metadata":{}},{"cell_type":"code","source":"top_items = train.groupby('item_nbr')['unit_sales'].sum().nlargest(10)\n\nplt.figure(figsize=(12, 5))\nax = top_items.sort_values().plot(kind='barh', color='salmon')\n\nfor container in ax.containers:\n    ax.bar_label(container, fmt='%.2f', padding=3)\n\nplt.title('Top 10 Selling Items', fontsize=14, fontweight='bold')\nplt.ylabel('Item Number')\nplt.xlabel('Total Unit Sales')\nplt.xticks(rotation=0)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:16.086226Z","iopub.execute_input":"2026-05-12T19:13:16.086562Z","iopub.status.idle":"2026-05-12T19:13:18.765848Z","shell.execute_reply.started":"2026-05-12T19:13:16.086534Z","shell.execute_reply":"2026-05-12T19:13:18.765188Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy doanh số bán hàng tập trung rất mạnh vào một số ít sản phẩm nổi bật trong hệ thống bán lẻ. Item có doanh số cao nhất đạt khoảng 6.26 triệu, trong khi các item còn lại trong top 10 dao động từ khoảng 3.54 triệu đến 5.51 triệu. Chênh lệch hơn 2.7 triệu giữa item đứng đầu và item cuối top 10 cho thấy mức độ không đồng đều rất lớn trong nhu cầu tiêu dùng giữa các sản phẩm.\n\nTừ góc nhìn kinh doanh cho thấy doanh nghiệp cần ưu tiên đặc biệt cho nhóm sản phẩm bán chạy nhất vì đây là các item ảnh hưởng trực tiếp đến doanh thu toàn hệ thống. Việc forecasting chính xác, tối ưu tồn kho và đảm bảo nguồn cung ổn định cho các sản phẩm này quan trọng hơn rất nhiều so với các item có demand thấp. Đồng thời, doanh nghiệp cũng có thể tập trung promotion, tối ưu trưng bày và chiến lược pricing cho các top-selling items nhằm tối đa hóa doanh thu và duy trì lợi thế cạnh tranh trong hệ thống bán lẻ.","metadata":{}},{"cell_type":"markdown","source":"# **Store Analysis**","metadata":{}},{"cell_type":"code","source":"def show_countplot(store, colName: str):\n    sns.set_theme(style=\"whitegrid\")\n    \n    # Tính toán giá trị để sắp xếp và tính tổng\n    val = store[colName].value_counts().sort_values(ascending=False)\n    summ = val.sum()\n\n    plt.figure(figsize=(10, len(val) * 0.5 + 2)) \n\n    ax = sns.countplot(data=store, y=colName, palette=\"pastel\", order=val.index)\n\n    for container in ax.containers:\n        # Lấy giá trị v (width) của từng cột để tính % dựa trên tổng summ\n        labels = [f'{(v / summ * 100):.2f}%' if (v := p.get_width()) > 0 else '' for p in container]\n        \n        # Dán nhãn vào biểu đồ\n        ax.bar_label(container, labels=labels, padding=5)\n\n    plt.title(f\"Distribution of {colName} (%)\", fontsize=14, fontweight='bold')\n    plt.xlabel(\"Count\")\n    plt.ylabel(colName)\n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:21.678315Z","iopub.execute_input":"2026-05-12T19:13:21.678942Z","iopub.status.idle":"2026-05-12T19:13:21.684824Z","shell.execute_reply.started":"2026-05-12T19:13:21.678913Z","shell.execute_reply":"2026-05-12T19:13:21.683887Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"show_countplot(stores, \"state\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:24.438067Z","iopub.execute_input":"2026-05-12T19:13:24.438791Z","iopub.status.idle":"2026-05-12T19:13:25.404323Z","shell.execute_reply.started":"2026-05-12T19:13:24.438762Z","shell.execute_reply":"2026-05-12T19:13:25.403737Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"show_countplot(stores, \"city\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:28.779607Z","iopub.execute_input":"2026-05-12T19:13:28.780083Z","iopub.status.idle":"2026-05-12T19:13:29.271343Z","shell.execute_reply.started":"2026-05-12T19:13:28.780047Z","shell.execute_reply":"2026-05-12T19:13:29.270682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"show_countplot(stores, \"cluster\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:32.478303Z","iopub.execute_input":"2026-05-12T19:13:32.478971Z","iopub.status.idle":"2026-05-12T19:13:32.818139Z","shell.execute_reply.started":"2026-05-12T19:13:32.478939Z","shell.execute_reply":"2026-05-12T19:13:32.817517Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"show_countplot(stores, \"type\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:38.540943Z","iopub.execute_input":"2026-05-12T19:13:38.541694Z","iopub.status.idle":"2026-05-12T19:13:38.716061Z","shell.execute_reply.started":"2026-05-12T19:13:38.541662Z","shell.execute_reply":"2026-05-12T19:13:38.715500Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Bốn biểu đồ cho thấy hệ thống cửa hàng của doanh nghiệp có sự tập trung rất rõ theo cả vị trí địa lý (state, city) và đặc điểm vận hành (cluster, type). Điều này phản ánh chiến lược mở rộng không đồng đều mà tập trung mạnh vào các khu vực và mô hình cửa hàng có tiềm năng doanh thu cao nhất.\n\n**Về mặt địa lý** hệ thống cửa hàng tập trung chủ yếu tại các trung tâm kinh tế lớn của Ecuador. Bang Pichincha chiếm khoảng 35.19% tổng số cửa hàng trong khi thành phố Quito riêng lẻ đã chiếm khoảng 33.33% toàn hệ thống. Bên cạnh đó, Guayas và Guayaquil cũng đóng vai trò rất quan trọng với tỷ trọng lần lượt khoảng 20.37% và 14.81%. Chỉ riêng các khu vực này đã chiếm hơn một nửa số lượng cửa hàng, cho thấy doanh nghiệp đang ưu tiên mở rộng tại những nơi có: mật độ dân số cao, sức mua lớn, hạ tầng thương mại phát triển và nhu cầu tiêu dùng mạnh. Điều này giúp doanh nghiệp tối ưu: logistics, chi phí phân phối, chuỗi cung ứng và khả năng triển khai promotion quy mô lớn.\n\nTuy nhiên, mức độ tập trung cao vào một số khu vực trọng điểm cũng tạo ra rủi ro phụ thuộc thị trường. Nếu nhu cầu tiêu dùng hoặc tình hình kinh tế tại Quito hay Guayaquil biến động mạnh, doanh thu toàn hệ thống có thể bị ảnh hưởng đáng kể. \n\nNgoài yếu tố địa lý, **biểu đồ cluster** cho thấy các cửa hàng được phân bổ theo nhiều cụm khác nhau nhưng không đồng đều. Một số cluster như: Cluster 3 (~ 12.96%), Cluster 10 và 6 (~ 11.11%) chiếm tỷ trọng lớn hơn đáng kể so với nhiều cluster khác chỉ khoảng 1.85% – 3.70%. Điều này cho thấy doanh nghiệp đang tập trung vào một số mô hình vận hành hoặc nhóm khách hàng nhất định có hiệu quả kinh doanh cao hơn. Các cluster nhiều khả năng phản ánh:\n- mức thu nhập khu vực\n- hành vi tiêu dùng\n- quy mô cửa hàng\n- mô hình bán lẻ khác nhau\n\nBên cạnh đó, **phân bố theo store type** cũng cho thấy hệ thống nghiêng mạnh về các loại cửa hàng: Type D (~ 33.33%), Type C (~ 27.78%) trong khi các loại như Type E chỉ chiếm khoảng 7.41%. Biểu đồ này phản ánh doanh nghiệp đang ưu tiên các mô hình cửa hàng phù hợp với:\n- khu vực đông dân\n- lưu lượng khách cao\n- khả năng tạo doanh thu lớn hơn\n\n**Góc nhìn kinh doanh** có thể thấy toàn bộ các biểu đồ cho thấy doanh nghiệp đang áp dụng chiến lược: tập trung nguồn lực vào các khu vực và mô hình cửa hàng mang lại hiệu quả cao nhất thay vì mở rộng đồng đều trên toàn hệ thống.\n\n**Chiến lược này giúp:** tối ưu vận hành, tăng hiệu quả logistics, giảm chi phí quản lý và tối đa hóa doanh thu tại các thị trường trọng điểm.\n\nTuy nhiên cũng cho thấy **nhu cầu xây dựng chiến lược forecasting và vận hành riêng cho từng: khu vực, cluster và store type.** Bởi hành vi tiêu dùng giữa các thành phố, nhóm khách hàng và mô hình cửa hàng có thể khác nhau rất lớn về:\n- seasonal demand\n- promotion response\n- traffic pattern\n- purchasing power\n\nDo đó, việc sử dụng một mô hình forecasting chung cho toàn hệ thống có thể không đủ hiệu quả. Thay vào đó, doanh nghiệp nên: segment forecasting theo cluster hoặc store type, tối ưu tồn kho theo khu vực và triển khai promotion phù hợp cho từng nhóm cửa hàng để cải thiện forecasting accuracy và tối ưu hiệu quả kinh doanh toàn hệ thống.","metadata":{}},{"cell_type":"code","source":"df = stores\nx_var= \"state\"\ny_var= \"type\"\n\nplt.figure(figsize=(5, 5))\ndf_grouped = df.groupby(x_var)[y_var].value_counts(normalize=True).unstack(y_var)\ndf_grouped=df_grouped.fillna(0)\ncolorr=sns.color_palette(\"pastel\",n_colors=df_grouped.shape[1])\ndf_grouped.plot.barh(stacked=True,color=colorr )\n\nplt.legend(loc='center left', bbox_to_anchor=(1, 0.5))\nfor ix, row in df_grouped.reset_index(drop=True).iterrows():\n    cumulative = 0\n    for element in row:\n        if element == element and element > 0.1 and (element is not None):\n            plt.text(\n                cumulative + element / 2,\n\n                ix,\n                f\"{int(element * 100)} %\",\n                va=\"center\",\n                ha=\"center\",\n                fontsize=10,\n            )\n        cumulative += element\nplt.title(\"Percent distribution of type in states\", fontsize=14, fontweight='bold')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:41.949805Z","iopub.execute_input":"2026-05-12T19:13:41.950623Z","iopub.status.idle":"2026-05-12T19:13:42.292943Z","shell.execute_reply.started":"2026-05-12T19:13:41.950592Z","shell.execute_reply":"2026-05-12T19:13:42.292204Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy chiến lược triển khai loại cửa hàng giữa các bang có sự khác biệt rất rõ rệt. Một số bang như: Bolivar, Chimborazo, Cotopaxi, Imbabura, Pastaza gần như chỉ sử dụng duy nhất Type C (100%), cho thấy doanh nghiệp đang áp dụng mô hình cửa hàng tiêu chuẩn hóa tại các khu vực nhỏ nhằm tối ưu vận hành và giảm chi phí quản lý.\n\nNgược lại, các bang lớn như Pichincha, Guayas lại có cơ cấu store type đa dạng hơn nhiều với sự xuất hiện của nhiều loại cửa hàng khác nhau. Điều này phản ánh rằng tại các thị trường lớn, doanh nghiệp cần nhiều mô hình cửa hàng để phục vụ các nhóm khách hàng và nhu cầu tiêu dùng đa dạng hơn.\n\nTừ góc nhìn kinh doanh, có thể thấy doanh nghiệp đang áp dụng chiến lược:\n- standardization ở thị trường nhỏ\n- diversification ở thị trường lớn.\n\nĐiều này giúp tối ưu hiệu quả vận hành tại từng khu vực thay vì sử dụng cùng một mô hình cửa hàng cho toàn bộ hệ thống bán lẻ.","metadata":{}},{"cell_type":"markdown","source":"# **Oil Analysis**","metadata":{}},{"cell_type":"code","source":"oil.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:46.247669Z","iopub.execute_input":"2026-05-12T19:13:46.248476Z","iopub.status.idle":"2026-05-12T19:13:46.256946Z","shell.execute_reply.started":"2026-05-12T19:13:46.248436Z","shell.execute_reply":"2026-05-12T19:13:46.256290Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =====================================================================\n# BIỂU ĐỒ 1: Giá dầu theo thời gian (Sử dụng Rolling Mean thay cho LOESS)\n# =====================================================================\nplt.figure(figsize=(14, 5))\n\n# 1. Vẽ đường dữ liệu gốc\nsns.lineplot(data=oil, x=\"date\", y=\"dcoilwtico\", label=\"Daily Price\")\n\n# 2. Tạo đường xu hướng mượt bằng Trung bình trượt (ví dụ: cửa sổ 30 ngày)\n# Bạn có thể đổi window=30 thành 60 hoặc 90 tùy thuộc vào độ mượt bạn muốn\noil['oil_trend'] = oil['dcoilwtico'].rolling(window=30, center=True, min_periods=1).mean()\n\n# 3. Vẽ đường xu hướng màu đỏ\nsns.lineplot(data=oil, x=\"date\", y=\"oil_trend\", color=\"red\", label=\"Trend (30-day Rolling Mean)\")\n\nplt.title(\"Oil Price Over Time\", fontsize=14, fontweight='bold')\nplt.ylabel(\"Oil Price (dcoilwtico)\")\nplt.xlabel(\"Date\")\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:48.984175Z","iopub.execute_input":"2026-05-12T19:13:48.984603Z","iopub.status.idle":"2026-05-12T19:13:49.189149Z","shell.execute_reply.started":"2026-05-12T19:13:48.984575Z","shell.execute_reply":"2026-05-12T19:13:49.188221Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy giá dầu có sự biến động rất mạnh trong giai đoạn 2013–2017 và xuất hiện một “structural break” rõ rệt từ cuối năm 2014. Trong giai đoạn 2013–2014, giá dầu duy trì ở mức cao khoảng 90 - 110 USD/thùng, tuy nhiên sau đó giảm mạnh xuống gần 30 USD/thùng vào đầu năm 2016 trước khi phục hồi nhẹ quanh mức 45 - 55 USD/thùng trong các năm tiếp theo.\n\nĐiều này phản ánh thị trường dầu mỏ có volatility rất cao và chịu ảnh hưởng mạnh từ các biến động kinh tế toàn cầu. Ngoài ra, sự thay đổi mạnh về xu hướng giá dầu cũng cho thấy dữ liệu kinh tế trong bài toán forecasting không hoàn toàn stationary theo thời gian mà tồn tại các giai đoạn biến động lớn (economic regime changes).\n\nTừ góc nhìn kinh doanh và forecasting, biểu đồ này cho thấy oil price có thể đóng vai trò như một external macroeconomic signal giúp mô hình học được: các giai đoạn economic shock, thay đổi sức mua thị trường, biến động chi phí logistics và thay đổi hành vi tiêu dùng trong dài hạn. Do đó, feature liên quan đến oil price có thể hữu ích trong việc cải thiện khả năng dự báo ở các giai đoạn thị trường biến động mạnh thay vì chỉ phản ánh mối quan hệ trực tiếp với doanh số bán hàng.","metadata":{}},{"cell_type":"code","source":"# =====================================================================\n# BIỂU ĐỒ 2: Biến động giá dầu hàng tuần (p2) - KHÔNG DÙNG STATSMODELS\n# =====================================================================\n\n# 1. Xử lý dữ liệu: sử dụng tên cột đúng là 'dcoilwtico' thay vì 'oilprice'\noil[\"lag7\"] = oil[\"dcoilwtico\"].shift(7)\noil[\"diff\"] = oil[\"dcoilwtico\"] - oil[\"lag7\"]\noil_diff = oil.dropna(subset=[\"diff\"]).copy() # .copy() để tránh cảnh báo SettingWithCopyWarning\n\nplt.figure(figsize=(14, 5))\n\n# 2. Vẽ đường biến động gốc (màu đen)\nsns.lineplot(data=oil_diff, x=\"date\", y=\"diff\", label=\"Weekly Change\")\n\n# 3. Tính toán đường xu hướng mượt bằng Trung bình trượt (Ví dụ: cửa sổ 30 ngày)\noil_diff['diff_trend'] = oil_diff['diff'].rolling(window=30, center=True, min_periods=1).mean()\n\n# 4. Vẽ đường xu hướng (màu đỏ)\nsns.lineplot(data=oil_diff, x=\"date\", y=\"diff_trend\", color=\"red\", label=\"Trend (30-day Rolling Mean)\")\n\nplt.title(\"Weekly Variations Trend\", fontsize=14, fontweight='bold')\nplt.ylabel(\"Weekly variations in Oil price\")\nplt.xlabel(\"Date\")\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:13:52.792246Z","iopub.execute_input":"2026-05-12T19:13:52.793236Z","iopub.status.idle":"2026-05-12T19:13:53.027914Z","shell.execute_reply.started":"2026-05-12T19:13:52.793193Z","shell.execute_reply":"2026-05-12T19:13:53.027183Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy mức biến động tuần của giá dầu thay đổi liên tục và có volatility khá cao trong toàn bộ giai đoạn 2013–2017. Các biến động ngắn hạn thường dao động quanh mức ±2 đến ±5, tuy nhiên tại một số thời điểm xuất hiện các spike rất lớn vượt quá: +7 hoặc giảm xuống dưới -10. Đặc biệt trong giai đoạn cuối 2014 đến đầu 2015 thời điểm thị trường dầu mỏ bắt đầu bước vào giai đoạn sụt giảm mạnh. \n\nĐường xu hướng trung bình trượt 30 ngày (đường đỏ) cho thấy: giai đoạn 2014 - 2015 có biến động âm kéo dài, sau đó thị trường chuyển sang trạng thái dao động thất thường hơn trong giai đoạn 2016–2017.\n\nBiểu đồ này hản ánh rằng giá dầu không chỉ thay đổi về xu hướng dài hạn mà còn có mức biến động ngắn hạn rất mạnh theo thời gian. Điều này cho thấy dữ liệu oil price chứa: nhiều noise, volatility và shock bất thường.\n\nTừ góc nhìn forecasting, đặc điểm này rất quan trọng vì: các biến external feature có volatility cao thường khó học hơn và tác động của chúng lên demand có thể không xuất hiện ngay lập tức mà tồn tại dưới dạng lag effect theo thời gian.\n\nDo đó, thay vì sử dụng raw oil price trực tiếp, mô hình forecasting có thể cải thiện hiệu quả bằng cách: sử dụng rolling mean, smoothing, lag features hoặc oil trend indicators để giảm noise và giúp mô hình học được xu hướng kinh tế ổn định hơn thay vì các biến động ngắn hạn ngẫu nhiên.","metadata":{}},{"cell_type":"markdown","source":"# **Holidays Analysis**","metadata":{}},{"cell_type":"code","source":"holidays.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:14:15.628020Z","iopub.execute_input":"2026-05-12T19:14:15.628532Z","iopub.status.idle":"2026-05-12T19:14:15.637845Z","shell.execute_reply.started":"2026-05-12T19:14:15.628504Z","shell.execute_reply":"2026-05-12T19:14:15.637260Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sns.set_theme(style=\"whitegrid\")\n\n# Giả định bạn đã đọc dữ liệu vào DataFrame tên là 'holidays'\n# holidays = pd.read_csv(\"path_to_holidays.csv\")\n\n# Khởi tạo lưới biểu đồ 2 dòng, 2 cột\nfig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))\n\n# -----------------------------------------------------------------\n# p1: Phân phối theo 'type' (Biểu đồ cột đứng)\n# -----------------------------------------------------------------\nsns.countplot(data=holidays, x=\"type\", hue=\"type\", palette=\"pastel\", ax=ax1, legend=False)\nax1.set_title(\"Holiday Distribution by Type\", fontsize=14, fontweight='bold')\nax1.set_xlabel(\"Type\")\nax1.set_ylabel(\"Count\")\n# Thêm nhãn số đếm trên đầu cột\nfor container in ax1.containers:\n    ax1.bar_label(container, fmt=\"%.0f\", padding=3)\n\n# -----------------------------------------------------------------\n# p2: Phân phối theo 'locale' (Biểu đồ cột đứng)\n# -----------------------------------------------------------------\nsns.countplot(data=holidays, x=\"locale\", hue=\"locale\", palette=\"pastel\", ax=ax2, legend=False)\nax2.set_title(\"Holiday Distribution by Locale\", fontsize=14, fontweight='bold')\nax2.set_xlabel(\"Locale\")\nax2.set_ylabel(\"Count\")\nfor container in ax2.containers:\n    ax2.bar_label(container, fmt=\"%.0f\", padding=3)\n\n# -----------------------------------------------------------------\n# p3: Top 12 mô tả ngày lễ thường gặp nhất (coord_flip() -> vẽ cột ngang)\n# -----------------------------------------------------------------\n# Bước xử lý dữ liệu (tương đương group_by + count + arrange + head trong R)\ntop_descriptions = holidays[\"description\"].value_counts().head(12)\n# Sắp xếp tăng dần (ascending=True) để khi vẽ ngang (barh), giá trị lớn nhất nằm trên cùng\ntop_descriptions = top_descriptions.sort_values(ascending=True)\n\n# Vẽ biểu đồ cột ngang trực tiếp bằng Pandas trên trục ax3\ntop_descriptions.plot(kind=\"barh\", color=\"royalblue\", ax=ax3)\nax3.set_title(\"Top 12 Most Frequent Holiday Descriptions\", fontsize=14, fontweight='bold')\nax3.set_xlabel(\"Frequency\")\nax3.set_ylabel(\"Description - most frequent\")\nfor container in ax3.containers:\n    ax3.bar_label(container, fmt=\"%.0f\", padding=3)\n\n# -----------------------------------------------------------------\n# p4: Phân phối theo 'transferred' (Biểu đồ cột đứng)\n# -----------------------------------------------------------------\nsns.countplot(data=holidays, x=\"transferred\", hue=\"transferred\", palette=\"pastel\", ax=ax4, legend=False)\nax4.set_title(\"Holiday Distribution by Transferred Status\", fontsize=14, fontweight='bold')\nax4.set_xlabel(\"Transferred\")\nax4.set_ylabel(\"Count\")\nfor container in ax4.containers:\n    ax4.bar_label(container, fmt=\"%.0f\", padding=3)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:14:42.499009Z","iopub.execute_input":"2026-05-12T19:14:42.499669Z","iopub.status.idle":"2026-05-12T19:14:43.143380Z","shell.execute_reply.started":"2026-05-12T19:14:42.499637Z","shell.execute_reply":"2026-05-12T19:14:43.142764Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Các biểu đồ cho thấy dữ liệu holiday trong hệ thống bán lẻ Ecuador có tính đa dạng rất cao về: loại ngày lễ, phạm vi ảnh hưởng, và đặc điểm tổ chức. Trong đó, nhóm Holiday truyền thống chiếm số lượng lớn nhất với khoảng 221 ngày, vượt xa các nhóm khác như: Event (~ 56), Additional (~ 51), Transfer (~ 12), Bridge và Work Day (~ 5). Điều này cho thấy các ngày nghỉ lễ chính thức đóng vai trò rất quan trọng trong hành vi tiêu dùng và có khả năng tạo seasonal effect mạnh lên doanh số bán hàng.\n\nNgoài ra, biểu đồ locale cho thấy: National holidays (~ 174) và Local holidays (~ 152) xuất hiện với tần suất rất cao, trong khi Regional holidays chỉ khoảng 24. Insight này phản ánh rằng: hành vi mua sắm tại Ecuador chịu ảnh hưởng mạnh từ cả lễ toàn quốc lẫn các lễ địa phương và demand pattern có thể khác nhau đáng kể giữa các khu vực.\n\nĐặc biệt, nhiều holiday descriptions lặp lại thường xuyên như: Carnaval (10 lần), Fundacion de Cuenca, Fundacion de Ibarra, cùng nhiều ngày “Cantonizacion” khác nhau. Điều này cho thấy Ecuador có rất nhiều lễ hội văn hóa địa phương mang tính lặp theo năm và có thể tạo ra recurring seasonal patterns trong dữ liệu bán hàng.\n\nMột điều quan trọng khác là phần lớn holidays không bị transfer: Transferred = False chiếm khoảng 338, trong khi True chỉ khoảng 12. Điều này cho thấy hầu hết các ngày lễ diễn ra đúng lịch cố định thay vì được dời sang ngày khác. Đây là đặc điểm rất có lợi cho forecasting vì: các seasonal patterns sẽ ổn định hơn, dễ học hơn và ít tạo noise hơn cho mô hình.\n\nTừ góc nhìn forecasting, toàn bộ các biểu đồ này cho thấy holidays là một trong những external features quan trọng nhất trong bài toán dự báo doanh số bán lẻ. Tuy nhiên, không phải holiday nào cũng có mức ảnh hưởng giống nhau. Mức tác động có thể phụ thuộc vào: holiday type, phạm vi ảnh hưởng (local/regional/national), vị trí cửa hàng và loại sản phẩm.\nVí dụ: national holidays có thể tạo spike demand trên toàn hệ thống trong khi local holidays chỉ ảnh hưởng mạnh tại một số thành phố hoặc bang cụ thể. Do đó, doanh nghiệp không nên chỉ sử dụng một binary feature đơn giản như is_holiday, mà nên phân tách chi tiết để giúp forecasting model học được chính xác hơn các seasonal demand patterns.:\n- holiday type\n- local\n- transferred status\n- holiday description\n\nTừ góc nhìn kinh doanh, các biểu đồ này cho thấy holidays đóng vai trò rất lớn trong: consumer traffic, promotion planning, inventory management và workforce allocation.\n\nViệc hiểu rõ loại holiday nào tạo ra demand spike mạnh sẽ giúp doanh nghiệp tối ưu tồn kho, chuẩn bị logistics, triển khai promotion đúng thời điểm và giảm rủi ro stock-out trong các mùa cao điểm tiêu dùng.","metadata":{}},{"cell_type":"markdown","source":"# **Transactions Analysis**","metadata":{}},{"cell_type":"code","source":"transactions.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:15:39.936582Z","iopub.execute_input":"2026-05-12T19:15:39.937361Z","iopub.status.idle":"2026-05-12T19:15:39.946870Z","shell.execute_reply.started":"2026-05-12T19:15:39.937329Z","shell.execute_reply":"2026-05-12T19:15:39.946028Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tính tổng số giao dịch của toàn hệ thống theo từng ngày\ndaily_tx = transactions.groupby('date')['transactions'].sum().reset_index()\n\nplt.figure(figsize=(14, 6))\n# 1. Vẽ dữ liệu thô (màu xám nhạt để không bị rối mắt)\nsns.lineplot(data=daily_tx, x='date', y='transactions', alpha=0.7, label='Daily Transactions')\n\n# 2. Vẽ đường xu hướng mượt 30 ngày (màu xanh dương) để thấy rõ chu kỳ\ndaily_tx['trend'] = daily_tx['transactions'].rolling(window=30, center=True, min_periods=1).mean()\nsns.lineplot(data=daily_tx, x='date', y='trend', label='30-day Trend')\n\nplt.title(\"Total Daily Transactions Over Time (System-wide)\", fontsize=14, fontweight='bold')\nplt.xlabel(\"Date\")\nplt.ylabel(\"Number of Transactions\")\nplt.legend()\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:15:42.149080Z","iopub.execute_input":"2026-05-12T19:15:42.149739Z","iopub.status.idle":"2026-05-12T19:15:42.426625Z","shell.execute_reply.started":"2026-05-12T19:15:42.149713Z","shell.execute_reply":"2026-05-12T19:15:42.425806Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy tổng số giao dịch hằng ngày của toàn hệ thống bán lẻ có xu hướng tăng dần trong giai đoạn 2013 - 2017, đồng thời xuất hiện các seasonal spikes rất rõ rệt theo từng năm.\n\nTrong giai đoạn đầu năm 2013, số lượng giao dịch trung bình dao động quanh khoảng 70,000 - 80,000 transactions/ngày. Tuy nhiên đến giai đoạn 2016 - 2017, mức trung bình đã tăng lên khoảng 85,000 – 95,000 transactions/ngày, cho thấy quy mô hoạt động và lượng khách hàng của hệ thống bán lẻ đang tăng trưởng theo thời gian.\n\nNgoài xu hướng tăng dài hạn, biểu đồ cũng cho thấy: các spike giao dịch rất lớn xuất hiện lặp lại gần đầu mỗi năm với nhiều thời điểm vượt mức 150,000 - 170,000 transactions/ngày. Điều này phản ánh sự tồn tại của: strong seasonality, holiday effects hoặc các dịp tiêu dùng cao điểm diễn ra định kỳ hằng năm.\n\nĐặc biệt, đường xu hướng trung bình trượt 30 ngày cho thấy transaction volume không tăng đột biến ngẫu nhiên mà có xu hướng tăng ổn định theo thời gian. Điều này cho thấy: nhu cầu thị trường đang mở rộng, hệ thống cửa hàng có thể đang phát triển thêm hoặc lượng khách hàng trung thành đang tăng lên theo từng năm.\n\nNgoài ra, biểu đồ cũng xuất hiện một số điểm giảm cực mạnh xuống gần bằng 0 vào đầu các năm. Đây nhiều khả năng là: dữ liệu thiếu, ngày hệ thống chưa ghi nhận đầy đủ giao dịch,\nhoặc các anomalous records thay vì phản ánh hành vi thực tế của thị trường. Đây là một dấu hiệu quan trọng trong data quality checking và cần được xử lý cẩn thận trước khi modeling.\n\nTừ góc nhìn forecasting, transactions là một feature cực kỳ quan trọng vì nó phản ánh trực tiếp: customer traffic, demand intensity và mức độ hoạt động của hệ thống bán lẻ. Khi kết hợp với sales forecasting, transaction data có thể giúp mô hình: học được customer behavior, nhận diện peak demand periods và cải thiện khả năng dự báo trong các mùa cao điểm.\n\nNgoài ra, việc transaction volume có trend tăng dài hạn, seasonality rõ rệt và recurring spikes theo năm cho thấy forecasting model cần:\n- xử lý temporal patterns tốt\n- sử dụng lag features\n- rolling statistics\n- seasonal decomposition\n- time-series specific features\n\n-> để mô hình hóa chính xác hành vi giao dịch theo thời gian.\n\nTừ góc nhìn kinh doanh biểu đồ này cho thấy hệ thống bán lẻ đang có xu hướng tăng trưởng lượng khách hàng và mức độ hoạt động theo thời gian. Tuy nhiên, các giai đoạn peak traffic rất lớn cũng đồng nghĩa doanh nghiệp cần: chuẩn bị inventory tốt hơn, tối ưu workforce allocation, tăng năng lực logistics và đảm bảo hệ thống vận hành ổn định để tránh stock-out, quá tải vận hành hoặc suy giảm trải nghiệm khách hàng trong các mùa tiêu dùng cao điểm.","metadata":{}},{"cell_type":"code","source":"# Tính toán trung bình số giao dịch mỗi ngày của từng cửa hàng\nstore_tx = transactions.groupby('store_nbr')['transactions'].mean().sort_values(ascending=False).head(10)\n# Đảo ngược để vẽ cột ngang từ lớn đến bé từ trên xuống\nstore_tx = store_tx.sort_values(ascending=True)\n\nplt.figure(figsize=(10, 6))\nax = store_tx.plot(kind='barh', color='emerald' if 'emerald' in locals() else '#2ecc71')\n\nfor container in ax.containers:\n    ax.bar_label(container, fmt='%.0f', padding=5)\n\nplt.title(\"Top 10 Stores with Highest Average Daily Transactions\", fontsize=14, fontweight='bold')\nplt.xlabel(\"Average Transactions per Day\")\nplt.ylabel(\"Store Number\")\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:15:46.066552Z","iopub.execute_input":"2026-05-12T19:15:46.067070Z","iopub.status.idle":"2026-05-12T19:15:46.245034Z","shell.execute_reply.started":"2026-05-12T19:15:46.067042Z","shell.execute_reply":"2026-05-12T19:15:46.244474Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy lưu lượng giao dịch tập trung mạnh tại một số cửa hàng lớn như store 44 (~ 4,337 transactions/ngày) hay store 47 (~ 3,897), cao gần gấp đôi so với nhiều store khác trong top 10. Điều này cho thấy áp lực vận hành trong hệ thống bán lẻ đang phân bố không đồng đều.\n\nCác cửa hàng có transaction volume cao không chỉ đóng vai trò tạo doanh thu chính mà còn là những điểm dễ phát sinh bottleneck về vận hành như quá tải quầy thanh toán, thiếu hàng, hoặc áp lực replenishment trong giờ cao điểm.\n\nTừ góc nhìn kinh doanh, doanh nghiệp cần ưu tiên capacity planning cho nhóm high-traffic stores thông qua tăng nhân sự, tối ưu checkout, cải thiện logistics, và xây dựng inventory buffer phù hợp.\n\nNgoài ra, biểu đồ này cũng cho thấy rủi ro tập trung doanh thu vào một số ít cửa hàng lớn. Nếu xảy ra gián đoạn vận hành tại các store trọng điểm, tác động đến doanh thu toàn hệ thống có thể rất đáng kể.","metadata":{}},{"cell_type":"code","source":"# Tạo thêm cột Thứ và Tháng để phân tích\ntransactions['date'] = pd.to_datetime(transactions['date'])\ntransactions['day_of_week'] = transactions['date'].dt.day_name()\ntransactions['month'] = transactions['date'].dt.month\n\n# Thống kê theo thứ tự các thứ trong tuần\nday_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']\nweekly_profile = transactions.groupby('day_of_week')['transactions'].mean().reindex(day_order)\n\nplt.figure(figsize=(10, 5))\nax = sns.barplot(x=weekly_profile.index, y=weekly_profile.values, palette=\"vlag\", hue=weekly_profile.index, legend=False)\n\nfor container in ax.containers:\n    ax.bar_label(container, fmt='%.0f', padding=3)\n\nplt.title(\"Average Transactions by Day of the Week\", fontsize=14, fontweight='bold')\nplt.xlabel(\"Day of the Week\")\nplt.ylabel(\"Average Transactions\")\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-12T19:15:49.576223Z","iopub.execute_input":"2026-05-12T19:15:49.577151Z","iopub.status.idle":"2026-05-12T19:15:49.824119Z","shell.execute_reply.started":"2026-05-12T19:15:49.577119Z","shell.execute_reply":"2026-05-12T19:15:49.823255Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Biểu đồ cho thấy hành vi mua sắm của khách hàng thay đổi rõ rệt theo từng ngày trong tuần. Trong khi transaction volume các ngày Monday - Friday dao động khá ổn định quanh mức 1,550 - 1,650 giao dịch/ngày, lượng giao dịch tăng mạnh vào cuối tuần, đặc biệt Saturday đạt gần 1,953 transactions/day - mức cao nhất toàn tuần. **Điều này cho thấy cuối tuần là thời điểm người tiêu dùng thực hiện các hoạt động mua sắm lớn hơn cho gia đình hoặc nhu cầu tích trữ hàng hóa cho tuần tiếp theo**. Khách hàng không chỉ mua nhiều hơn mà còn có xu hướng dành nhiều thời gian hơn cho supermarket shopping trong weekend.\n\nNgoài ra, Thursday là ngày có transaction thấp nhất (~ 1,550), phản ánh đây có thể là giai đoạn “low shopping momentum” trước khi nhu cầu bắt đầu tăng trở lại vào Friday và bùng nổ vào cuối tuần.\n\nTừ góc nhìn kinh doanh biểu đồ này cho thấy doanh nghiệp nên xem cuối tuần là “high customer engagement period” thay vì chỉ là peak sales period. Đây là thời điểm phù hợp để triển khai bundle promotions, cross-selling, sampling campaigns hoặc loyalty programs nhằm tối đa hóa giá trị mỗi khách hàng trong lúc customer traffic đạt cao nhất.\n\nNgược lại, các ngày giữa tuần có thể phù hợp hơn cho targeted discounts, customer retention campaigns hoặc operational optimization nhằm kích thích nhu cầu trong các low-traffic periods.","metadata":{}}]}