04/11/2019, 20:51

Marketing với Python Part 2 - Phân Khúc Khách Hàng

Phân khúc khách hàng Phân khúc khách hàng sử dụng mô hình RFM Loạt bài bài viết được thiết kế để giải thích làm thế nào sử dụng Python để phát triển công ty theo hướng phân tích dữ liệu. Các bài viết sẽ bao gồm các kỹ thuật như: lập trình python, phân tích dữ liệu, máy học. Chúng ta ...

Phân khúc khách hàng

Phân khúc khách hàng sử dụng mô hình RFM

Loạt bài bài viết được thiết kế để giải thích làm thế nào sử dụng Python để phát triển công ty theo hướng phân tích dữ liệu. Các bài viết sẽ bao gồm các kỹ thuật như: lập trình python, phân tích dữ liệu, máy học. Chúng ta sẽ đi tìm hiểu các chủ đề sau:

  1. Hiểu dữ liệu của bạn
  2. Phân khúc khách hàng
  3. Dự đoán lợi nhuận từ khách hàng
  4. Dự đoán khách hàng rời bỏ sử dụng dịch vụ của công ty
  5. Dự đoán ngày mua hàng tiếp theo của khách hàng
  6. Dự đoán tình hình kinh doanh
  7. Kiểm thử đánh giá các chiến dịch Marketing
  8. Upsell
  9. A/B testing

Bài viết sử dụng Python và Pandas, nên nếu các bạn chưa biết thì có thể tìm hiểu trước Python và Pandas nhé. Hoặc các bạn làm Marketing chưa biết code, vẫn có thể đọc qua bài viết để hiểu ý tưởng sử dụng dữ liệu hiện có để phát triển công ty.

Sometimes you gotta run before you can walk - Tony Stark

Yêu cầu hệ thống: cài Jupyter Notebook và Python

Phần 2: Phân khúc khách hàng

Ở bài viết trước, chúng ta đã tìm hiểu, phân tích dữ liệu của một công ty bán lẻ trực tuyến và tìm ra các yếu tố ảnh hưởng đến doanh thu lợi nhuận của công ty (vd: tỷ lệ khách hàng cũ tiếp tục sử dụng dịch vụ của công ty - Retention Rate ). Chúng ta đã biết cách sử dụng Python và Pandas thống kê và tìm hiểu các yếu tố đó. Bây giờ, chúng ta sẽ tập trung vào khách hàng và tìm cách phân loại khách hàng theo nhóm để phục vụ cho nhu cầu marketing sau này.

Chúng ta cần phải thực hiện công việc phân nhóm, phân loại khách hàng..., bởi vì chúng ta không thể đối xử tất cả khách hàng giống nhau: ví dụ, mỗi chiến dịch marketing sẽ nhắm vào một phân khúc khách hàng khác nhau, nội dung khách nhau, kênh phân phối chiến dịch khách nhau...

Khi khách hàng đến với chúng ta, họ có các nhu cầu riêng biệt, chúng ta phải tìm cách phản hồi và hành động dựa trên các nhu cầu này đối với từng khách hàng riêng biệt.

Có rất nhiều cách, phương thức để phân loại khách hàng. Trong bài viết này, chúng ta sẽ phân loại khách hàng dựa trên mô hình RFM, một mô hình rất hay được sử dụng để đo tỷ lệ sử dụng dịch vụ của khách hàng, đồng thời có thể được sử dụng để đánh giá sản phẩm dịch vụ của công ty có phù hợp với thị trường hay không.

RFM là các từ viết tắt của Recency - Frequency - Monetary Value, dịch theo tiếng Việt có nghĩa là: hành động gần đây nhất, bao nhiêu lần và có giá trị bao nhiêu. Nếu xét trong ngữ cảnh của một nhà bán lẻ, dựa trên các hóa đơn bán hàng, thì các thông số này sẽ là: lần mua gần nhất, bao nhiêu lần mua, và giá trị tổng các lần giao dịch là bao nhiêu.

Chúng ta sẽ phân nhóm khách hàng theo các phân khúc sau:

  • Giá trị thấp (low value): là nhóm khách hàng mua ít hơn nhóm khác, ít thường xuyên sử dụng dịch vụ, và mang về lợi nhuận cho công ty thấp.
  • Giá trị trung bình (Mid value): các chỉ số mua sắm, sử dụng dịch vụ và lợi nhuận mang về cho công ty đề ở mức trung bình.
  • Giá trị cao (hight value): đây là phân khúc khách hàng quan trọng nhất, mang về lợi nhuận cao cho công ty và thường xuyên sử dụng dịch vụ nhất.

Để phân khúc khách hàng theo mô hình RFM, chúng ta cần phải tính các thông số Recency, Frequency and Monetary Value và sử dụng phương pháp máy học không giám sát (unsupervised machine learning) để phân nhóm gôm cụm khách hàng. Trong bài viết, mình sẽ sử dụng nhiều thuật ngữ tiếng anh, vì nếu dịch sang tiếng Việt sẽ rất dài dòng, mong các bạn thông cảm nhé.

Recency - R Để tính thông số R này, chúng ta cần tìm ra ngày mua gần đây nhất của khách hàng và số ngày không sử dụng dịch vụ của họ - inactive days (tính từ thời điểm mua gần nhất đến thời điểm đang xét). Sau khi có con số inactive days của mỗi khách hàng, chúng ta sẽ áp dụng thuật toán phân nhóm gôm cụm K-means để tính điểm recency

Bài viết sẽ tiếp tục sử dụng dữ liệu giống như bài trước, các bạn có thể download tại đây. Vẫn tiếp tục sử dụng các dữ liệu phát sinh từ UK

# 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)

Tính recency (R)

#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)

Tiếp tục, chúng ta xem xét dữ liệu Rencency phân phối như thế nào: mean, min, max, count and % bằng hàm describe()

Chúng ta có thể thấy rằng, nếu tính trung bình cho tập dự liệu recency đang có, thì con số này là 90 ngày (mean), và theo số phần trăm, thì có đến 50% dữ liệu khách hàng có số recency là 49 ngày.

Cũng với đoạn code trên, cho ta biểu đồ phân bổ số liệu Recency của khách hàng

Giờ sẽ đến phần chính của bài, chúng ta sẽ áp dụng thuật toán phân nhóm K-means để tính điểm recency. Nhưng trước tiên, thì chúng ta phải cho thuật toán biết cần phân bao nhiêu nhóm là hợp lý. Để tìm ra con số này, ta áp dụng phương thức Elbow. Có thể hiểu đơn giản là, phương thức Elbow sẽ cho ta con số cụm tối ưu nhất cho thuật toán K-means.

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()

Chúng ta thấy rằng số lương cụng tối ưu nhất là 3. Nhưng chúng ta có thể lựa số cụm nhỏ hoặc lớn hơn 3, tùy theo yêu cầu kinh doanh. Chúng ta chọn số cụm là 4 cho bài viết 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 đã phân cụm khách hàng, và chỉ định mỗi khách hàng sẽ thuộc 1 cụm khác nhau và tập dữ liệu tx_user.

Chúng ta có thể thấy, cụm 1 là cụm tập khách hàng có recency tốt nhất (càng nhỏ càng tốt), có nghĩa là đây là cụm có khách hàng hoạt động gần đây nhất(mua hàng...)

Chúng ta thực hiện thêm hàm order_cluster() để sắp xếp lại các cụm khách hàng theo theo hướng cụm 0 là tệ nhất -> cụm 3 là tốt nhất...

Tuyệt vời, cụm 3 là cụm có tập khách hàng hoạt động gần đây nhiều nhất.

Tiếp theo, tính toán Frequency và Monetary Value cũng thực hiện giống như trên

Frequency - F

Để phân cụm khách hàng theo F, ta cần phải tìm tổng số đơn hàng của mỗi khách hàng.

#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)

Phân loại khách hàng theo F

#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()

F càng lớn, thì khách hàng đó càng tốt cho công ty (mua nhiều)

Monetary Value - M

Chúng ta sẽ phân nhóm khách hàng theo M. Đầu tiên chúng ta tính M cho mỗi khách hàng, vẽ biểu đồ, và gom cụm giống như các bước tính F

#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 thấy cũng có nhiều khách hàng mang về cho công ty lợi nhuận âm. Tiếp tục gôm cụm:

#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 RFM

Cuối cùng, chúng ta đã có điểm RFM (theo cụm). Tiếp theo chúng ta sẽ tính tổng các điểm này:

#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()

Theo bảng trên, khách hàng có điểm 8 là khách hàng tốt nhất. Để đơn giản, chúng ta sẽ phân tiếp thành 3 nhóm khách hàng:

  • 0 to 2: Low Value
  • 3 to 4: Mid Value
  • 5+: High Value
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' 

Tiếp theo, vẽ hình để xem sự phân bố tập khách hàng như thế nào:

#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(awidth=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(awidth=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(awidth=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(awidth=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(awidth=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(awidth=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(awidth=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(awidth=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(awidth=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)

Từ đây, chúng ta có thể lên chiến lược, hành động với các tập khách hàng này:

  • High Value: Improve Retention
  • Mid Value: Improve Retention + Increase Frequency
  • Low Value: Increase Frequency

Sau bài viết này, hy vọng các bạn có chiến lược marketing phù hợp với từng nhóm khách hàng khác nhau. VD: nhóm khách hàng cần quan tâm nhiều hơn, nhóm khách hàng cần khuyến mãi, tặng coupon giảm giá, nhóm khách hàng cần cân nhắc sử dụng sản phẩm mới của công ty với giá đặc biệt ưu đãi...

Trong phần tiếp theo, chúng ta sẽ tìm hiểu tiếp một thông số quan trọng CLV (Customer Lifetime Value), tính toán lợi nhuận khách hàng mang về cho công ty

Lifetime Value: Total Gross Revenue - Total Cost

0