總體思路
基於聚類的精準推薦總體
先基於聚類:
生成推薦規則:
在用戶沒買過的商品中,同類客戶總購買次數(平均購買次數)最多的商品,就是這類客戶最喜歡的商品
數據清洗
優先刪除:
缺失率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
刪除無用信息
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[ [ "訂單編號" , "買家會員名" , "買家實際支付金額" , "收貨地址" , "寶貝標題 " , "寶貝種類" , "寶貝總數量" , "退款金額" ] ]
數據編碼
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. 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>]
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 生成最後模型,打上標籤
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_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
❤