Trong bài viết trước, chúng ta đã phân tích các chỉ số chính trong các hoạt động kinh doanh bán lẻ trực tuyến. Trong bài viết này, chúng ta sẽ tập trung vào khách hàng và sự phân khúc khách hàng.
Đến lúc này sẽ có nhiều bạn đặt ra câu hỏi, tại sao chúng ta cần phải thực hiện giai đoạn này?
Vì mỗi khách hàng cần có sự đối xử khác nhau tùy vào tính cách, hành vi và độ tuổi của họ, không thể cùng đối xử với mọi khách hàng theo cùng một cách giống nhau.
Như cùng một nội dung, một kênh và cùng một tầm quan trọng được. Vì như vậy khách hàng họ sẽ tìm đến một thương hiệu khác hiểu và tôn trọng họ hơn.
Bạn có thể thực hiện nhiều phân đoạn khác nhau tùy theo nhu cầu mà bạn đang tìm hiểu. Chẳng hạn như, bạn muốn tăng tỷ lệ giữ chân khách hàng, bạn có thể thực hiện phân đoạn dựa trên xác suất churn. Và bạn còn chần chừ gì nữa mà không bắt tay vào việc hành động ngay!
Ngoài ra cũng có những phương pháp phân đoạn rất phổ biến và hữu ích khác. Dưới đây chúng ta sẽ tìm hiểu một trong số chúng là: RFM
Bạn có thể tham khảo thêm bài viết này để biết rõ hơn về khái niệm RFM là gì nhé!
Về phương pháp luận, chúng ta cần tính toán lần truy cập gần đây, tần suất, giá trị tiền tệ cũng như áp dụng machine learning không giám sát để xác định các nhóm (cụm) khác nhau. Hãy bắt đầu viết mã và xem cách thực hiện phân cụm RFM dưới đây nhé!
Lần truy cập gần đây
Để tính toán lần truy cập gần đây, chúng ta cần tìm hiểu xem ngày mua hàng gần đây nhất của từng khách hàng và xem xem họ đã không hoạt động trong bao nhiêu ngày.
Sau đó chúng ta sẽ áp dụng công thức sau: K-means * clustering
để kiếm ra số lần truy cập gần đây của khách hàng.
Trước khi chuyển sang tính toán lần truy cập gần đây, hãy cùng tóm tắt lại công việc dữ liệu mà chúng ta đã thực hiện trước đây.
# import libraries
from datetime import datetime, timedelta
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from __future__ import division
import plotly.plotly as py
import plotly.offline as pyoff
import plotly.graph_objs as go
#inititate Plotly
pyoff.init_notebook_mode()
#load our data from CSV
tx_data = pd.read_csv('data.csv')
#convert the string date field to datetime
tx_data['InvoiceDate'] = pd.to_datetime(tx_data['InvoiceDate'])
#we will be using only UK data
tx_uk = tx_data.query("Country=='United Kingdom'").reset_index(drop=True)
Bây giờ chúng ta có thể tính toán lần truy cập gần đây:
#create a generic user dataframe to keep CustomerID and new segmentation scores
tx_user = pd.DataFrame(tx_data['CustomerID'].unique())
tx_user.columns = ['CustomerID']
#get the max purchase date for each customer and create a dataframe with it
tx_max_purchase = tx_uk.groupby('CustomerID').InvoiceDate.max().reset_index()
tx_max_purchase.columns = ['CustomerID','MaxPurchaseDate']
#we take our observation point as the max invoice date in our dataset
tx_max_purchase['Recency'] = (tx_max_purchase['MaxPurchaseDate'].max() - tx_max_purchase['MaxPurchaseDate']).dt.days
#merge this dataframe to our new user dataframe
tx_user = pd.merge(tx_user, tx_max_purchase[['CustomerID','Recency']], on='CustomerID')
tx_user.head()
#plot a recency histogram
plot_data = [
go.Histogram(
x=tx_user['Recency']
)
]
plot_layout = go.Layout(
title='Recency'
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)
Khung dữ liệu mới tx_user của chúng ta hiện chứa dữ liệu lần truy cập gần đây:
Để có một cái nhìn nhanh về lần gần đây trông như thế nào, chúng ta có thể sử dụng phương thức .describe () của pandas. Nó sẽ hiển thị giá trị trung bình, tối thiểu, tối đa, số lượng và phần trăm dữ liệu.
Đoạn mã ở trên có biểu đồ để cho chúng ta thấy sự phân bổ lần truy cập gần đây của các khách hàng.
Tiếp theo, chúng ta sẽ đến với một phần khá là thú vị.
Chúng ta sẽ áp dụng phân cụm K-mean để chỉ định điểm số lần truy cập gần đây. Nhưng chúng ta cần biết có bao nhiêu cụm đối với thuật toán K-mean. Để tìm ra nó, chúng ta sẽ áp dụng phương pháp Elbow.
Phương pháp Elbow chỉ đơn giản cho biết số cụm tối ưu để có quán tính tối ưu. Đoạn mã và biểu đồ quán tính như sau:
from sklearn.cluster import KMeans
sse={}
tx_recency = tx_user[['Recency']]
for k in range(1, 10):
kmeans = KMeans(n_clusters=k, max_iter=1000).fit(tx_recency)
tx_recency["clusters"] = kmeans.labels_
sse[k] = kmeans.inertia_
plt.figure()
plt.plot(list(sse.keys()), list(sse.values()))
plt.xlabel("Number of cluster")
plt.show()
Ở đây có vẻ như số 3 là cái tối ưu. Dựa theo yêu cầu kinh doanh, chúng ta có thể tiếp tục với ít hoặc nhiều cụm hơn. Chúng ta sẽ chọn số4 cho ví dụ này:
#build 4 clusters for recency and add it to dataframe
kmeans = KMeans(n_clusters=4)
kmeans.fit(tx_user[['Recency']])
tx_user['RecencyCluster'] = kmeans.predict(tx_user[['Recency']])
#function for ordering cluster numbers
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
tx_user = order_cluster('RecencyCluster', 'Recency',tx_user,False)
Chúng ta đã tính toán các cụm và gán chúng cho từng khách hàng trong dataframe tx_user.
Chúng ta có thể thấy các cụm với lần truy cập gần đây có các đặc điểm khác nhau như thế nào. Khách hàng ở cụm 1 rất gần so với cụm 2.
Chúng ta đã thêm một hàm vào mã, đó là order_cluster (). K-mean chỉ định các cụm dưới dạng số nhưng không theo cách có thứ tự. Chúng ta không thể nói cụm 0 là kém nhất và cụm 4 là tốt nhất.
Phương thức order_cluster () thực hiện điều này và khung dữ liệu mới của chúng ta đã trông gọn gàng hơn rất nhiều:
Các bạn hãy áp dụng tương tự cho tần suất và doanh thu.
Tính thường xuyên
Để tạo cụm tần suất, chúng ta cần tìm tổng số đơn đặt hàng cho mỗi khách hàng. Trước tiên, hãy cùng tính xem tần suất sẽ trông như thế nào trong cơ sở dữ liệu khách hàng của chúng ta:
#get order counts for each user and create a dataframe with it
tx_frequency = tx_uk.groupby('CustomerID').InvoiceDate.count().reset_index()
tx_frequency.columns = ['CustomerID','Frequency']
#add this data to our main dataframe
tx_user = pd.merge(tx_user, tx_frequency, on='CustomerID')
#plot the histogram
plot_data = [
go.Histogram(
x=tx_user.query('Frequency < 1000')['Frequency']
)
]
plot_layout = go.Layout(
title='Frequency'
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)
Áp dụng cùng một logic để có các cụm tần số và gán điều này cho từng khách hàng:
#k-means
kmeans = KMeans(n_clusters=4)
kmeans.fit(tx_user[['Frequency']])
tx_user['FrequencyCluster'] = kmeans.predict(tx_user[['Frequency']])
#order the frequency cluster
tx_user = order_cluster('FrequencyCluster', 'Frequency',tx_user,True)
#see details of each cluster
tx_user.groupby('FrequencyCluster')['Frequency'].describe()
Đặc điểm của các cụm tần số của chúng ta sẽ trông giống như dưới đây:
Theo ký hiệu tương tự như các cụm lần truy cập gần đây, số tần suất cao cho biết khách hàng hoạt động tốt hơn.
Doanh thu
Tiếp đến chúng ta hãy xem cơ sở dữ liệu khách hàng sẽ trông như thế nào khi chúng ta phân nhóm chúng dựa trên doanh thu. Chúng ta sẽ tính toán doanh thu cho từng khách hàng, vẽ biểu đồ và áp dụng cùng một phương pháp phân nhóm.
#calculate revenue for each customer
tx_uk['Revenue'] = tx_uk['UnitPrice'] * tx_uk['Quantity']
tx_revenue = tx_uk.groupby('CustomerID').Revenue.sum().reset_index()
#merge it with our main dataframe
tx_user = pd.merge(tx_user, tx_revenue, on='CustomerID')
#plot the histogram
plot_data = [
go.Histogram(
x=tx_user.query('Revenue < 10000')['Revenue']
)
]
plot_layout = go.Layout(
title='Monetary Value'
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)
Chúng ta cũng có một số khách hàng có doanh thu âm. Hãy tiếp tục và áp dụng k-means clustering:
#apply clustering
kmeans = KMeans(n_clusters=4)
kmeans.fit(tx_user[['Revenue']])
tx_user['RevenueCluster'] = kmeans.predict(tx_user[['Revenue']])
#order the cluster numbers
tx_user = order_cluster('RevenueCluster', 'Revenue',tx_user,True)
#show details of the dataframe
tx_user.groupby('RevenueCluster')['Revenue'].describe()
Tổng điểm
Thật là đáng kinh ngạc khi chúng ta có điểm số(số cụm) cho lần truy cập gần đây cùng với tần suất và doanh thu. Hãy cùng tạo ra một điểm tổng thể từ chúng:
#calculate overall score and use mean() to see details
tx_user['OverallScore'] = tx_user['RecencyCluster'] + tx_user['FrequencyCluster'] + tx_user['RevenueCluster']
tx_user.groupby('OverallScore')['Recency','Frequency','Revenue'].mean()
Việc cho điểm ở trên, cho chúng ta thấy rõ rằng khách hàng có điểm 8 là khách hàng tiềm năng nhất và khách hàng có điểm 0 là khách hàng ít tiềm năng nhất.
Để giữ cho mọi thứ đơn giản, chúng ta sẽ quy định giá trị cho những con số này:
- 0 đến 2: giá trị thấp
- 3 đến 4: giá trị trung bình
- Trên 5: giá trị cao
Chúng ta có thể dễ dàng áp dụng cách đặt giá trị này trên khung dữ liệu của mình:
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'
Bây giờ hãy xem các phân đoạn của chúng ta sẽ được phân phối như thế nào trên biểu đồ phân tán:
Bạn có thể thấy các phân đoạn được phân biệt rõ ràng với nhau như thế nào về RFM. Bạn có thể tìm thấy các đoạn mã đồ thị bên dưới:
#Revenue vs Frequency
tx_graph = tx_user.query("Revenue < 50000 and Frequency < 2000")
plot_data = [
go.Scatter(
x=tx_graph.query("Segment == 'Low-Value'")['Frequency'],
y=tx_graph.query("Segment == 'Low-Value'")['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'")['Frequency'],
y=tx_graph.query("Segment == 'Mid-Value'")['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'")['Frequency'],
y=tx_graph.query("Segment == 'High-Value'")['Revenue'],
mode='markers',
name='High',
marker= dict(size= 11,
line= dict(width=1),
color= 'red',
opacity= 0.9
)
),
]
plot_layout = go.Layout(
yaxis= {'title': "Revenue"},
xaxis= {'title': "Frequency"},
title='Segments'
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)
#Revenue Recency
tx_graph = tx_user.query("Revenue < 50000 and Frequency < 2000")
plot_data = [
go.Scatter(
x=tx_graph.query("Segment == 'Low-Value'")['Recency'],
y=tx_graph.query("Segment == 'Low-Value'")['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'")['Recency'],
y=tx_graph.query("Segment == 'Mid-Value'")['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'")['Recency'],
y=tx_graph.query("Segment == 'High-Value'")['Revenue'],
mode='markers',
name='High',
marker= dict(size= 11,
line= dict(width=1),
color= 'red',
opacity= 0.9
)
),
]
plot_layout = go.Layout(
yaxis= {'title': "Revenue"},
xaxis= {'title': "Recency"},
title='Segments'
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)
# Revenue vs Frequency
tx_graph = tx_user.query("Revenue < 50000 and Frequency < 2000")
plot_data = [
go.Scatter(
x=tx_graph.query("Segment == 'Low-Value'")['Recency'],
y=tx_graph.query("Segment == 'Low-Value'")['Frequency'],
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'")['Recency'],
y=tx_graph.query("Segment == 'Mid-Value'")['Frequency'],
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'")['Recency'],
y=tx_graph.query("Segment == 'High-Value'")['Frequency'],
mode='markers',
name='High',
marker= dict(size= 11,
line= dict(width=1),
color= 'red',
opacity= 0.9
)
),
]
plot_layout = go.Layout(
yaxis= {'title': "Frequency"},
xaxis= {'title': "Recency"},
title='Segments'
)
fig = go.Figure(data=plot_data, layout=plot_layout)
pyoff.iplot(fig)
Chúng ta sẽ cùng bắt tay vào việc thực hiện các phân đoạn này cùng với các chiến lược chính khá rõ ràng như:
- Giá trị cao: cải thiện tỷ lệ giữ chân khách hàng
- Giá trị trung bình: cải thiện tỷ lệ giữ chân khách hàng + tăng tần suất
- Giá trị thấp: tăng tần suất
Càng vào chuyên sâu sẽ càng thú vị và hấp dẫn hơn!
Trong phần tiếp theo (phần 3), chúng ta sẽ cùng tìm hiểu về việc tính toán và cùng dự đoán giá trị vòng đời của khách hàng. Hẹn gặp lại các bạn trong phần tiếp theo nhé.
Bài viết được dịch từ đâ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