電商數據基於聚類的精準營銷項目

總體思路

基於聚類的精準推薦總體

  • 先基於聚類:
    • 把用戶分羣,對每一個客戶都標記上標籤值。
  • 生成推薦規則:
    • 在用戶沒買過的商品中,同類客戶總購買次數(平均購買次數)最多的商品,就是這類客戶最喜歡的商品

數據清洗

  • 優先刪除:
    • 缺失率90%以上
    • 整個字段只有1個值
    • 整個字段有效信息幾乎沒有
  • 需要轉碼:
    • 啞變量編碼

數據整合

  • 目的是生成一張用戶所有購買行爲的信息表
    • 三表進行連接合並
# 導入數據包
import numpy as np
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
plt.style.use('seaborn')
plt.rcParams['font.sans-serif']=['Simhei']  #顯示中文,解決圖中無法顯示中文的問題
plt.rcParams['axes.unicode_minus']=False    #設置顯示中文後,負號顯示受影響。解決座標軸上亂碼問題 

數據清洗

訂單表清洗

數據初步探索

order = pd.read_csv(r"...\order.csv",index_col=0)
order.head(1)
訂單編號 買家會員名 買家應付貨款 買家應付郵費 買家支付積分 總金額 返點積分 買家實際支付金額 買家實際支付積分 訂單狀態 ... 是否代付 定金排名 修改後的sku 修改後的收貨地址 異常信息 天貓卡券抵扣 集分寶抵扣 是否是O2O交易 退款金額 預約門店
0 21407300627014900 1425 58.51 0.0 0 58.51 0 58.51 0 交易成功 ... NaN NaN NaN NaN NaN NaN NaN 0.0 NaN

1 rows × 45 columns

order.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 3989 entries, 0 to 3988
Data columns (total 45 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   訂單編號      3989 non-null   int64  
 1   買家會員名     3989 non-null   int64  
 2   買家應付貨款    3989 non-null   float64
 3   買家應付郵費    3989 non-null   float64
 4   買家支付積分    3989 non-null   int64  
 5   總金額       3989 non-null   float64
 6   返點積分      3989 non-null   int64  
 7   買家實際支付金額  3989 non-null   float64
 8   買家實際支付積分  3989 non-null   int64  
 9   訂單狀態      3989 non-null   object 
 10  買家留言      384 non-null    object 
 11  收貨人姓名     3989 non-null   int64  
 12  收貨地址      3989 non-null   object 
 13  運送方式      3989 non-null   object 
 14  聯繫電話      142 non-null    object 
 15  聯繫手機      3986 non-null   object 
 16  訂單創建時間    3989 non-null   object 
 17  訂單付款時間    3989 non-null   object 
 18  寶貝標題      3989 non-null   object 
 19  寶貝種類      3989 non-null   int64  
 20  物流單號      3988 non-null   object 
 21  物流公司      3988 non-null   object 
 22  訂單備註      460 non-null    object 
 23  寶貝總數量     3989 non-null   int64  
 24  店鋪Id      3989 non-null   int64  
 25  店鋪名稱      3989 non-null   int64  
 26  訂單關閉原因    3989 non-null   object 
 27  賣家服務費     3989 non-null   int64  
 28  買家服務費     3989 non-null   object 
 29  發票擡頭      0 non-null      float64
 30  是否手機訂單    3728 non-null   object 
 31  分階段訂單信息   0 non-null      float64
 32  特權訂金訂單id  0 non-null      float64
 33  是否上傳合同照片  3989 non-null   object 
 34  是否上傳小票    3989 non-null   object 
 35  是否代付      3989 non-null   object 
 36  定金排名      0 non-null      float64
 37  修改後的sku   0 non-null      float64
 38  修改後的收貨地址  61 non-null     object 
 39  異常信息      0 non-null      float64
 40  天貓卡券抵扣    0 non-null      float64
 41  集分寶抵扣     12 non-null     float64
 42  是否是O2O交易  0 non-null      float64
 43  退款金額      3989 non-null   float64
 44  預約門店      0 non-null      float64
dtypes: float64(15), int64(11), object(19)
memory usage: 1.6+ MB

刪除無用信息

# 刪除空值項大於20%字段:
order=order.dropna(axis=1,thresh=order.shape[0]*0.2)

#刪除整個字段只有一個信息的值:
for  i in order.columns:
    if order[i].nunique()==1:
        del order[i]  
        
# 手動選擇與用戶購買信息有關字段
order=order[["訂單編號","買家會員名","買家實際支付金額","收貨地址","寶貝標題 ","寶貝種類","寶貝總數量","退款金額"]]

數據編碼

#退款金額0-1獨熱編碼
order.退款金額=np.where(order.退款金額>0,1,0)

#收貨地址獨熱編碼
address=order.收貨地址.str[:3].str.strip()
address=pd.get_dummies(address,prefix="地址")


#寶貝種類獨熱編碼
kinds=pd.get_dummies(order.寶貝種類,prefix="寶貝種類")

#刪除原表中已經編碼完成的字段,將編碼完成後字段加入訂單表
order=order.drop(["收貨地址","寶貝種類"],axis=1)
order=pd.concat([order,address,kinds],axis=1)
order.head(1)
訂單編號 買家會員名 買家實際支付金額 寶貝標題 寶貝總數量 退款金額 地址_上海 地址_雲南省 地址_內蒙古 地址_北京 ... 寶貝種類_39 寶貝種類_40 寶貝種類_41 寶貝種類_43 寶貝種類_45 寶貝種類_46 寶貝種類_47 寶貝種類_48 寶貝種類_49 寶貝種類_50
0 21407300627014900 1425 58.51 ... 59 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0

1 rows × 83 columns

訂單詳情表清洗

數據初步探索

order_detail=pd.read_csv(r"...\Items_order.csv")
order_detail.head(1)
訂單編號 標題 價格 購買數量 外部系統編號 商品屬性 套餐信息 備註 訂單狀態 商家編碼
0 21407300627014900 ... 0.58 12 WY013-2SZD0426 顏色分類:小號 NaN NaN 交易成功 WY013-2SZD0426
order_detail.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 21897 entries, 0 to 21896
Data columns (total 10 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   訂單編號    21897 non-null  int64  
 1   標題      21897 non-null  object 
 2   價格      21897 non-null  float64
 3   購買數量    21897 non-null  int64  
 4   外部系統編號  21897 non-null  object 
 5   商品屬性    12636 non-null  object 
 6   套餐信息    0 non-null      float64
 7   備註      130 non-null    object 
 8   訂單狀態    21897 non-null  object 
 9   商家編碼    21897 non-null  object 
dtypes: float64(2), int64(2), object(6)
memory usage: 1.7+ MB

刪除無用信息

order_detail=order_detail.dropna(axis=1,thresh=order_detail.shape[0]*0.2)

for  i in order_detail.columns:
    if order_detail[i].nunique()==1:
        del order_detail[i]        
        
order_detail=order_detail[["訂單編號","標題","價格","購買數量","訂單狀態"]]

# 篩選交易成功的記錄
order_detail=order_detail[order_detail.訂單狀態=="交易成功"]
order_detail=order_detail.reset_index(drop=True).iloc[:,:-1]
order_detail.head(1)
訂單編號 標題 價格 購買數量
0 21407300627014900 ... 0.58 12

商品詳情表

數據初步探索

items_detail=pd.read_csv(r"...\Items_attribute.csv")
items_detail.head(1)
寶貝ID 標題 價格 玩具類型 適用年齡 品牌
0 537396783238 ... 8.9 塑膠玩具 3歲,4歲,5歲,6歲 3
items_detail.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 288 entries, 0 to 287
Data columns (total 6 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   寶貝ID    288 non-null    int64  
 1   標題      288 non-null    object 
 2   價格      288 non-null    float64
 3   玩具類型    252 non-null    object 
 4   適用年齡    284 non-null    object 
 5   品牌      288 non-null    int64  
dtypes: float64(1), int64(2), object(3)
memory usage: 13.6+ KB

數據編碼

#填充缺失值:
items_detail.適用年齡=items_detail.適用年齡.fillna(items_detail.適用年齡.mode()[0])

a=[]
for i in items_detail.適用年齡.value_counts().index:
    a.extend(i.split(","))    
a=list(set(a))
# 對出現的所有年齡小標籤作人工分類:
baby=["3個月","6個月","12個月"]
youer=['18個月','2歲','3歲']
xueqian=['4歲','5歲','6歲']
stu=['7歲','8歲','9歲','10歲','11歲','12歲','13歲','14歲','14歲以上']
def change(x):
    a=x.split(",")
    st=""
    for i in a:
        if i in baby:
            if st.find("嬰兒")!=-1:
                continue
            st=st+"嬰兒|"
        elif i in youer:
            if st.find("幼兒")!=-1:
                continue
            st=st+"幼兒|"
        elif i in xueqian:
            if st.find("學前")!=-1:
                continue
            st=st+"學前|"           
        else:
            if st.find("學生")!=-1:
                continue
            st=st+"學生|"    
    return st
age=items_detail.適用年齡.apply(change)
age=age.str.get_dummies("|")
age.columns="年齡_"+age.columns
age
年齡_嬰兒 年齡_學前 年齡_學生 年齡_幼兒
0 0 1 0 1
1 0 1 0 1
2 0 1 1 1
3 0 1 1 1
4 0 1 0 1
... ... ... ... ...
283 0 1 1 1
284 0 1 1 1
285 1 0 0 1
286 0 1 1 1
287 0 1 1 1

288 rows × 4 columns

#品牌字段處理
items_detail.品牌.isnull().sum()
brand=pd.get_dummies(items_detail.品牌,prefix="品牌")
#商品詳情表
items_detail=pd.concat([items_detail.iloc[:,:3],age,brand],axis=1)

表合併

三表合一個表

#表合併的目的:在三張表中,儘可能地保留**客戶的購買行爲信息

table_01 = pd.merge(order_detail, items_detail, how="inner", on="標題")

#第二次表合併

table_02 = pd.merge(table_01, order, how="left", on="訂單編號")

先把介意直接求和的客戶信息表製作出來

#把table_02轉化爲一行記錄一個用戶所有購買行爲的信息表。

#  刪除重複值
table_02 = table_02.drop_duplicates()

table_03 = table_02.drop(["訂單編號", "標題", "寶貝ID", "寶貝標題 ", "價格_x", "價格_y"],
                         axis=1)

table_04 = table_03.drop(["買家實際支付金額", "寶貝總數量"], axis=1)

order_tag_01 = table_04.groupby("買家會員名").sum()

再把不能直接求和的用order 表求得金額

table_05 = table_02[["訂單編號", "買家會員名", "買家實際支付金額", "寶貝總數量"]]

order_tag_02 = order.groupby("買家會員名")[["買家實際支付金額", "寶貝總數量"]].mean()

得到用戶購買行爲信息表

order_tag_all = pd.merge(order_tag_01, order_tag_02, how="inner", on="買家會員名")

# 看一下缺失值
order_tag_all.isnull().sum()[order_tag_all.isnull().sum() != 0]
Series([], dtype: int64)

數據建模

初次建模

# 歸一化。

mms=MinMaxScaler()
data_norm=mms.fit_transform(order_tag_all.values)

# 手肘法調參

sse=[]
for k in range(1,25):
    km=KMeans(n_clusters=k)
    km.fit(data_norm)
    sse.append(km.inertia_)
#可視化學習曲線   
plt.plot(range(1,25),sse,marker="o")
[<matplotlib.lines.Line2D at 0x2a51b044448>]

在這裏插入圖片描述

刪除無效字段後 再次建模

# 批量刪除“寶貝種類”這些字段
a = []
for i in order_tag_all.columns:
    if i.find("寶貝種類")!=-1 or i.find("地址")!=-1 or i.find("品牌")!=-1 :
        a.append(i)       
order_tag_all.drop(a,axis=1,inplace=True)
# 重新再做歸一化

mms=MinMaxScaler()
data_norm=mms.fit_transform(order_tag_all.values)

# 擬合模型

import matplotlib.pyplot as plt
sse=[]
for k in range(1,25):
    km=KMeans(n_clusters=k)
    km.fit(data_norm)
    sse.append(km.inertia_)


plt.plot(range(1,25),sse,marker="o")
[<matplotlib.lines.Line2D at 0x2a522cdae88>]

在這裏插入圖片描述

# 輪廓係數圖確定參數k
score=[]
for k in range(2,25):
    km=KMeans(n_clusters=k)
    res_km=km.fit(data_norm)
    score.append(silhouette_score(data_norm,res_km.labels_))
# 可視化輪廓係數   
plt.plot(range(2,25),score,marker="o")
[<matplotlib.lines.Line2D at 0x2a5228d4688>]

在這裏插入圖片描述

# 在k爲5的時候,模型能夠兼顧sse較小且輪廓係數較大。

用k=5 生成最後模型,打上標籤

# 重新建模

km=KMeans(n_clusters=5)
km.fit(data_norm)
clusters=km.labels_
pd.Series(clusters).value_counts()


# 把不同的會員和對應的標籤匹配上:
order_tag_all["類別"]=clusters
result=order_tag_all["類別"]

推薦系統

思路

  • 篩選出來所有會員沒購買的商品
  • 找到對應會員所屬的客戶類別購買次數最多的商品

用戶-商品-購買次數表

user_itmes=pd.merge(order_detail,order,how="left",on="訂單編號")
user_itmes=user_itmes[["買家會員名","標題"]]
user_itmes["購買次數"]=1


# 透視的字段“購買次數”,計算所有會員對所有商品的購買總次數,

user_itmes=user_itmes.pivot_table("購買次數","買家會員名","標題",aggfunc=np.sum).fillna(0)
user_itmes=user_itmes.stack().reset_index()
user_itmes.rename(columns={0:"購買次數"},inplace=True)

user_itmes.head(2)
買家會員名 標題 購買次數
0 0 ... 0.0
1 0 ... 0.0

用戶-未購買商品表

user_item_notbuy=user_itmes[user_itmes.購買次數==0.0]
買家會員名 標題 購買次數
0 0 ... 0.0
1 0 ... 0.0
2 0 .. 0.0
3 0 .. 0.0
4 0 ... 0.0

user_item_notbuy只記錄用戶對未購買商品的信息。

用戶- 未購買商品-類別表

user_itme_notbuy_clu = pd.merge(user_item_notbuy,result,how='left',on='買家會員名')
del user_itme_notbuy_clu['購買次數']

user_itme_notbuy_clu=user_itme_notbuy_clu.dropna()
user_itme_notbuy_clu.reset_index(drop=True,inplace=True)

cluster_item_num=pd.merge(user_itmes,result,how="left",on="買家會員名").iloc[:,1:]
clusters=pd.DataFrame(result).reset_index()
user_itme_notbuy_clu=pd.merge(user_item_notbuy,clusters,how="left",on="買家會員名")
user_itme_notbuy_clu.drop("購買次數",axis=1,inplace=True)
user_itme_notbuy_clu=user_itme_notbuy_clu.dropna()

類別-商品-購買次數表

cluster_item_num=pd.merge(user_itmes,result,how="left",on="買家會員名").iloc[:,1:]

#不同類別的客戶對不同商品的購買總次數表

cluster_item_num=cluster_item_num.groupby(["類別","標題"]).sum().reset_index()

最終推薦表

# 最終要從user_itme_notbuy_clu提取前3列,以及cluster_item_num最後一列,通過表連接的方式合併提取:

user_notbuy_fre=pd.merge(user_itme_notbuy_clu,cluster_item_num,how="left",on=["類別","標題"])

#定義函數用來生成推薦指數
def sort1(x):
    s =x.sort_values('購買次數',ascending=False)[0:5]
    s['推薦指數'] = ["❤❤❤❤❤","❤❤❤❤","❤❤❤","❤❤","❤"]
    return s

yd = user_notbuy_fre.groupby('買家會員名').apply(sort1).reset_index(drop=True)

yd.head(5)
買家會員名 標題 類別 購買次數 推薦指數
0 0 .. 0.0 217.0 ❤❤❤❤❤
1 0 .. 0.0 209.0 ❤❤❤❤
2 0 .. 0.0 199.0 ❤❤❤
3 0 ... 0.0 187.0 ❤❤
4 0 ... 0.0 141.0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章