用戶畫像是通過分析用戶的基礎(chǔ)信息、特征偏好、社會(huì)屬性等各維度的數(shù)據(jù),刻畫出用戶的信息全貌,它是建立在一系列屬性數(shù)據(jù)之上的目標(biāo)用戶模型。
用戶畫像的本質(zhì)是一個(gè)用以描述用戶需求的工具。用戶畫像一般是產(chǎn)品設(shè)計(jì)、運(yùn)營(yíng)人員從用戶群體中抽象出來的典型用戶,從中可以挖掘用戶價(jià)值,提供個(gè)性化推薦、精準(zhǔn)營(yíng)銷等服務(wù)。
用戶畫像主要應(yīng)用有:
- 精準(zhǔn)營(yíng)銷:精準(zhǔn)直郵、短信、App消息推送、個(gè)性化廣告等。
- 用戶研究:指導(dǎo)產(chǎn)品優(yōu)化,甚至做到產(chǎn)品功能的私人定制等。
- 個(gè)性服務(wù):個(gè)性化推薦、個(gè)性化搜索等。
- 業(yè)務(wù)決策:排名統(tǒng)計(jì)、地域分析、行業(yè)趨勢(shì)、競(jìng)品分析等。

【一】數(shù)據(jù)集概況
- 導(dǎo)入模塊和數(shù)據(jù)
#導(dǎo)入庫
%matplotlib inline
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import matplotlib
import seaborn as sns
# 指定字體
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['font.family']='sans-serif'
#解決負(fù)號(hào)'-'顯示為方塊的問題
matplotlib.rcParams['axes.unicode_minus'] = False
import pymysql
pymysql.install_as_MySQLdb()
from sqlalchemy import create_engine
import gc
import warnings
warnings.filterwarnings('ignore')
from datetime import datetime
# 導(dǎo)入數(shù)據(jù)集
df = pd.read_excel("order_data.xlsx")
# 導(dǎo)入用戶詳情數(shù)據(jù)集
df_user = pd.read_excel("user_data.xlsx")
訂單數(shù)據(jù)

訂單特征的唯一值數(shù)量
df_count=pd.DataFrame()
for i in ['item_id','behavior_type','item_category','time']:
df_count.loc[i,0]=df[i].nunique()
df_count=df_count.rename(columns={0:'標(biāo)簽數(shù)量'},index={'item_id':'小類別編碼',
'behavior_type':'行為類型',
'item_category':'大類別編碼',
'time':'行為時(shí)間'})
from matplotlib.font_manager import FontProperties
myfont=FontProperties(fname=r'C:\\Windows\\Fonts\\simhei.ttf',size=8)
sns.set(font=myfont.get_name())
plt.figure(figsize=(12,5),dpi=200)
g=sns.barplot(data=df_count,x=df_count.index,y='標(biāo)簽數(shù)量')
plt.title('訂單數(shù)據(jù)庫')
x=df_count.index
y=df_count['標(biāo)簽數(shù)量']
plt.yticks(np.arange(0,100001,20000))
for i,row in enumerate(df_count['標(biāo)簽數(shù)量']):
g.text(i,row+3000,str(row)[:-2]+'種',ha='center',va='center')

用戶數(shù)據(jù)

用戶特征的唯一值數(shù)量
df_user_count=pd.DataFrame()
for i in df_user.drop('user_id',axis=1):
df_user_count.loc[i,0]=df_user[i].nunique()
df_user_count=df_user_count.rename(columns={0:'標(biāo)簽數(shù)量'},index={'gender':'性別',
'age':'年齡',
'city':'城市',
'province':'省份',
'marriage':'婚姻狀況',
'eduction':'學(xué)歷',
'job':'職業(yè)'})
plt.figure(figsize=(10,3),dpi=100)
g=sns.barplot(data=df_user_count,x=df_user_count.index,y='標(biāo)簽數(shù)量')
plt.title('用戶數(shù)據(jù)庫',fontsize=15)
x=df_user_count.index
y=df_user_count['標(biāo)簽數(shù)量']
plt.yticks(np.arange(0,41,5),fontsize=10)
plt.ylabel('標(biāo)簽數(shù)量',fontsize=13)
for i,row in enumerate(df_user_count['標(biāo)簽數(shù)量']):
g.text(i,row+1,str(row)[:-2]+'種',ha='center',va='center',fontsize=10)

城市云詞條
#將用戶瀏覽活躍時(shí)間段加入到用戶標(biāo)簽表中
labels = pd.merge(labels,time_browse_hour,how='left',on='user_id')
labels.rename(columns={'hour':'time_browse'},inplace=True)
#詞云
import wordcloud
import jieba
import jieba.analyse
import codecs
from wordcloud import WordCloud,ImageColorGenerator,STOPWORDS #詞云,顏色生成器,停止詞
import numpy as np #科學(xué)計(jì)算
from PIL import Image
segments = []
stopwords = [line.strip() for line in codecs.open('中文停用詞表.txt', 'r', 'utf-8').readlines()]
jieba.analyse.set_stop_words('中文停用詞表.txt')
labels['city'].to_csv('city.txt',sep='\t',index=False)
text = open("city.txt",encoding='utf8').read()
text = text.replace('\n',"").replace("\u3000","")
text_cut = jieba.lcut(text)
text_cut = ' '.join(text_cut)
background = Image.open("中國地圖.jpg")
graph = np.array(background)
word_cloud = WordCloud(font_path="simsun.ttc",
background_color="white",
mask=graph, # 指定詞云的形狀
stopwords=stopwords)
word_cloud.generate(text_cut)
plt.subplots(figsize=(12,8),dpi=200)
plt.imshow(word_cloud)
plt.axis("off")

df=labels
user_sex_df = df.groupby("gender")["user_id"].count()
## 利用pd.cut進(jìn)行數(shù)據(jù)離散化切分,注意分組標(biāo)簽和分組數(shù)要一致
"""
pandas.cut(x,bins,right=True,labels=None,retbins=False,precision=3,include_lowest=False)
x:需要切分的數(shù)據(jù)
bins:切分區(qū)域
right : 是否包含右端點(diǎn)默認(rèn)True,包含
labels:對(duì)應(yīng)標(biāo)簽,用標(biāo)記來代替返回的bins,若不在該序列中,則返回NaN
retbins:是否返回間距bins
precision:精度
include_lowest:是否包含左端點(diǎn),默認(rèn)False,不包含
"""
bins = [0,20,25,30,35,40,45,50,55,1000]
labels = ["(0-20]","(20-25]","(25-30]","(30-35]","(35-40]","(40-45]","(45-50]","(50-55]","55歲以上"]
df["age_group"] = pd.cut(df["age"],bins=bins,labels=labels)
# 繪制柱狀圖,,rot=0 表示旋轉(zhuǎn)角度,0-360
age_group_df = df.groupby("age_group").user_id.count().reset_index()
# 按省份分類
pro_user_df = df.groupby("province").user_id.count().reset_index().sort_values(by="user_id",ascending=True)
pro_user_df=pro_user_df.sort_values('user_id',ascending=False)
# 按省份分類
city_user_df = df.groupby("city").user_id.count().reset_index().sort_values(by="user_id",ascending=True)
# 按婚姻分類
marry_df = df.groupby("marriage").user_id.count()
# 按學(xué)歷分類
eduction_df = df.groupby("eduction").user_id.count().reset_index()
eduction_df=eduction_df.sort_values('user_id',ascending=False)
# 按工作分類
job_df = df.groupby("job").user_id.count().reset_index()
job_df=job_df.sort_values('user_id',ascending=False)
myfont=FontProperties(fname=r'C:\\Windows\\Fonts\\simhei.ttf',size=8)
sns.set(style='darkgrid',font=myfont.get_name())
plt.figure(figsize=(50,70),dpi=100)
plt.subplot(711)
sns.barplot(data=job_df,x='job',y='user_id',palette='Blues_r')
plt.xticks(fontsize=50)
plt.yticks(range(0,81,20),fontsize=50)
plt.xlabel('職業(yè)',fontsize=55)
plt.ylabel('人數(shù)',fontsize=55)
plt.title('客戶職業(yè)分布',fontsize=60)
for x,y in enumerate(job_df['user_id']):
plt.text(x,y+5,y,fontsize=50,ha='center')
plt.subplot(712)
sns.barplot(data=eduction_df,x='eduction',y='user_id')
plt.xticks(fontsize=50)
plt.yticks(range(0,201,50),fontsize=50)
plt.xlabel('學(xué)歷',fontsize=55)
plt.ylabel('人數(shù)',fontsize=55)
plt.title('客戶學(xué)歷分布',fontsize=60)
for x,y in enumerate(eduction_df['user_id']):
plt.text(x,y+5,y,fontsize=50,ha='center')
plt.subplot(713)
sns.barplot(data=marry_df,x=marry_df.index,y=list(reversed(marry_df.values)))
plt.xticks(fontsize=50)
plt.yticks(range(0,181,90),fontsize=50)
plt.xlabel('婚姻狀態(tài)',fontsize=55)
plt.ylabel('人數(shù)',fontsize=55)
plt.title('客戶婚姻狀態(tài)分布',fontsize=60)
for x,y in enumerate(marry_df.values):
plt.text(x,y+5,y,fontsize=50,ha='center')
plt.subplot(714)
sns.barplot(data=city_user_df,x='city',y='user_id',palette='Greens_r')
plt.xticks(fontsize=50)
plt.yticks(range(0,61,20),fontsize=50)
plt.xlabel('城市',fontsize=55)
plt.ylabel('人數(shù)',fontsize=55)
plt.title('客戶所在城市分布',fontsize=60)
for x,y in enumerate(city_user_df['user_id']):
plt.text(x,y+2,y,fontsize=50,ha='center')
plt.subplot(715)
sns.barplot(data=pro_user_df,x='province',y='user_id',palette='Oranges_r')
plt.xticks(fontsize=50)
plt.yticks(range(0,61,20),fontsize=50)
plt.xlabel('省份',fontsize=55)
plt.ylabel('人數(shù)',fontsize=55)
plt.title('客戶所在省份分布',fontsize=60)
for x,y in enumerate(pro_user_df['user_id']):
plt.text(x,y+2,y,fontsize=50,ha='center')
plt.subplot(716)
sns.barplot(data=user_sex_df1,x=user_sex_df1.gender,y=user_sex_df1.user_id)
plt.xticks(fontsize=50)
plt.yticks(range(0,121,60),fontsize=50)
plt.xlabel('省份',fontsize=55)
plt.ylabel('人數(shù)',fontsize=55)
plt.title('客戶性別分布',fontsize=60)
for x,y in enumerate(user_sex_df1.user_id):
plt.text(x,y+2,y,fontsize=50,ha='center')
plt.subplot(717)
sns.barplot(data=age_group_df,x='age_group',y='user_id',palette='Reds_r')
plt.xticks(fontsize=50)
plt.yticks(range(0,71,20),fontsize=50)
plt.xlabel('年齡',fontsize=55)
plt.ylabel('人數(shù)',fontsize=55)
plt.title('客戶年齡分布',fontsize=60)
for x,y in enumerate(age_group_df['user_id']):
plt.text(x,y+2,y,fontsize=50,ha='center')
plt.tight_layout()
plt.subplots_adjust(wspace=0.5,hspace=0.5)
plt.savefig('711.png')

【二】日期和時(shí)間段處理
#將time字段拆分為日期和時(shí)段
df['date'] = df['time'].str[0:10]
df['date'] = pd.to_datetime(df['date'],format='%Y-%m-%d')
df['time'] = df['time'].str[11:]
df['time'] = df['time'].astype(int)
# 將時(shí)段分為'凌晨'、'上午'、'中午'、'下午'、'晚上',左開右閉區(qū)間
df['hour'] = pd.cut(df['time'],bins=[-1,5,10,13,18,24],labels=['凌晨','上午','中午','下午','晚上'])
myfont=FontProperties(fname=r'C:\Windows\Fonts\simhei.ttf',size=8)
sns.set(font=myfont.get_name())
hour_order=[ '上午', '中午', '下午','晚上', '凌晨']
ax1=plt.figure(figsize=(10,3),dpi=100)
plt.title('用戶活躍時(shí)間分布',fontsize=15)
sns.countplot(data=df,x='hour',order=hour_order,hue='behavior_type')
plt.legend(['瀏覽','收藏','加購','購買'],fontsize=10)
plt.xticks(fontsize=10)
plt.yticks(fontsize=10)
plt.xlabel('時(shí)間',fontsize=13)
plt.ylabel('合計(jì)數(shù)量',fontsize=13)
ax2=plt.figure(figsize=(10,3),dpi=100)
ax2=sns.countplot(df['date'],order=sorted(df['date'].unique()))
plt.xticks(rotation=90,fontsize=15)
ax2.set_title('用戶活躍日期分布(不區(qū)分具體行為)',fontsize=15,ha='center')
plt.xticks(fontsize=10)
plt.yticks(fontsize=10)
plt.xlabel('(年-月-日)',fontsize=13)
plt.ylabel('合計(jì)數(shù)量',fontsize=13)
一天當(dāng)中,用戶晚上活動(dòng)最為頻繁,其次是下午,凌晨活動(dòng)頻次較少,屬于合理范疇。
-
12月12日為近30日最活躍的日期,原因主要為雙12活動(dòng)。
image.png
action_hour=pd.DataFrame(df['time'].value_counts()).sort_index(ascending=True)
plt.figure(figsize=(10,3),dpi=100)
plt.title('用戶活躍時(shí)段',fontsize=15)
plt.plot(action_hour.index,action_hour['time'],'-o')
plt.xticks(range(0,24,1),fontsize=10)
plt.yticks(fontsize=10)
plt.xlabel('(時(shí)間)',fontsize=13)
plt.ylabel('瀏覽等行為合計(jì)數(shù)量',fontsize=13)
一天當(dāng)中,用戶活躍時(shí)段集中在晚上18:00~22:00。

【三】制作用戶標(biāo)簽表
一、用戶活躍時(shí)間
- 1.1、用戶瀏覽活躍時(shí)間段
- 1.2、用戶購買活躍時(shí)間段
a、用戶瀏覽活躍時(shí)間段
計(jì)算加工流程:
- a、提取 behavior_type=1 的用戶瀏覽數(shù)據(jù)
- b、然后根據(jù) 用戶id+時(shí)間段 分組計(jì)數(shù),并且求出最大值
- c、獲取 用戶id+最活躍時(shí)間段,如果有多個(gè)最活躍時(shí)間段,則進(jìn)行逗號(hào)拼接
behavior_type 的內(nèi)容
- 瀏覽:behavior_type=1
- 收藏:behavior_type=2
- 加購:behavior_type=3
- 購買:behavior_type=4
#對(duì)用戶和時(shí)段分組,統(tǒng)計(jì)瀏覽次數(shù)
time_browse = df[df['behavior_type']==1].groupby(['user_id','hour']).item_id.count().reset_index()
time_browse.rename(columns={'item_id':'hour_counts'},inplace=True)
#統(tǒng)計(jì)每個(gè)用戶瀏覽次數(shù)最多的時(shí)段
time_browse_max = time_browse.groupby('user_id').hour_counts.max().reset_index()
time_browse_max.rename(columns={'hour_counts':'read_counts_max'},inplace=True)
time_browse = pd.merge(time_browse,time_browse_max,how='left',on='user_id')
#選取各用戶瀏覽次數(shù)最多的時(shí)段,如有并列最多的時(shí)段,用逗號(hào)連接
time_browse_hour = time_browse.loc[time_browse['hour_counts']==time_browse['read_counts_max'],'hour'].groupby(time_browse['user_id']).aggregate(lambda x:','.join(x)).reset_index()
count_browse_hour=time_browse_hour.groupby('hour').count()
count_browse_hour2=count_browse_hour.reset_index()
count_browse_hour2['hour']=count_browse_hour2['hour'].astype('category')
count_browse_hour2['hour'].cat.reorder_categories([ '上午', '中午', '下午','晚上', '凌晨','下午,晚上'], inplace=True)
#畫圖
hour_order=[ '上午', '中午', '下午','晚上', '凌晨','下午,晚上']
ax1=plt.figure(figsize=(10,3),dpi=100)
plt.title('各用戶瀏覽時(shí)間最長(zhǎng)的時(shí)段分布',fontsize=15)
g=sns.barplot(data=count_browse_hour2,x='hour',y='user_id',order=hour_order)
plt.xticks(fontsize=10)
plt.yticks(range(0,200,50),fontsize=10)
plt.xlabel('時(shí)段',fontsize=13)
plt.ylabel('合計(jì)數(shù)量',fontsize=13)
for x,y in enumerate(count_browse_hour2['user_id']):
g.text(x,y+5,str(y)+'人',ha='center',fontsize=10)
-
共有121人喜歡在晚上瀏覽購買商品,只有少數(shù)人喜歡在凌晨和中午瀏覽電商平臺(tái)
image.png
b、用戶購買活躍時(shí)間段
計(jì)算加工流程:
- a、提取 behavior_type=4 的用戶購買數(shù)據(jù)
- b、然后根據(jù) 用戶id+時(shí)間段 分組計(jì)數(shù),并且求出最大值
- c、獲取 用戶id+最活躍時(shí)間段,如果有多個(gè)最活躍時(shí)間段,則進(jìn)行逗號(hào)拼接
#生成邏輯與瀏覽活躍時(shí)間段相同
time_buy = df[df['behavior_type']==4].groupby(['user_id','hour']).item_id.count().reset_index()
time_buy.rename(columns={'item_id':'hour_counts'},inplace=True)
time_buy_max = time_buy.groupby('user_id').hour_counts.max().reset_index()
time_buy_max.rename(columns={'hour_counts':'buy_counts_max'},inplace=True)
time_buy = pd.merge(time_buy,time_buy_max,how='left',on='user_id')
time_buy_hour = time_buy.loc[time_buy['hour_counts']==time_buy['buy_counts_max'],'hour'].groupby(time_buy['user_id']).aggregate(lambda x:','.join(x)).reset_index()
#將用戶購買活躍時(shí)間段加入到用戶標(biāo)簽表中
labels = pd.merge(labels,time_buy_hour,how='left',on='user_id')
labels.rename(columns={'hour':'time_buy'},inplace=True)
count_time_buy=labels.groupby('time_buy').agg({'time_buy':'count'})
#畫圖
ax1=plt.figure(figsize=(10,3),dpi=100)
plt.title('各用戶主要購買時(shí)間的時(shí)段分布',fontsize=15)
g=sns.barplot(data=count_time_buy,x=count_time_buy.index,y='time_buy')
plt.xticks(fontsize=10,rotation=90)
plt.yticks(range(0,81,20),fontsize=10)
plt.xlabel('時(shí)段',fontsize=13)
plt.ylabel('合計(jì)數(shù)量',fontsize=13)
for x,y in enumerate(count_time_buy['time_buy']):
g.text(x,y+5,str(y)+'人',ha='center',fontsize=10)
-
人們喜歡在下午或者晚上購物,合計(jì)113人,占比50.82%。
image.png
二、關(guān)于類目的用戶行為
- 2.1、瀏覽最多的類目
- 2.2、收藏最多的類目
- 2.3、加購最多的類目
- 2.4、購買最多的類目
a、瀏覽最多的類目
計(jì)算加工流程:
- a、提取 behavior_type=1 的用戶購買數(shù)據(jù)
- b、然后根據(jù) 用戶id+類目 分組計(jì)數(shù),并且求出最大值
- c、獲取 用戶id+瀏覽最多的類目,如果有多個(gè)類目,則進(jìn)行逗號(hào)拼接
df_cate_most_browse = df_browse.groupby(['user_id','item_category']).item_id.count().reset_index()
df_cate_most_browse.rename(columns={'item_id':'item_category_counts'},inplace=True)
#統(tǒng)計(jì)每個(gè)用戶瀏覽次數(shù)最多的類目
df_cate_most_browse_max = df_cate_most_browse.groupby('user_id').item_category_counts.max().reset_index()
df_cate_most_browse_max.rename(columns={'item_category_counts':'item_category_counts_max'},inplace=True)
df_cate_most_browse = pd.merge(df_cate_most_browse,df_cate_most_browse_max,how='left',on='user_id')
df_cate_most_browse['item_category'] = df_cate_most_browse['item_category'].astype(str)
#選取各用戶瀏覽次數(shù)最多的類目,如有并列最多的類目,用逗號(hào)連接
df_cate_browse = df_cate_most_browse.loc[df_cate_most_browse['item_category_counts']==df_cate_most_browse['item_category_counts_max'],'item_category'].groupby(df_cate_most_browse['user_id']).aggregate(lambda x:','.join(x)).reset_index()
#將用戶瀏覽最多的類目加入到用戶標(biāo)簽表中
labels = pd.merge(labels,df_cate_browse,how='left',on='user_id')
labels.rename(columns={'item_category':'cate_most_browse'},inplace=True)
b、收藏最多的類目
- a、提取 behavior_type=2 的用戶購買數(shù)據(jù)
- b、然后根據(jù) 用戶id+類目 分組計(jì)數(shù),并且求出最大值
- c、獲取 用戶id+收藏最多的類目,如果有多個(gè)類目,則進(jìn)行逗號(hào)拼接
#生成邏輯與瀏覽最多的類目相同
df_cate_most_collect = df_collect.groupby(['user_id','item_category']).item_id.count().reset_index()
df_cate_most_collect.rename(columns={'item_id':'item_category_counts'},inplace=True)
df_cate_most_collect_max = df_cate_most_collect.groupby('user_id').item_category_counts.max().reset_index()
df_cate_most_collect_max.rename(columns={'item_category_counts':'item_category_counts_max'},inplace=True)
df_cate_most_collect = pd.merge(df_cate_most_collect,df_cate_most_collect_max,how='left',on='user_id')
df_cate_most_collect['item_category'] = df_cate_most_collect['item_category'].astype(str)
df_cate_collect = df_cate_most_collect.loc[df_cate_most_collect['item_category_counts']==df_cate_most_collect['item_category_counts_max'],'item_category'].groupby(df_cate_most_collect['user_id']).aggregate(lambda x:','.join(x)).reset_index()
labels = pd.merge(labels,df_cate_collect,how='left',on='user_id')
labels.rename(columns={'item_category':'cate_most_collect'},inplace=True)
c、加購最多的類目
- a、提取 behavior_type=3 的用戶購買數(shù)據(jù)
- b、然后根據(jù) 用戶id+類目 分組計(jì)數(shù),并且求出最大值
- c、獲取 用戶id+加購最多的類目,如果有多個(gè)類目,則進(jìn)行逗號(hào)拼接
# 生成邏輯與瀏覽最多的類目相同
df_cate_most_cart = df_cart.groupby(['user_id','item_category']).item_id.count().reset_index()
df_cate_most_cart = df_cart.groupby(['user_id','item_category']).item_id.count().reset_index()
df_cate_most_cart.rename(columns={'item_id':'item_category_counts'},inplace=True)
df_cate_most_cart_max = df_cate_most_cart.groupby('user_id').item_category_counts.max().reset_index()
df_cate_most_cart_max.rename(columns={'item_category_counts':'item_category_counts_max'},inplace=True)
df_cate_most_cart = pd.merge(df_cate_most_cart,df_cate_most_cart_max,how='left',on='user_id')
df_cate_most_cart['item_category'] = df_cate_most_cart['item_category'].astype(str)
df_cate_cart = df_cate_most_cart.loc[df_cate_most_cart['item_category_counts']==df_cate_most_cart['item_category_counts_max'],'item_category'].groupby(df_cate_most_cart['user_id']).aggregate(lambda x:','.join(x)).reset_index()
labels = pd.merge(labels,df_cate_cart,how='left',on='user_id')
labels.rename(columns={'item_category':'cate_most_cart'},inplace=True)
d、購買最多的類目
- a、提取 behavior_type=4 的用戶購買數(shù)據(jù)
- b、然后根據(jù) 用戶id+類目 分組計(jì)數(shù),并且求出最大值
- c、獲取 用戶id+購買最多的類目,如果有多個(gè)類目,則進(jìn)行逗號(hào)拼接
#生成邏輯與瀏覽最多的類目相同
df_cate_most_buy = df_buy.groupby(['user_id','item_category']).item_id.count().reset_index()
df_cate_most_buy = df_buy.groupby(['user_id','item_category']).item_id.count().reset_index()
df_cate_most_buy.rename(columns={'item_id':'item_category_counts'},inplace=True)
df_cate_most_buy_max = df_cate_most_buy.groupby('user_id').item_category_counts.max().reset_index()
df_cate_most_buy_max.rename(columns={'item_category_counts':'item_category_counts_max'},inplace=True)
df_cate_most_buy = pd.merge(df_cate_most_buy,df_cate_most_buy_max,how='left',on='user_id')
df_cate_most_buy['item_category'] = df_cate_most_buy['item_category'].astype(str)
df_cate_buy = df_cate_most_buy.loc[df_cate_most_buy['item_category_counts']==df_cate_most_buy['item_category_counts_max'],'item_category'].groupby(df_cate_most_buy['user_id']).aggregate(lambda x:','.join(x)).reset_index()
labels = pd.merge(labels,df_cate_buy,how='left',on='user_id')
labels.rename(columns={'item_category':'cate_most_buy'},inplace=True)
- 瀏覽、收藏、加購、購買最多前十種類目產(chǎn)品可視化展示
# 先獲取各個(gè)需要的數(shù)據(jù)集
df_browse = df.loc[df['behavior_type']==1,['user_id','item_id','item_category']]
df_collect = df.loc[df['behavior_type']==2,['user_id','item_id','item_category']]
df_cart = df.loc[df['behavior_type']==3,['user_id','item_id','item_category']]
df_buy = df.loc[df['behavior_type']==4,['user_id','item_id','item_category']]
def top10_purchase(df,action):
df_top10=df.groupby('item_id').count().sort_values('user_id',ascending=False)
df_top10['item_category']=round(df_top10['user_id']/df_top10['user_id'].sum()*100,3)
df_top10['item_category']=df_top10['item_category'].apply(lambda x:str(x)+'%')
df_top10=df_top10.head(10)
ax=plt.figure(figsize=(10,3),dpi=100)
plt.title('用戶'+action+'產(chǎn)品TOP10(次數(shù)/占比)',fontsize=15)
g=sns.barplot(data=df_top10,x=df_top10.index,y='user_id',order=df_top10.index)
plt.xticks(fontsize=10,rotation=45)
plt.yticks(range(0,max(df_top10['user_id'].max()//10*13+1,df_top10['user_id'].max()+2),max(df_top10['user_id'].max()//10*10//5,1)),fontsize=10)
plt.xlabel('產(chǎn)品編號(hào)',fontsize=13)
plt.ylabel(action+'次數(shù)',fontsize=13)
for x,y in enumerate(df_top10['user_id']):
g.text(x,y+y*0.05,str(y)+'次',ha='center',fontsize=10)
for x,y in enumerate(df_top10['item_category']):
g.text(x,df_top10['user_id'].min()/2,y,ha='center',fontsize=10)
top10_purchase(df_browse,'瀏覽')
top10_purchase(df_collect,'收藏')
top10_purchase(df_cart,'加購')




三、30天用戶行為
- 3.1 近30天購買次數(shù)
- 3.2 近30天加購次數(shù)
- 3.3 近30天活躍天數(shù)
3.1 近30天購買次數(shù)
- a、提取 behavior_type=4 的用戶購買數(shù)據(jù)
- b、然后根據(jù) 用戶id 分組計(jì)數(shù),得到結(jié)果
#將購買行為按用戶進(jìn)行分組,統(tǒng)計(jì)次數(shù)
df_counts_30_buy = df[df['behavior_type']==4].groupby('user_id').item_id.count().reset_index()
labels = pd.merge(labels,df_counts_30_buy,how='left',on='user_id')
labels.rename(columns={'item_id':'counts_30_buy'},inplace=True)
3.2 近30天加購次數(shù)
- a、提取 behavior_type=3 的用戶購買數(shù)據(jù)
- b、然后根據(jù) 用戶id 分組計(jì)數(shù),得到結(jié)果
#將加購行為按用戶進(jìn)行分組,統(tǒng)計(jì)次數(shù)
df_counts_30_cart = df[df['behavior_type']==3].groupby('user_id').item_id.count().reset_index()
labels = pd.merge(labels,df_counts_30_cart,how='left',on='user_id')
labels.rename(columns={'item_id':'counts_30_cart'},inplace=True)
labels=labels.iloc[:,~labels.columns.duplicated()]
3.3 近30天活躍天數(shù)
- a、提取所有用戶購買數(shù)據(jù)
- b、然后根據(jù) 用戶id 分組計(jì)數(shù),統(tǒng)計(jì)不同日期的天數(shù)
#對(duì)用戶進(jìn)行分組,統(tǒng)計(jì)活躍的天數(shù),包括瀏覽、收藏、加購、購買
counts_30_active = df.groupby('user_id')['date'].nunique()
labels = pd.merge(labels,counts_30_active,how='left',on='user_id')
labels.rename(columns={'date':'counts_30_active'},inplace=True)
四、7天用戶行為
- 4.1 近7天購買次數(shù)
- 4.2 近7天加購次數(shù)
- 4.3 近7天活躍次數(shù)
#數(shù)據(jù)集中的最后日期是12月18號(hào),統(tǒng)計(jì)11號(hào)之后的用戶行為
df_near_7 = df[df['date']>'2020-12-11']
4.1 近7天購買次數(shù)
- a、提取 behavior_type=4 的用戶購買數(shù)據(jù)
- b、然后根據(jù) 用戶id 分組計(jì)數(shù),得到結(jié)果
df_counts_7_buy = df_near_7[df_near_7['behavior_type']==4].groupby('user_id').item_id.count().reset_index()
labels = pd.merge(labels,df_counts_7_buy,how='left',on='user_id')
labels.rename(columns={'item_id':'counts_7_buy'},inplace=True)
4.2 近7天加購次數(shù)
- a、提取 behavior_type=3 的用戶加購數(shù)據(jù)
- b、然后根據(jù) 用戶id 分組計(jì)數(shù),得到結(jié)果
df_counts_7_cart = df_near_7[df_near_7['behavior_type']==3].groupby('user_id').item_id.count().reset_index()
labels = pd.merge(labels,df_counts_7_cart,how='left',on='user_id')
labels.rename(columns={'item_id':'counts_7_cart'},inplace=True)
4.3 近7天活躍天數(shù)
- a、獲取每個(gè)用戶近7天里面的日期數(shù)據(jù),不區(qū)分用戶行為有記錄就算
- b、去重統(tǒng)計(jì)有多少個(gè)日期
counts_7_active = df_near_7.groupby('user_id')['date'].nunique()
labels = pd.merge(labels,counts_7_active,how='left',on='user_id')
labels.rename(columns={'date':'counts_7_active'},inplace=True)
五、最后一次行為距今天數(shù)
- 5.1 上次瀏覽距今天數(shù)
- 5.2 上次加購距今天數(shù)
- 5.3 上次購買距今天數(shù)
5.1 上次瀏覽距今天數(shù)
- a、提取 behavior_type=1 的用戶瀏覽數(shù)據(jù),
- b、獲取里面最大的一個(gè)日期時(shí)間,然后用現(xiàn)在時(shí)間相減得到天數(shù)
- c、添加到標(biāo)簽內(nèi)容里面去
days_browse = df[df['behavior_type']==1].groupby('user_id')['date'].max().apply(lambda x:(datetime.strptime('2020-12-19','%Y-%m-%d')-datetime.strptime(x,'%Y-%m-%d')).days)
labels = pd.merge(labels,days_browse,how='left',on='user_id')
labels.rename(columns={'date':'days_browse'},inplace=True)
5.2 上次加購距今天數(shù)
- a、提取 behavior_type=3 的用戶加購數(shù)據(jù),
- b、獲取里面最大的一個(gè)日期時(shí)間,然后用現(xiàn)在時(shí)間(2020-12-19)相減得到天數(shù)
- c、添加到標(biāo)簽內(nèi)容里面去
days_cart = df[df['behavior_type']==3].groupby('user_id')['date'].max().apply(lambda x:(datetime.strptime('2020-12-19','%Y-%m-%d')-datetime.strptime(x,'%Y-%m-%d')).days)
labels = pd.merge(labels,days_cart,how='left',on='user_id')
labels.rename(columns={'date':'days_cart'},inplace=True)
5.3 上次購買距今天數(shù)
- a、提取 behavior_type=4 的用戶購買數(shù)據(jù),
- b、獲取里面最大的一個(gè)日期時(shí)間,然后用現(xiàn)在時(shí)間(2020-12-19)相減得到天數(shù)
- c、添加到標(biāo)簽內(nèi)容里面去
days_buy = df[df['behavior_type']==4].groupby('user_id')['date'].max().apply(lambda x:(datetime.strptime('2020-12-19','%Y-%m-%d')-datetime.strptime(x,'%Y-%m-%d')).days)
labels = pd.merge(labels,days_buy,how='left',on='user_id')
labels.rename(columns={'date':'days_buy'},inplace=True)
六、最近兩次購買間隔天數(shù)
- a、提取 behavior_type=4 的用戶購買數(shù)據(jù),
- b、對(duì) 用戶id+日期 進(jìn)行分組,統(tǒng)計(jì)記錄數(shù)
- c、再對(duì)上面得到的數(shù)據(jù)根據(jù) 用戶id 進(jìn)行分組,然后對(duì)日期進(jìn)行一個(gè)偏移,獲取
- d、添加到標(biāo)簽內(nèi)容里面去
df_interval_buy = df[df['behavior_type']==4].groupby(['user_id','date']).item_id.count().reset_index()
df_interval_buy['date']=df_interval_buy['date'].apply(lambda x:datetime.strptime(x,'%Y-%m-%d'))
interval_buy = df_interval_buy.groupby('user_id')['date'].apply(lambda x:x.sort_values().diff(1).dropna().head(1)).reset_index()
interval_buy['date'] = interval_buy['date'].apply(lambda x : x.days)
interval_buy.drop('level_1',axis=1,inplace=True)
interval_buy.rename(columns={'date':'interval_buy'},inplace=True)
labels = pd.merge(labels,interval_buy,how='left',on='user_id')
七、是否瀏覽未下單
- a、提取 behavior_type=1 的瀏覽數(shù)據(jù) 和 behavior_type=4 的用戶購買數(shù)據(jù),
- b、根據(jù) 用戶id+商品id+用戶行為 來進(jìn)行分組,統(tǒng)計(jì)每個(gè)用戶對(duì)每個(gè)商品的瀏覽情況和購買情況
- c、判斷每一個(gè)用戶對(duì)于每一個(gè)商品是否存在,瀏覽但是未購買的行為,如果有那新建一個(gè)字段的值記為1,沒有則為0
- d、再根據(jù) 用戶id 進(jìn)行分組,統(tǒng)計(jì)每個(gè)用戶的 瀏覽但未購買 的次數(shù),如果大于0則為 是,否則為 否
df_browse_buy = df.loc[(df['behavior_type']==1) | (df['behavior_type']==4),['user_id','item_id','behavior_type','time']]\
browse_not_buy.fillna(0,inplace=True)
browse_not_buy['browse_not_buy'] = 0
browse_not_buy.loc[(browse_not_buy['browse']>0) & (browse_not_buy['buy']==0),'browse_not_buy'] = 1
browse_not_buy = browse_not_buy.groupby('user_id')['browse_not_buy'].sum().reset_index()
labels = pd.merge(labels,browse_not_buy,how='left',on='user_id')
labels['browse_not_buy'] = labels['browse_not_buy'].apply(lambda x: '是' if x>0 else '否')
八、是否加購未下單
- a、提取 behavior_type=3 的加購數(shù)據(jù) 和 behavior_type=4 的用戶購買數(shù)據(jù),
- b、根據(jù) 用戶id+商品id+用戶行為 來進(jìn)行分組,統(tǒng)計(jì)每個(gè)用戶對(duì)每個(gè)商品的加購情況和購買情況
- c、判斷每一個(gè)用戶對(duì)于每一個(gè)商品是否存在,加購但是未購買的行為,如果有那新建一個(gè)字段的值記為1,沒有則為0
- d、再根據(jù) 用戶id 進(jìn)行分組,統(tǒng)計(jì)每個(gè)用戶的 加購但未購買 的次數(shù),如果大于0則為 是,否則為 否
df_cart_buy = df.loc[(df['behavior_type']==3) | (df['behavior_type']==4),['user_id','item_id','behavior_type','time']]
cart_not_buy = pd.pivot_table(df_cart_buy,index=['user_id','item_id'],columns=['behavior_type'],values=['time'],aggfunc=['count'])
cart_not_buy.columns = ['cart','buy']
cart_not_buy.fillna(0,inplace=True)
cart_not_buy['cart_not_buy'] = 0
cart_not_buy.loc[(cart_not_buy['cart']>0) & (cart_not_buy['buy']==0),'cart_not_buy'] = 1
cart_not_buy = cart_not_buy.groupby('user_id')['cart_not_buy'].sum().reset_index()
labels = pd.merge(labels,cart_not_buy,how='left',on='user_id')
九、用戶屬性標(biāo)簽
- 9.1 是否復(fù)購用戶
- 9.2 訪問活躍度
- 9.3 購買的品類是否單一
- 9.4 用戶價(jià)值分組
9.1 是否復(fù)購用戶
- a、提取 behavior_type=4 的用戶購買數(shù)據(jù)
- b、如果計(jì)數(shù)大于1則有復(fù)購,否則沒有復(fù)購
buy_again = df[df['behavior_type']==4].groupby('user_id')['item_id'].count().reset_index()
buy_again.rename(columns={'item_id':'buy_again'},inplace=True)
labels = pd.merge(labels,buy_again,how='left',on='user_id')
labels['buy_again'].fillna(-1,inplace=True)
#未購買的用戶標(biāo)記為‘未購買’,有購買未復(fù)購的用戶標(biāo)記為‘否’,有復(fù)購的用戶標(biāo)記為‘是’
labels['buy_again'] = labels['buy_again'].apply(lambda x: '是' if x>1 else '否' if x==1 else '未購買')
9.2 訪問活躍度
- a、獲取標(biāo)簽的統(tǒng)計(jì)值 counts_30_active 近30天活躍人數(shù)情況
- b、對(duì)活躍次數(shù)分組計(jì)數(shù),也就是得到了訪問次數(shù)和訪問人數(shù)的情況
- c、進(jìn)行繪圖得到趨勢(shì)圖
- d、如果訪問活躍度超過20,則定義為“高”,否則定義為“低”
user_active_level = labels['counts_30_active'].value_counts().sort_index(ascending=False)
plt.figure(figsize=(10,3),dpi=100)
plt.plot(user_active_level.index,user_active_level.values,'--o')
plt.title('30天內(nèi)訪問天數(shù)與訪問人數(shù)的關(guān)系',fontsize=15)
plt.xticks(range(0,32,5),fontsize=10)
plt.yticks(range(0,21,5),fontsize=10)
plt.xlabel('訪問天數(shù)',fontsize=13)
plt.ylabel('訪問人數(shù)',fontsize=13)
for x,y in enumerate(list(reversed(user_active_level.values))):
plt.text(x+1,y+1,y,ha='center',fontsize=10)

總體上看,訪問天數(shù)多的訪客比訪問天數(shù)少的訪客數(shù)量多,且以20次左右為拐點(diǎn),因此定義訪問天數(shù)小于20次的為低活躍,訪問天數(shù)大于等于20次的定義為高活躍。此定義只是從用戶的分布角度出發(fā),工作中當(dāng)從業(yè)務(wù)出發(fā)定義是否活躍。
labels['buy_active_level'] = '高'
labels.loc[labels['counts_30_buy']<=19,'buy_active_level'] = '低'
9.3 購買的品類是否單一
- a、提取 behavior_type=4 的用戶購買數(shù)據(jù)
- b、根據(jù) 用戶id 進(jìn)行分組,統(tǒng)計(jì) 類目的數(shù)量
- c、判斷計(jì)數(shù)是否大于1,大于1的
buy_single = df[df['behavior_type']==4].groupby('user_id').item_category.nunique().reset_index()
buy_single.rename(columns={'item_category':'buy_single'},inplace=True)
labels = pd.merge(labels,buy_single,how='left',on='user_id')
labels['buy_single'].fillna(-1,inplace=True)
labels['buy_single'] = labels['buy_single'].apply(lambda x: '否' if x>1 else '是' if x==1 else '未購買' )
ax1=plt.figure(figsize=(10,3),dpi=100)
plt.title('是否只購買了一次',fontsize=15)
g=sns.countplot(data=labels,x='buy_single')
plt.xticks(fontsize=13)
plt.yticks(range(0,201,20),fontsize=10)
plt.xlabel(' ')
plt.ylabel('人數(shù)',fontsize=13,rotation=90)
for x,y in enumerate([180,29,13]):
g.text(x,y+5,str(y)+'人',ha='center',fontsize=10)

9.4 用戶價(jià)值分組(RFM)
- a、獲取標(biāo)簽的統(tǒng)計(jì)值 days_buy 得到上次距今購買天數(shù)
- b、對(duì)購買天數(shù)進(jìn)行統(tǒng)計(jì)計(jì)數(shù),得到 buy_days_level
- c、繪制購買天數(shù)buy_days_level 和 購買人數(shù)的圖形走勢(shì)
- d、對(duì)購買天數(shù)進(jìn)行分類,如果大于8天則為“低”,反之為“高”
RFM:
最近一次消費(fèi) (Recency)
消費(fèi)頻率 (Frequency)
消費(fèi)金額 (Monetary)
last_buy_days = labels['days_buy'].value_counts().sort_index()
from matplotlib.font_manager import FontProperties
myfont=FontProperties(fname=r'C:\\Windows\\Fonts\\simhei.ttf',size=8)
sns.set(font=myfont.get_name())
plt.figure(figsize=(10,3),dpi=100)
plt.plot(last_buy_days.index,last_buy_days.values,'--o')
plt.title('最后一次購買距今天數(shù)與人數(shù)的關(guān)系',fontsize=15)
plt.xticks(range(0,32,5),fontsize=10)
plt.yticks(range(0,41,5),fontsize=10)
plt.xlabel('距今天數(shù)',fontsize=13)
plt.ylabel('購買人數(shù)',fontsize=13)
for x,y in enumerate(last_buy_days.values):
plt.text(x+1,y+1,y,ha='center',fontsize=10)

注:訪問異常的那天為雙12
labels['buy_days_level'] = '高'
labels.loc[labels['days_buy']>8,'buy_days_level'] = '低'
labels['rfm_value'] = labels['buy_active_level'].str.cat(labels['buy_days_level'])
def trans_value(x):
if x == '高高':
return '重要價(jià)值客戶'
elif x == '低高':
return '重要深耕客戶'
elif x == '高低':
return '重要喚回客戶'
else:
return '即將流失客戶'
labels['rfm'] = labels['rfm_value'].apply(trans_value)
labels.drop(['buy_days_level','rfm_value'],axis=1,inplace=True)
RFM=labels['rfm'].value_counts()
ax1=plt.figure(figsize=(10,3),dpi=100)
plt.title('RFM模型',fontsize=15)
g=sns.barplot(y=labels['rfm'].value_counts().index,x=labels['rfm'].value_counts().values)
plt.xticks(range(0,141,20),fontsize=10)
plt.yticks(fontsize=10)
plt.xlabel('人數(shù)',fontsize=13)
plt.ylabel('客戶RFM類型',fontsize=13,rotation=90)
for x,y in enumerate(labels['rfm'].value_counts().values):
g.text(y+5,x,str(y)+'人',ha='center',fontsize=10)

# 導(dǎo)入訂單數(shù)據(jù)
order_df = pd.read_excel("order_data.xlsx")
order_df['time']=order_df['time'].apply(lambda x:'2020'+x[4:])
# 把訂單日期轉(zhuǎn)換為時(shí)間格式
order_df["time"]=pd.to_datetime(order_df["time"])
# 提取時(shí)間點(diǎn)
order_df["time_hour"]=order_df["time"].dt.hour
# 為了能按星期統(tǒng)計(jì)情況,需要把時(shí)間轉(zhuǎn)換成星期幾,默認(rèn)周一是從0計(jì)數(shù)
order_df["time_week"]=order_df["time"].dt.dayofweek+1
#統(tǒng)計(jì)星期購物的情況
week_order_df = order_df.groupby("time_week").user_id.count().reset_index()
myfont=FontProperties(fname=r'C:\\Windows\\Fonts\\simhei.ttf',size=8)
sns.set(font=myfont.get_name())
plt.figure(figsize=(10,3),dpi=100)
plt.plot(week_order_df['time_week'],week_order_df['user_id'],'--o')
plt.title('每周購物情況',fontsize=15)
plt.xticks(range(1,8,1),fontsize=10)
plt.yticks(range(30000,42001,2000),fontsize=10)
plt.xlabel('第N周',fontsize=13)
plt.ylabel('購買次數(shù)',fontsize=13)
for x,y in enumerate(week_order_df['user_id']):
plt.text(x+1,y+500,y,ha='center',fontsize=10)

# 統(tǒng)計(jì)時(shí)間點(diǎn)購物情況
hour_order_df = order_df.groupby("time_hour").user_id.count().reset_index()
myfont=FontProperties(fname=r'C:\\Windows\\Fonts\\simhei.ttf',size=8)
sns.set(font=myfont.get_name())
plt.figure(figsize=(10,3),dpi=100)
plt.plot(hour_order_df['time_hour'],hour_order_df['user_id'],'--o')
plt.title('一天購物時(shí)間分布',fontsize=15)
plt.xticks(range(0,24,1),fontsize=10)
plt.yticks(range(0,25001,5000),fontsize=10)
plt.xlabel('24小時(shí)',fontsize=13)
plt.ylabel('購買次數(shù)',fontsize=13)
for x,y in enumerate(hour_order_df['user_id']):
plt.text(x,y+1000,y,ha='center',fontsize=10)



