, September 29, 2022

0 kết quả được tìm thấy

Data Driven Growth (P.3): Dự đoán giá trị vòng đời khách hàng

  • Đăng bởi  Pum
  •  Jun 14, 2022

  •   12 min reads
Data Driven Growth (P.3): Dự đoán giá trị vòng đời khách hàng

Tiếp nối bài viết trước, chúng ta đã phân khúc khách hàng của mình và tìm ra ai là khách hàng tiềm năng. Bây giờ, chúng ta nên đo lường một trong những số liệu quan trọng nhất mà chúng ta nên theo dõi chặt chẽ đó là: giá trị vòng đời của khách hàng (Customer Lifetime Value).

Chúng ta đầu tư vào khách hàng (chi phí mua lại, quảng cáo ngoại tuyến, khuyến mại, chiết khấu, ...) để tạo doanh thu và có lãi.

Đương nhiên, những hành động này sẽ giúp ta có được một lượng lớn khách hàng thân thiết nhưng trong số đó vẫn có một số khách hàng làm giảm khả năng sinh lời. Vì thế, chúng ta cần xác định rõ các mẫu hành vi để có thể phân khúc khách hàng và hành động với từng khách hàng phù hợp hơn.

Tính toán giá trị vòng đời của khách hàng là một phần không quá khó. Đầu tiên, chúng ta cần chọn một cột mốc thời gian cụ thể như 3, 6, 12, 24 tháng. Chúng ta sẽ có giá trị vòng đời của mỗi khách hàng trong khoảng thời gian cụ thể đó với phương trình sau:

Giá trị vòng đời: Tổng doanh thu - Tổng chi phí

Phương trình này bây giờ sẽ cung cấp cho chúng ta thấy giá trị vòng đời của khách hàng. Nếu chúng ta thấy một khách hàng mà có giá trị vòng đời là âm thì có lẽ đã quá muộn để thực hiện các hành động dưới. Tại thời điểm này, chúng ta cần dự đoán tương lai với machine learning:


Chúng ta sẽ xây dựng một mô hình machine learning đơn giản nhằm dự đoán giá trị vòng đời của khách hàng.

Dự đoán giá trị vòng đời của khách hàng

Chúng ta cũng vẫn sẽ tiếp tục sử dụng tập dữ liệu bán lẻ trực tuyến của mình cho ví dụ này. Hãy cùng xác định các bước thôi nào:

  • Xác định khung thời gian thích hợp để tính giá trị vòng đời của khách hàng
  • Xác định các tính năng chúng ta sẽ sử dụng để dự đoán tương lai và tạo ra chúng
  • Tính toán giá trị vòng đời khách hàng (LTV) để đào tạo mô hình machine learning
  • Xây dựng và chạy mô hình machine learning
  • Kiểm tra xem mô hình có hữu ích không

Quyết định khung thời gian sẽ phụ thuộc vào ngành, mô hình kinh doanh, chiến lược của bạn và còn nhiều yếu tố khác nữa.

Đối với một số ngành, 1 năm là khoảng thời gian rất dài nhưng đối với một số ngành khác thì đó là khoảng thời gian ngắn. Trong ví dụ sau, chúng ta sẽ lấy cột mốc là 6 tháng.

Điểm RFM cho mỗi ID khách hàng (mà chúng ta đã tính toán trong bài viết trước) là ứng cử viên tốt nhất cho bộ tính năng. Để triển khai nó một cách chính xác, chúng ta cần chia nhỏ tập dữ liệu của mình.

Chúng ta sẽ lấy dữ liệu trong 3 tháng, tính toán RFM và sử dụng nó để dự đoán 6 tháng tới. Vì vậy, trước tiên chúng ta cần tạo hai khung dữ liệu và nối điểm RFM vào chúng.

#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


import plotly.plotly as py
import plotly.offline as pyoff
import plotly.graph_objs as go

import xgboost as xgb
from sklearn.model_selection import KFold, cross_val_score, train_test_split

import xgboost as xgb

#initate plotly
pyoff.init_notebook_mode()

#read data from csv and redo the data work we done before
tx_data = pd.read_csv('data.csv')
tx_data['InvoiceDate'] = pd.to_datetime(tx_data['InvoiceDate'])
tx_uk = tx_data.query("Country=='United Kingdom'").reset_index(drop=True)

#create 3m and 6m dataframes
tx_3m = tx_uk[(tx_uk.InvoiceDate < date(2011,6,1)) & (tx_uk.InvoiceDate >= date(2011,3,1))].reset_index(drop=True)
tx_6m = tx_uk[(tx_uk.InvoiceDate >= date(2011,6,1)) & (tx_uk.InvoiceDate < date(2011,12,1))].reset_index(drop=True)

#create tx_user for assigning clustering
tx_user = pd.DataFrame(tx_3m['CustomerID'].unique())
tx_user.columns = ['CustomerID']

#order cluster method
def order_cluster(cluster_field_name, target_field_name,df,ascending):
    new_cluster_field_name = 'new_' + cluster_field_name
    df_new = df.groupby(cluster_field_name)[target_field_name].mean().reset_index()
    df_new = df_new.sort_values(by=target_field_name,ascending=ascending).reset_index(drop=True)
    df_new['index'] = df_new.index
    df_final = pd.merge(df,df_new[[cluster_field_name,'index']], on=cluster_field_name)
    df_final = df_final.drop([cluster_field_name],axis=1)
    df_final = df_final.rename(columns={"index":cluster_field_name})
    return df_final


#calculate recency score
tx_max_purchase = tx_3m.groupby('CustomerID').InvoiceDate.max().reset_index()
tx_max_purchase.columns = ['CustomerID','MaxPurchaseDate']
tx_max_purchase['Recency'] = (tx_max_purchase['MaxPurchaseDate'].max() - tx_max_purchase['MaxPurchaseDate']).dt.days
tx_user = pd.merge(tx_user, tx_max_purchase[['CustomerID','Recency']], on='CustomerID')

kmeans = KMeans(n_clusters=4)
kmeans.fit(tx_user[['Recency']])
tx_user['RecencyCluster'] = kmeans.predict(tx_user[['Recency']])

tx_user = order_cluster('RecencyCluster', 'Recency',tx_user,False)

#calcuate frequency score
tx_frequency = tx_3m.groupby('CustomerID').InvoiceDate.count().reset_index()
tx_frequency.columns = ['CustomerID','Frequency']
tx_user = pd.merge(tx_user, tx_frequency, on='CustomerID')

kmeans = KMeans(n_clusters=4)
kmeans.fit(tx_user[['Frequency']])
tx_user['FrequencyCluster'] = kmeans.predict(tx_user[['Frequency']])

tx_user = order_cluster('FrequencyCluster', 'Frequency',tx_user,True)

#calcuate revenue score
tx_3m['Revenue'] = tx_3m['UnitPrice'] * tx_3m['Quantity']
tx_revenue = tx_3m.groupby('CustomerID').Revenue.sum().reset_index()
tx_user = pd.merge(tx_user, tx_revenue, on='CustomerID')

kmeans = KMeans(n_clusters=4)
kmeans.fit(tx_user[['Revenue']])
tx_user['RevenueCluster'] = kmeans.predict(tx_user[['Revenue']])
tx_user = order_cluster('RevenueCluster', 'Revenue',tx_user,True)


#overall scoring
tx_user['OverallScore'] = tx_user['RecencyCluster'] + tx_user['FrequencyCluster'] + tx_user['RevenueCluster']
tx_user['Segment'] = 'Low-Value'
tx_user.loc[tx_user['OverallScore']>2,'Segment'] = 'Mid-Value' 
tx_user.loc[tx_user['OverallScore']>4,'Segment'] = 'High-Value' 




Chúng ta đã tạo tính năng cho điểm RFM và bây giờ bộ tính năng của chúng ta trông giống như bên dưới:

Vì bộ tính năng của chúng ta đã sẵn sàng, hãy tính LTV trong 6 tháng cho mỗi khách hàng mà chúng ta sẽ sử dụng để đào tạo mô hình của mình.

Không có chi phí được chỉ định trong tập dữ liệu. Đó là lý do tại sao doanh thu trở thành LTV là trực tiếp.

#calculate revenue and create a new dataframe for it
tx_6m['Revenue'] = tx_6m['UnitPrice'] * tx_6m['Quantity']
tx_user_6m = tx_6m.groupby('CustomerID')['Revenue'].sum().reset_index()
tx_user_6m.columns = ['CustomerID','m6_Revenue']


#plot LTV histogram
plot_data = [
    go.Histogram(
        x=tx_user_6m.query('m6_Revenue < 10000')['m6_Revenue']
    )
]

plot_layout = go.Layout(
        title='6m Revenue'
    )
fig = go.Figure(data=plot_data, layout=plot_layout)

Đoạn mã này tính toán LTV và vẽ biểu đồ của nó:

Biểu đồ cho thấy, rõ ràng chúng ta có những khách hàng có LTV âm nhưng trong đó cũng có một số là ngoại lệ. Lọc ra những điểm ngoại lệ có ý nghĩa để có một mô hình machine learning phù hợp.

Bước tiếp theo, chúng ta sẽ hợp nhất khung dữ liệu 3 tháng và 6 tháng để xem mối tương quan giữa LTV và bộ tính năng mà chúng ta có.

tx_merge = pd.merge(tx_user, tx_user_6m, on='CustomerID', how='left')
tx_merge = tx_merge.fillna(0)

tx_graph = tx_merge.query("m6_Revenue < 30000")

plot_data = [
    go.Scatter(
        x=tx_graph.query("Segment == 'Low-Value'")['OverallScore'],
        y=tx_graph.query("Segment == 'Low-Value'")['m6_Revenue'],
        mode='markers',
        name='Low',
        marker= dict(size= 7,
            line= dict(width=1),
            color= 'blue',
            opacity= 0.8
           )
    ),
        go.Scatter(
        x=tx_graph.query("Segment == 'Mid-Value'")['OverallScore'],
        y=tx_graph.query("Segment == 'Mid-Value'")['m6_Revenue'],
        mode='markers',
        name='Mid',
        marker= dict(size= 9,
            line= dict(width=1),
            color= 'green',
            opacity= 0.5
           )
    ),
        go.Scatter(
        x=tx_graph.query("Segment == 'High-Value'")['OverallScore'],
        y=tx_graph.query("Segment == 'High-Value'")['m6_Revenue'],
        mode='markers',
        name='High',
        marker= dict(size= 11,
            line= dict(width=1),
            color= 'red',
            opacity= 0.9
           )
    ),
]

plot_layout = go.Layout(
        yaxis= {'title': "6m LTV"},
        xaxis= {'title': "RFM Score"},
        title='LTV'
    )
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)

Đoạn mã dưới đây kết hợp tập hợp tính năng và dữ liệu LTV, lập biểu đồ LTV so với điểm RFM tổng thể:

Ở đây chúng ta có thể thấy tương quan khá tích cực, điểm RFM cao có nghĩa là LTV cao.

Trước khi xây dựng mô hình machine learning, chúng ta cần xác định vấn đề ở đây là gì? Bản thân LTV là một bài toán hồi quy, mô hình machine learning có thể dự đoán giá trị $ của LTV.

Nhưng ở đây, chúng ta muốn phân đoạn LTV. Bởi vì, nó sẽ dễ hành động hơn cũng như dễ dàng giao tiếp với người khác hơn, bằng cách áp dụng phân nhóm K-means, chúng ta có thể xác định các nhóm LTV hiện có của mình và xây dựng các phân đoạn trên đó.

Xem xét phần phân tích này, dựa trên LTV dự đoán mà chúng ta sẽ đối xử với mỗi khách hàng khác nhau. Đối với ví dụ này, chúng ta sẽ áp dụng phân nhóm với 3 phân đoạn (số lượng phân đoạn thực sự phụ thuộc vào động lực kinh doanh và mục tiêu của bạn):

  • LTV thấp
  • LTV giữa
  • LTV cao

Chúng ta sẽ áp dụng phân cụm K-means để quyết định các phân đoạn và quan sát các đặc điểm của chúng:

#remove outliers
tx_merge = tx_merge[tx_merge['m6_Revenue']<tx_merge['m6_Revenue'].quantile(0.99)]


#creating 3 clusters
kmeans = KMeans(n_clusters=3)
kmeans.fit(tx_merge[['m6_Revenue']])
tx_merge['LTVCluster'] = kmeans.predict(tx_merge[['m6_Revenue']])

#order cluster number based on LTV
tx_merge = order_cluster('LTVCluster', 'm6_Revenue',tx_merge,True)

#creatinga new cluster dataframe
tx_cluster = tx_merge.copy()

#see details of the clusters
tx_cluster.groupby('LTVCluster')['m6_Revenue'].describe()

Chúng ta đã hoàn thành phân cụm LTV và đây là đặc điểm của từng cụm:

2 là tốt nhất với 8,2 nghìn LTV trung bình trong khi 0 là kém nhất với 396.

Còn vài bước nữa trước khi ta tạo ra mô hình machine learning:

  • Cần phải thực hiện một số kỹ thuật tính năng. Chúng ta nên chuyển đổi cột phân loại sang cột số.
  • Chúng ta sẽ kiểm tra mối tương quan của các tính năng với nhãn của chúng ta, các cụm LTV.
  • Chúng ta sẽ chia bộ tính năng và nhãn (LTV) của chúng ta thành X và Y. Chúng ta sử dụng X để dự đoán Y.
  • Sẽ tạo tập dữ liệu đào tạo và kiểm tra. Sẽ được sử dụng để xây dựng mô hình machine learning. Chúng ta sẽ áp dụng mô hình của mình vào Test set để xem hiệu suất thực sự của nó.

Đoạn mã dưới đây thực hiện tất cả cho chúng ta:

#convert categorical columns to numerical
tx_class = pd.get_dummies(tx_cluster)

#calculate and show correlations
corr_matrix = tx_class.corr()
corr_matrix['LTVCluster'].sort_values(ascending=False)

#create X and y, X will be feature set and y is the label - LTV
X = tx_class.drop(['LTVCluster','m6_Revenue'],axis=1)
y = tx_class['LTVCluster']

#split training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.05, random_state=56)

Hãy bắt đầu với dòng đầu tiên. Phương thức get_dummies () chuyển đổi các cột phân loại thành các ký hiệu 0–1. Xem chính xác những gì nó làm với ví dụ:

Đây là tập dữ liệu của chúng ta trước get_dummies (). Chúng ta có một cột phân loại là phân đoạn. Điều gì sẽ xảy ra sau khi áp dụng get_dummies ():

Cột phân đoạn đã biến mất nhưng chúng ta có những cột số mới đại diện cho nó. Chúng ta đã chuyển đổi nó thành 3 cột khác nhau với 0 và 1, và làm cho nó có thể sử dụng được cho mô hình machine learning.

Chúng ta có dữ liệu dưới đây:

Chúng ta thấy rằng điểm doanh thu, tần suất và RFM trong 3 tháng sẽ khá là hữu ích cho các mô hình machine learning.

Vì chúng ta có các bộ đào tạo và thử nghiệm, chúng ta có thể xây dựng mô hình của chính mình.

#XGBoost Multiclassification Model
ltv_xgb_model = xgb.XGBClassifier(max_depth=5, learning_rate=0.1,objective= 'multi:softprob',n_jobs=-1).fit(X_train, y_train)

print('Accuracy of XGB classifier on training set: {:.2f}'
       .format(ltv_xgb_model.score(X_train, y_train)))
print('Accuracy of XGB classifier on test set: {:.2f}'
       .format(ltv_xgb_model.score(X_test[X_train.columns], y_test)))

y_pred = ltv_xgb_model.predict(X_test)
print(classification_report(y_test, y_pred))

Chúng ta đã sử dụng một thư viện ML khá mạnh có tên là XGBoost để phân loại. Nó đã trở thành một mô hình đa phân loại kể từ khi chúng ta có 3 nhóm (cụm). Hãy xem kết quả ban đầu:

Độ chính xác thể hiện 84% trên bộ thử nghiệm. Đây có được xem là một kết quả tốt hay không?

Trước tiên, chúng ta cần kiểm tra điểm chuẩn của mình. Cụm lớn nhất mà chúng ta có là cụm 0, chiếm 76,5% tổng số cơ sở.

84% so với 76,5% cho chúng ta biết rằng mô hình machine learning của mình là một mô hình hữu ích nhưng cần phải cải thiện lại một chút. Chúng ta nên tìm ra nơi mà mô hình bị lỗi.

Chúng ta có thể xác định điều đó bằng cách xem lại báo cáo phân loại:

Độ chính xác và thu hồi có thể chấp nhận được đối với 0. Ví dụ, đối với cụm 0 (LTV thấp), nếu mô hình cho chúng ta biết khách hàng này thuộc cụm 0, 90 trên 100 sẽ đúng (độ chính xác). Và mô hình xác định thành công 93% khách hàng cụm 0 thực tế (thu hồi).

Chúng ta thực sự cần cải thiện mô hình cho các cụm khác. Ví dụ: chúng ta hầu như không phát hiện được 56% khách hàng LTV tầm trung. Các hành động có thể thực hiện để cải thiện những điểm đó:

  • Thêm nhiều tính năng hơn và cải thiện kỹ thuật tính năng
  • Thử các mô hình khác ngoài XGBoost
  • Áp dụng điều chỉnh siêu tham số cho mô hình hiện tại
  • Thêm nhiều dữ liệu hơn vào mô hình nếu có thể

Không phải rất tốt sao, vì giờ đây chúng ta có một mô hình machine learning dự đoán được các phân khúc LTV trong tương lai của khách hàng. Chúng ta có thể dễ dàng điều chỉnh các hành động của mình dựa trên điều đó.

Chắc chắn chúng ta sẽ không muốn mất khách hàng có LTV cao. Vì vậy, trong phần tiếp theo (phần 4)  chúng ta sẽ tập trung vào việc dự đoán lòng trung thành của khách hàng. Hẹn gặp lại các bạn trong phần sau nhé!

Bài viết được dịch từ đây.

Bài viết cùng seri

Bài viết liên quan

Master data là gì? Sự khác nhau giữa Master data và Transaction data

Master data là tập hợp các định danh thống nhất và các thuộc tính mở rộng. Nó mô tả các thực thể cốt lõi của doanh nghiệp bao gồm khách hàng,.......

Master data là gì? Sự khác nhau giữa Master data và Transaction data
Danh mục các loại biểu đồ trong Data Visualization

Bạn có thể tìm thấy danh sách các loại biểu đồ, nó sẽ hoạt động như một hướng dẫn đầy hữu ích giúp bạn lựa chọn được biểu đồ phù hợp với nhu cầu của bản thân....

Danh mục các loại biểu đồ trong Data Visualization
Data Analysis with Excel: Analysis ToolPak

Bộ công cụ Analysis ToolPak trên Excel sẽ giúp bạn tiết kiệm thời gian và đơn giản hóa các bước phân tích dữ liệu tài chính, thống kê ....

Data Analysis with Excel: Analysis ToolPak
Data Analysis with Excel: Solver

Excel có một công cụ được gọi là solver cung cấp các lệnh và các tính năng tùy chỉnh để giải quyết các vấn đề quyết định....

Data Analysis with Excel: Solver
Data Analysis with Excel: What-If Analysis

What-If Analysis trong Excel cho phép bạn thử các giá trị (scenarios) khác nhau cho các công thức....

Data Analysis with Excel: What-If Analysis
You've successfully subscribed to 200Lab Blog
Great! Next, complete checkout for full access to 200Lab Blog
Xin chào mừng bạn đã quay trở lại
OK! Tài khoản của bạn đã kích hoạt thành công.
Success! Your billing info is updated.
Billing info update failed.
Your link has expired.