Hầu hết các hành động của khách hàng đã được giải thích trong loạt bài viết trước đều có chung một tâm lý: đối xử với khách hàng theo cách mà họ xứng đáng được nhận.
Trước khi họ mong đợi điều đó (ví dụ: dự đoán LTV), hành động trước khi điều gì đó tồi tệ xảy ra (ví dụ: churn). Phân tích dự đoán giúp chúng ta cải thiện rất nhiều về vấn đề này.
Và một trong những điều tuyệt nhất là nó có thể giúp chúng ta dự đoán ngày mua hàng tiếp theo của khách hàng. Điều gì sẽ xảy ra nếu một khách hàng mua hàng sau 7 ngày? Chúng ta có thể xây dựng chiến lược của mình và đưa ra nhiều hành động chiến thuật như:
- Không khuyến mãi cho khách hàng này vì họ vẫn sẽ mua hàng bằng mọi cách
- Thu hút khách hàng bằng tiếp thị trong nước và nếu không có giao dịch mua nào trong khoảng thời gian dự đoán này hãy sa thải nhân viên đã dự đoán chúng
Trong bài viết này, chúng ta sẽ sử dụng tập dữ liệu bán lẻ trực tuyến và làm theo các bước bên dưới:
- Data Wrangling (tạo tập dữ liệu trước / sau và tính toán chênh lệch ngày mua hàng)
- Kỹ thuật tính năng
- Chọn mô hình machine learning
- Mô hình đa phân loại
- Điều chỉnh siêu tham số
Dữ liệu Wrangling
Hãy bắt đầu với việc nhập dữ liệu và thực hiện công việc dữ liệu sơ bộ:
#import libraries
from datetime import datetime, timedelta,date
import pandas as pd
%matplotlib inline
from sklearn.metrics import classification_report,confusion_matrix
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from __future__ import division
from sklearn.cluster import KMeans
#do not show warnings
import warnings
warnings.filterwarnings("ignore")
#import plotly for visualization
import plotly.plotly as py
import plotly.offline as pyoff
import plotly.graph_objs as go
#import machine learning related libraries
from sklearn.svm import SVC
from sklearn.multioutput import MultiOutputClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
import xgboost as xgb
from sklearn.model_selection import KFold, cross_val_score, train_test_split
#initiate plotly
pyoff.init_notebook_mode()
#import the csv
tx_data = pd.read_csv('data.csv')
#print first 10 rows
tx_data.head(10)
#convert date field from string to datetime
tx_data['InvoiceDate'] = pd.to_datetime(tx_data['InvoiceDate'])
#create dataframe with uk data only
tx_uk = tx_data.query("Country=='United Kingdom'").reset_index(drop=True)
Nhập tệp CSV và chuyển đổi trường ngày
Chúng ta nhập tệp CSV, chuyển đổi trường ngày khỏi chuỗi thành DateTime để làm cho nó hoạt động và lọc ra các quốc gia khác ngoài Vương quốc Anh.
Để xây dựng mô hình của mình, chúng ta nên chia dữ liệu thành hai phần:
Chúng ta sẽ sử dụng dữ liệu của 6 tháng gần đây để dự đoán ngày mua hàng đầu tiên của khách hàng trong 3 tháng tới. Nếu không có giao dịch mua, chúng ta cũng sẽ dự đoán được điều đó. Giả sử ngày kết thúc của chúng ta là ngày 9 tháng 9 và chia nhỏ dữ liệu:
tx_6m = tx_uk[(tx_uk.InvoiceDate < date(2011,9,1)) & (tx_uk.InvoiceDate >= date(2011,3,1))].reset_index(drop=True)
tx_next = tx_uk[(tx_uk.InvoiceDate >= date(2011,9,1)) & (tx_uk.InvoiceDate < date(2011,12,1))].reset_index(drop=True)
tx_6m đại diện cho hiệu suất 6 tháng trong khi chúng ta sẽ sử dụng tx_next để tìm ra những ngày mua hàng cuối cùng trong tx_6m và ngày mua hàng đầu tiên trong tx_next
Ngoài ra, chúng ta sẽ tạo khung dữ liệu có tên tx_user để sở hữu bộ tính năng cấp người dùng cho mô hình dự đoán:
tx_user = pd.DataFrame(tx_6m['CustomerID'].unique())
tx_user.columns = ['CustomerID']
Bằng cách sử dụng dữ liệu tx_next, chúng ta cần tính toán nhãn của chúng ta (số ngày từ lần mua cuối cùng trước ngày khóa sổ và lần mua đầu tiên sau đó)
#create a dataframe with customer id and first purchase date in tx_next
tx_next_first_purchase = tx_next.groupby('CustomerID').InvoiceDate.min().reset_index()
tx_next_first_purchase.columns = ['CustomerID','MinPurchaseDate']
#create a dataframe with customer id and last purchase date in tx_6m
tx_last_purchase = tx_6m.groupby('CustomerID').InvoiceDate.max().reset_index()
tx_last_purchase.columns = ['CustomerID','MaxPurchaseDate']
#merge two dataframes
tx_purchase_dates = pd.merge(tx_last_purchase,tx_next_first_purchase,on='CustomerID',how='left')
#calculate the time difference in days:
tx_purchase_dates['NextPurchaseDay'] = (tx_purchase_dates['MinPurchaseDate'] - tx_purchase_dates['MaxPurchaseDate']).dt.days
#merge with tx_user
tx_user = pd.merge(tx_user, tx_purchase_dates[['CustomerID','NextPurchaseDay']],on='CustomerID',how='left')
#print tx_user
tx_user.head()
#fill NA values with 999
tx_user = tx_user.fillna(999)
Bây giờ, tx_next sẽ nhìn giống như bên dưới:
Bạn có thể dễ dàng nhìn thấy các giá trị NaN vì những khách hàng đó chưa thực hiện bất kỳ giao dịch mua hàng nào. Chúng ta sẽ điền NaN thành 999 để xác định chúng nhanh chóng sau này.
Chúng ta có ID khách hàng và nhãn tương ứng trong khung dữ liệu. Hãy làm phong phú nó với bộ tính năng để xây dựng mô hình machine learning.
Kỹ thuật tính năng
Đối với dự án này, chúng ta đã chọn các ứng cử viên tính năng như dưới đây:
- Điểm và cụm RFM
- Số ngày giữa ba lần mua hàng cuối cùng
- Trung bình và độ lệch chuẩn của sự khác biệt giữa các lần mua hàng tính theo ngày
Sau khi thêm các tính năng này, chúng ta cần xử lý các tính năng phân loại bằng cách áp dụng phương thức get_dummies.
Đối với RFM chúng ta sẽ chia sẻ khối mã và tiếp tục.
Chúng ta sẽ sử dụng phương thức shift () rất nhiều trong phần này.
Đầu tiên, chúng ta tạo khung dữ liệu với ID khách hàng và ngày lập hóa đơn (không phải ngày giờ). Sau đó, chúng ta sẽ xóa các bản sao vì khách hàng có thể thực hiện nhiều giao dịch mua hàng trong một ngày và sự khác biệt sẽ trở thành 0 cho những lần mua hàng đó.
#create a dataframe with CustomerID and Invoice Date
tx_day_order = tx_6m[['CustomerID','InvoiceDate']]
#convert Invoice Datetime to day
tx_day_order['InvoiceDay'] = tx_6m['InvoiceDate'].dt.date
tx_day_order = tx_day_order.sort_values(['CustomerID','InvoiceDate'])
#drop duplicates
tx_day_order = tx_day_order.drop_duplicates(subset=['CustomerID','InvoiceDay'],keep='first')
Tiếp đến, bằng cách sử dụng shift, chúng ta sẽ tạo các cột mới với ngày của 3 lần mua hàng gần nhất và xem khung dữ liệu của chúng ta.
#shifting last 3 purchase dates
tx_day_order['PrevInvoiceDate'] = tx_day_order.groupby('CustomerID')['InvoiceDay'].shift(1)
tx_day_order['T2InvoiceDate'] = tx_day_order.groupby('CustomerID')['InvoiceDay'].shift(2)
tx_day_order['T3InvoiceDate'] = tx_day_order.groupby('CustomerID')['InvoiceDay'].shift(3)
Đầu ra:
Hãy bắt đầu tính toán sự khác biệt về số ngày cho mỗi ngày lập hóa đơn:
tx_day_order['DayDiff'] = (tx_day_order['InvoiceDay'] - tx_day_order['PrevInvoiceDate']).dt.days
tx_day_order['DayDiff2'] = (tx_day_order['InvoiceDay'] - tx_day_order['T2InvoiceDate']).dt.days
tx_day_order['DayDiff3'] = (tx_day_order['InvoiceDay'] - tx_day_order['T3InvoiceDate']).dt.days
Đầu ra:
Đối với mỗi ID khách hàng, chúng ta sử dụng phương thức .agg() để tìm ra giá trị trung bình và độ lệch chuẩn của sự khác biệt giữa các lần mua hàng trong ngày:
tx_day_diff = tx_day_order.groupby('CustomerID').agg({'DayDiff': ['mean','std']}).reset_index()
tx_day_diff.columns = ['CustomerID', 'DayDiffMean','DayDiffStd']
Bây giờ chúng ta sẽ phải đưa ra một quyết định khó khăn. Cách tính trên khá hữu ích cho những khách hàng mua nhiều lần nhưng chúng ta không thể áp dụng tương tự cho những người mới mua hàng 1-2 lần được.
Ví dụ: còn quá sớm để gắn thẻ một khách hàng là thường xuyên trong khi họ mới chỉ mới mua hàng có 2 lần.
Chúng ta sẽ chỉ giữ chân những khách hàng có lần mua hàng trên 3 lần bằng cách sử dụng dòng sau:
tx_day_order_last = tx_day_order.drop_duplicates(subset=['CustomerID'],keep='last')
Cuối cùng, chúng ta đã loại bỏ được các giá trị NA, hợp nhất các khung dữ liệu mới tx_user và áp dụng .get_dummies() để chuyển đổi các giá trị phân loại:
tx_day_order_last = tx_day_order_last.dropna()
tx_day_order_last = pd.merge(tx_day_order_last, tx_day_diff, on='CustomerID')
tx_user = pd.merge(tx_user,
tx_day_order_last[['CustomerID','DayDiff','DayDiff2','DayDiff3','DayDiffMean','DayDiffStd']], on='CustomerID')
#create tx_class as a copy of tx_user before applying get_dummies
tx_class = tx_user.copy()
tx_class = pd.get_dummies(tx_class)
Bộ tính năng của chúng ta đã sẵn sàng để xây dựng mô hình phân loại. Nhưng có rất nhiều mô hình khác nhau, chúng ta nên sử dụng mô hình nào?
Chọn mô hình machine learning
Trước khi chọn mô hình, chúng ta cần phải thực hiện hành động sau. Đầu tiên, chúng ta cần xác định các lớp có trong nhãn của chúng ta. Hãy sử dụng phương thức .describe () để xem chúng
Đưa ra quyết định về việc giới hạn số ngày mua là một câu hỏi cho cả thống kê và nhu cầu kinh doanh. Nó phải có ý nghĩa về mặt đầu tiên và dễ dàng thực hiện cũng như hành động và giao tiếp. Xem xét hai điều này, chúng ta sẽ chia làm ba nhóm:
- 0–20: Khách hàng sẽ mua trong 0–20 ngày - Nhóm hạng: 2
- 21–49: Khách hàng sẽ mua trong 21–49 ngày - Nhóm hạng: 1
- ≥ 50: Khách hàng sẽ mua hơn 50 ngày - Nhóm hạng: 0
tx_class['NextPurchaseDayRange'] = 2
tx_class.loc[tx_class.NextPurchaseDay>20,'NextPurchaseDayRange'] = 1
tx_class.loc[tx_class.NextPurchaseDay>50,'NextPurchaseDayRange'] = 0
Bước cuối cùng là xem mối tương quan giữa các tính năng và nhãn của chúng ta. Ma trận tương quan là một trong những cách rõ ràng nhất để thể hiện điều này:
corr = tx_class[tx_class.columns].corr()
plt.figure(figsize = (30,20))
sns.heatmap(corr, annot = True, linewidths=0.2, fmt=".2f")
Có vẻ như điểm tổng thể có mối tương quan tích cực cao nhất (0,45) và lần truy cập gần đây có mức tiêu cực cao nhất (-0,54).
Đối với vấn đề cụ thể này, chúng ta sẽ sử dụng mô hình cho độ chính xác cao nhất. Hãy chia nhỏ các bài kiểm tra đào tạo để kiểm tra và đo độ chính xác của các mô hình khác nhau:
Độ chính xác trên mỗi mô hình:
Từ kết quả này, chúng ta thấy rằng Naive Bayes là hoạt động tốt nhất với độ chính xác ~ 64%. Nhưng trước đó, hãy nhìn lại chính xác những gì chúng ta đã làm. Chúng ta đã áp dụng một khái niệm cơ bản trong machine learning đó là xác thực chéo.
Và làm cách nào để chúng ta có thể chắc chắn về sự ổn định của mô hình trên các bộ dữ liệu khác nhau? Ngoài ra, điều gì sẽ xảy ra nếu có nhiễu trong bộ thử nghiệm mà chúng ta đã chọn?
Xác thực chéo là một cách để đo lường điều này. Nó cung cấp điểm của mô hình bằng cách chọn các bộ thử nghiệm khác nhau. Nếu độ lệch thấp có nghĩa là mô hình ổn định. Trong trường hợp của chúng ta, sự sai lệch giữa các điểm số có thể chấp nhận được (ngoại trừ Decision Tree Classifier).
Thông thường, chúng ta nên đi trước với Naive Bayes. Nhưng đối với ví dụ này, hãy cùng XGBoost tiếp tục trình bày cách chúng ta có thể cải thiện một mô hình hiện có bằng một số kỹ thuật nâng cao.
Mô hình đa phân loại
Để xây dựng mô hình, chúng ta sẽ làm theo các bước trong các bài viết trước. Nhưng để cải thiện nó hơn nữa, chúng ta sẽ thực hiện điều chỉnh siêu tham số.
Chúng ta sẽ tìm ra các thông số tốt nhất của mô hình để làm cho nó cung cấp độ chính xác tốt nhất.
Trước tiên, hãy bắt đầu với việc viết mã mô hình của chúng ta:
xgb_model = xgb.XGBClassifier().fit(X_train, y_train)
print('Accuracy of XGB classifier on training set: {:.2f}'
.format(xgb_model.score(X_train, y_train)))
print('Accuracy of XGB classifier on test set: {:.2f}'
.format(xgb_model.score(X_test[X_train.columns], y_test)))
Trong phiên bản này, độ chính xác của chúng ta trên bộ thử nghiệm là 58%:
XGBClassifier có nhiều tham số. Bạn có thể tìm thấy danh sách chúng ở đây. Đối với ví dụ này, chúng sẽ chọn max_depth và min_child_weight.
Đoạn mã dưới đây sẽ tạo ra các giá trị tốt nhất cho các tham số này:
from sklearn.model_selection import GridSearchCV
param_test1 = {
'max_depth':range(3,10,2),
'min_child_weight':range(1,6,2)
}
gsearch1 = GridSearchCV(estimator = xgb.XGBClassifier(),
param_grid = param_test1, scoring='accuracy',n_jobs=-1,iid=False, cv=2)
gsearch1.fit(X_train,y_train)
gsearch1.best_params_, gsearch1.best_score_
Thuật toán cho biết các giá trị tốt nhất là 3 và 5 cho max_depth và min_child_weight tương ứng. Kiểm tra cách nó cải thiện độ chính xác:
Điểm của chúng ta đã tăng từ 58% lên 62%. Nó là một cải tiến có hiệu quả tốt.
Biết được ngày mua hàng tiếp theo cũng là một chỉ báo tốt để dự đoán doanh số bán hàng (phần 6), trong phần tiếp theo chúng ta sẽ đi sâu về chủ đề này .
Bài viết được dịch tại đây.
Pum
Life is short. Smile while you still have teeth :)
Bài viết liên quan
Tìm hiểu SQL: Hướng dẫn Prompt SQL với ChatGPT, Copilot
Dec 07, 2024 • 11 min read
Database (Cơ sở dữ liệu) là gì? Những loại Database phổ biến nhất hiện nay
Sep 01, 2024 • 11 min read
Python là gì? Những đặc điểm nổi bật và Ứng dụng của Python
Aug 28, 2024 • 14 min read
Ứng dụng Hypothesis Testing - Kiểm định giả thuyết trong Y học
Jul 18, 2024 • 8 min read
Google Colab là gì? Hướng dẫn sử dụng Google Colab cho người mới
Jul 02, 2024 • 10 min read
Hướng dẫn cách lấy dữ liệu Facebook Ads Tự động Mỗi ngày Miễn phí - Phần 2
Jun 24, 2024 • 6 min read