• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Python消费者行为项目——精准营销

武飞扬头像
果园yyyyyyyy
帮助1

一、项目背景与目的

大数据具有信息量大、类型繁多、价值密度低、速度快、时效高的特点。随着互联网的发展,大数据在商业竞争中越来越显现出重要的作用,很多企业利用大数据进行储存、计算、分析并开展多层次的商业创新。在此背景下,消费者接触商品的方式发生了变化,购物呈现出多样化,消费理念和意识也随之发生了改变。当前在所有营销方式中,精准营销通过定量和定性相结合的方法,对目标市场的不同消费者进行细致分析,根据其消费心理和行为特征,采用现代技术、方法和指向明确的策略,实现对目标市场不同消费群体强有效性的营销沟通。基于这些优点,精准营销超越了传统的营销手段。
因此,本项目旨在通过对海量交易流水数据的深度分析与挖掘,构建全方位的客户标签体系。其次,基于客户标签体系,从基本信息、消费能力、行为习惯等多个维度对客户进行精准画像。最后,计算客户商品兴趣度排行榜,支持精准目标客户的筛选。通过此项目来进一步熟悉和掌握精准营销的方法与流程。

二、项目流程

学新通

#导入项目中所需的包
from io import StringIO
import pandas as pd
import re
import matplotlib.pyplot as plt
import matplotlib
import datetime
import seaborn as sns
import jieba
from wordcloud import WordCloud
import PIL
import numpy as np
from jieba import analyse
import copy
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
import matplotlib.dates as mdates
学新通

三、数据源

1. 数据介绍

本项目采用模拟的客户交易数据sell.sql进行分析,此数据包含40000条交易流水数据,每条交易记录包含客户id、交易金额、交易附言和交易时间四个字段,如下表所示。

字段名称 中文名称 备注
user_id 客户id 客户唯一标识
payment 交易金额 正为支出、负为收入
postscript 交易附言 为此项交易的文字描述
unix_time 交易时间 unix时间戳

2. 数据解析与读取

直接利用pandas和re对sql数据进行解析和读取,最终转换为dataframe格式的数据。
代码参考:https://www.jb51.net/article/204513.htm

# 解析sql数据,将其转换为dataframe格式
# 首先将sql文件中的数据传换成str,利用正则表达式进行解析处理,用pandas读取,得到dataframe格式的数据
def read_sql_script_by_tablename(sql_file_path, table_name, quotechar="'") -> (str, dict):
    # 参数说明
    # sql_file_path表示sql文件读取路径
    # table_name表示数据库表的名称
    # quotechar表示用单引号解析还是用双引号解析,默认为单引号解析
    insert_check = re.compile(r"insert  into  `?(\w ?)`?\(", re.I | re.A)
    with open(sql_file_path, encoding="utf-8") as f:
        sql_txt = f.read()
    end_pos = -1
    dfs = []
    while True:
        match_obj = insert_check.search(sql_txt, end_pos 1)
        if not match_obj:
            break
        start_pos = match_obj.span()[1] 1
        end_pos = sql_txt.find(";", start_pos)
        if table_name != match_obj.group(1):
            continue
        tmp = re.sub(r"\)( values |,)\(", "\n", sql_txt[start_pos:end_pos])
        tmp = re.sub(r"[`()]", "", tmp[53:])
        df = pd.read_csv(StringIO(tmp), 
                         quotechar=quotechar,
                         index_col = False,
                         header = None,
                         names = ['user_id','payment','postscript','unix_time'])
        dfs.append(df)
    return pd.concat(dfs)
学新通

学新通

四、数据预处理

1. 统计分析

(1)基本信息统计

学新通
学新通
可以看到交易附言字段中,数据由文本组成,后续需进行文本处理。交易金额字段有部分数据为NaN,后续需对其进行处理。交易时间字段的数据是unix时间戳,且数据的长度不一,unix时间戳一般情况下为10位数,后续需将其进行处理。由于该数据中无重复数据,故后续数据处理中不需要对其进行去重操作。

(2)客户信息及交易信息统计

# 计算客户个数
user_num = len(df['user_id'].unique())
print('客户总数为:',user_num)
# 计算客户交易次数
user_counts = df['user_id'].value_counts()
print('每个客户交易次数为:\n',user_counts)

学新通
可以看到在整个流水交易数据中,交易客户总数为301个,id为179的客户交易次数最多,而id为288的客户交易次数最少,此结果有助于后续的数据分析,从而实现对客户精准营销。

2. 异常值处理

unix_time字段数据长度不一,通过观察可以知道,有9位、10位和11位,需对其进行处理,我们知道unix时间戳一般为10位,故采用正则表达式来对数据进行匹配,检测位数不为10的数据对其进行处理。

# 书写正则表达式
pattern = '^[\d]{10}$'
# 筛选异常值
outlier = df[~df['unix_time'].astype(str).str.match(pattern)]
# 统计不同类型的异常值及其数量
outlier_counts = outlier['unix_time'].value_counts()
outlier_counts

学新通

可以看到有4947条数据都是异常数据,1000000000对应的北京时间为:,9999999999对应的北京时间为2286-11-21 01:46:39,为方便后续的数据分析与可视化,根据unix时间戳与北京时间的转换,设定具体的处理办法为:针对只有9位的数据在其所有数字前加1,针对11位的数据,将其最后一位删除。

for i in outlier['unix_time'].index:    # 通过索引循环异常数据
    s = str(outlier['unix_time'][i])     #将异常值赋值给s进行处理
    if len(s)==9:
        s = ''.join(['1', s])   # 处理unix时间戳为9位的异常值,在其数值第一位前加1
    else:
        s = s[:-1]    # 处理unix时间戳为11位的异常值,删除其最后一位
    df['unix_time'][i] = s      # 处理完毕后,根据索引值代替原数据,异常值处理完毕
df

学新通
查看是否处理完成
学新通
可以看到unix_time字段的数据均成为10位,异常值处理完毕。

3. 缺失值处理

统计分析部分知道,payment字段中有NaN值,仅有45条,对本项目分析影响很小,故直接删除即可,删除后数据剩39955条。
学新通
学新通

4. 数据格式转换

(1)时间格式与时区转换

注:这里的时间数据稍微有点问题,但其实不妨碍分析。
由于unix_time字段的数据是unix时间戳格式,为便于后续分析,需将其转换为标准的时间格式,即“%Y-%m-%d %H:%M:%S”,并通过 8小时进行时区转换。

# 时间格式转换
df['pay_time'] = pd.to_datetime(df['unix_time'],unit='s',errors='coerce')
# 时区转换
df['pay_time'] = df['pay_time']   pd.Timedelta(hours=8)

学新通

(2)交易金额数据格式转换

由于交易金额是以“分”为单位的,为了符合我们的习惯,将其转换为以“元”为单位。

# 交易金额数据格式转换(payment字段由以“分”为单位转换为以“元”为单位)
df['payment'] = df['payment']/100

学新通

五、客户交易行为分析

1. 时间维度分析

(1)交易次数随时间的可视化分析

# 交易次数随时间的可视化分析
fig = plt.figure(figsize=(12,6))
# 绘制折线图
df['pay_time'].dt.date.value_counts().plot()
# 设置图形标题
plt.title("不同时间的交易次数分布")
# 设置y轴标签
plt.ylabel("交易次数")
# 设置x轴标签
plt.xlabel("时间")
#设置中文显示
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['font.family']=['sans-serif']
plt.show()

学新通
由于jupyter不能将图局部放大,故使用spyder将图局部放大后,如下图,可以看到2026年9月到2029年5月期间,交易次数较频繁,故后续分析将着重针对此时间段内的数据进行分析。
注:由于数据的问题,后续所做的图只显示用spyder局部放大后的图。
学新通

(2)交易金额随时间的可视化分析

#交易金额随时间的可视化分析
fig = plt.figure(figsize=(12,6))
#绘制折线图
abs(df['payment']).groupby(df['pay_time'].dt.date).sum().plot() # 交易金额有正有负,代表资金流入流出。取绝对值代表交易金额有流动
#设置图形标题
plt.title("不同时间的交易金额分布")
#设置y轴标签
plt.ylabel("交易金额")
#设置x轴标签
plt.xlabel("时间")
#设置中文显示
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['font.family']=['sans-serif']
plt.show()

学新通
可以看到交易金额也集中在2026年9月到2029年5月这段时间,故后续分析将着重针对此时间段内的数据进行分析。

(3)交易有效时段设置

将时间限定再2026年9月1日到2029年5月31日之间,可以看到在这期间交易的数据由30576条。

# 时间限定
df = df[(df['pay_time']<=pd.Timestamp(2029,5,31)) & (df['pay_time']>=pd.Timestamp(2026,9,1))]
df.shape

学新通

(4)每天24小时交易次数的分布

# 每天24小时交易次数的分布
fig = plt.figure(figsize=(8,6))
# 绘制条形图
df['pay_time'].dt.hour.value_counts().sort_index().plot.bar(color='orange',rot=360)
# 设置图形标题
plt.title("每天24小时交易次数的分布")
# 设置x轴标签
plt.xlabel("小时")
# 设置y轴标签
plt.ylabel("交易次数")
# 设置中文显示
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['font.family']=['sans-serif']
plt.show()

学新通
可以看到一天24小时中,5点的时候交易次数最多,其他时段交易次数分布较为均衡。

2. 交易属性的分析

(1)客户交易次数的可视化分析

# 客户交易次数的可视化分析
fig = plt.figure(figsize=(16,5))
# 绘制核密度图
sns.kdeplot(df.user_id.value_counts(),shade=True,legend=False)
# 设置x、y轴标签
plt.xlabel('交易次数')
plt.ylabel('频率')
# 设置图的标题
plt.title('客户交易次数分布')
# 设置中文显示
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['font.family']=['sans-serif']
plt.show()

学新通可以看到,客户的交易次数从60-140不等,主要分布在80-120。在此后的指标构建中,要根据客户的交易记录构建指标,需用在此交易次数的数据来判断用户是否为休眠客户、活跃用户等。

(2)客户平均交易金额的可视化分析

# 客户平均交易金额可视化分析
fig = plt.figure(figsize=(16,5))
# 绘制核密度图
sns.kdeplot(abs(df.payment).groupby(df.user_id).mean(),shade=True,legend=False)
# 设置x、y轴标签
plt.xlabel('平均交易金额')
plt.ylabel('频率')
# 设置图的标题
plt.title('客户平均交易金额的分布')
# 设置中文显示
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['font.family']=['sans-serif']
plt.show()

学新通
可以看到,客户平均交易金额主要在6-16之间,频率最大的再9元左右。

(3)客户交易流入流出的可视化分析

1)客户交易流入流出次数的可视化分析
# 客户交易流入流出次数的可视化分析
fig,[ax1,ax2] = plt.subplots(1,2,figsize=(16,5))
# 定义和选取交易次数流入流出的记录
input_payment = df[df['payment']<0]
output_payment = df[df['payment']>0]
# 计算每个客户的流入流出次数
input_payment_count = input_payment['user_id'].value_counts()
output_payment_count = output_payment['user_id'].value_counts()
# 绘制直方图
sns.distplot(input_payment_count,ax = ax1)
sns.distplot(output_payment_count,ax = ax2)
# 设置标题
ax1.set_title('客户交易的流入次数分布')
ax2.set_title('客户交易的流出次数分布')
plt.show()

学新通
可以看到,客户交易的流入主要集中在id为45-90的客户之间,流出主要在id为20-60之间。

2)客户交易流入流出金额的可视化分析
# 客户交易流入流出金额的可视化分析
# 定义和选取金额流入流出的交易记录
input_payment = df[df['payment']<0]
output_payment = df[df['payment']>0]
# 计算每个客户的流入流出金额
input_payment_amount = input_payment.groupby('user_id')['payment'].mean()
output_payment_amount = output_payment.groupby('user_id')['payment'].mean()
# 设置图的大小
fig,[ax1,ax2] = plt.subplots(1,2,figsize=(16,5))
# 绘制直方图
sns.distplot(input_payment_amount,ax = ax1)
sns.distplot(output_payment_amount,ax = ax2)
# 设置标题
ax1.set_title('客户交易的平均流入金额分布')
ax2.set_title('客户交易的平均流出金额分布')
# 显示负号
matplotlib.rcParams['axes.unicode_minus']=False
plt.show()
学新通

学新通

3. 交易附言的分析

(1)文本数据预处理

交易附言为文本类型,需要对其进行文本预处理,从而挖掘交易附言文本中的信息,探索文本内容的主题,以此寻找客户标签构建的方向。

# 交易附言本文预处理
# 数据采样
df = df.sample(20000,random_state = 22)
# 文本分词
df['postscript_cutted'] = df['postscript'].apply(lambda x:' '.join(jieba.cut(x)))
# 过滤停用词
stopwords = ['n']
def del_stopwords(words): 
    output = ''
    for word in words:  
        if word not in stopwords:
            output  = word
    return output

df['postscript_cutted'] = df['postscript'].apply(del_stopwords)

学新通

(2)交易附言的词云图绘制

# 交易附言词云图绘制
# 数据采样
df = df.sample(20000,random_state = 22)
# 文本拼接
postscript_document = " ".join(df['postscript_cutted'])
# 设置图的大小
fig = plt.figure(figsize=(20,10))
# 创建词云对象(参数中mask设置词云背景图片)
image1 = PIL.Image.open('E:/大三/消费者行为分析/椭圆.png')
MASK = np.array(image1)
wordcloud = WordCloud(background_color='white',font_path = 'simfang.ttf',mask=MASK,scale=2,collocations=False,random_state=30)
# 生成词云
wordcloud.generate(postscript_document)
plt.imshow(wordcloud)
plt.axis("off")
plt.show()
学新通

学新通
从词云图中可以看出,交易附言中出现较多的词为支付宝、网银、信用卡、分期付款,微信、转账、现金、交易次之,从中可以分析客户的交易行为和习惯。

(3)文本数据关键词提取

可以看到排名前50的关键词主要集中在网银、支付宝、分期付款、信用卡、微信、转账、劳务、现金等,和词云图显示的结果基本一致。

# 文本数据关键词提取
# 提取关键词
tags = jieba.analyse.extract_tags(postscript_document,topK=50,withWeight=True)
# 输出关键词
for tag in tags:
    print(tag)

学新通

六、客户标签体系构建

1. 客户标签体系构建流程

学新通
**事实类标签:**可以直接从客户交易记录中进行统计和计算的标签例如网购消费、餐饮消费、商旅消费等。
**规则类标签:**规则类标签是在事实类标签的基础上,结合人工经验,对客户的某项指标进行的计算或归类例如RFM标签、是否休眠客户、是否有高端消费等。
**预测类标签:**原始数据中不能直接提取,需要借助模型进行预测的标签,例如客户价值等级。
**文本类标签:**从客户交易记录的文本中提取的关键词也可用于描述客户偏好,将此部分关键词作为文本类标签例如彩票、儿童、孕妇、基金等。

2. 事实类标签构建

(1)交易次数和交易总额

# 事实类标签的计算
# 交易次数和交易总额
user_features = pd.DataFrame(index = df['user_id'].unique())
# 计算客户交易次数
user_features['total_transactions_cnt'] = df.groupby('user_id').size()
# 计算客户的交易总金额
user_features['total_transactions_amt'] = abs(df.payment).groupby(df['user_id']).sum()

学新通

(2)转账次数和转账总额

# 转账次数和转账总额
# 提取包含转账行为的记录
tranfer = df[df['postscript'].str.contains('转账')]
# 计算客户的转账次数
user_features['tranfer_cnt'] = tranfer.groupby('user_id').size()
# 计算客户的转账总金额
user_features['tranfer_amt'] = abs(tranfer.payment).groupby(tranfer['user_id']).sum()
# 计算客户的转账平均金额
user_features['tranfer_mean'] = abs(tranfer.payment).groupby(tranfer['user_id']).mean()

学新通

(3)单次最大消费金额

# 选取交易金额大于0的交易记录
consume_info = df[df.payment>0]
# 选取包含消费行为的记录
consume = consume_info[~consume_info['postscript'].str.contains('转账|提现|转入|还款')]
# 单次最大消费金额
user_features['max_consume_amt'] = consume.groupby('user_id')['payment'].max()

学新通

(4)其他事实类标签

# 其他事实类标签的计算
# 消费订单比例
user_features["consume_order_ratio"] = consume['payment'].groupby(consume['user_id']).size()/user_features['total_transactions_cnt']
# 提取商旅消费的记录
train_bus = consume[consume["postscript"].str.contains("车票|火车票|机票")]
travel_hotel = consume[consume['postscript'].str.contains("住宿|宾馆|酒店|携程|去哪")]
business_travel = pd.concat([train_bus,travel_hotel])
# 商旅消费次数
user_features['business_travel_cnt'] = business_travel.groupby('user_id').size()
# 商旅消费总金额
user_features['business_travel_amt'] = business_travel.payment.groupby(business_travel['user_id']).sum()
# 商旅消费平均金额
user_features['business_travel_avg_amt'] = business_travel.payment.groupby(business_travel['user_id']).mean()
# 提取公共事业缴费记录
public = consume_info[consume_info['postscript'].str.contains('水费|电费|燃气费')]

学新通

3. 规则类标签构建

(1)有无高端消费

1表示是高端消费,0表示非高端消费。

# 计算阈值
threshold = user_features['max_consume_amt'].quantile(0.75)
# 判断有无高端消费
user_features['high_consumption'] = user_features['max_consume_amt'].apply(lambda x:1 if x>threshold else 0)

学新通

(2)是否休眠客户

1表示是休眠客户,0表示非休眠客户。

# 计算阈值
threshold = user_features['total_transactions_cnt'].quantile(0.25)
# 判断是否休眠
user_features['sleep_customers'] = user_features['total_transactions_cnt'].apply(lambda x:1 if x>threshold else 0)

学新通

(3)RFM模型

学新通
学新通

1)计算R/F/M的值

由于R值是距离观察点的时间差,预处理的过程中,将数据集的时间限定在2026.9.1-2029.5.31。故在RFM模型中,将观察点的时间设为2029.6.1。那由此可以根据每笔交易时间计算最近天数。另外,RFM模型的前提是提取只属于消费类的数据。在前边6.2.3部分我们已经选取了只含消费类交易的数据,存入了comsume中,故在计算R/F/M值时,直接用其进行计算即可。

# 选取观察点
standard_day = pd.Timestamp(2029,6,1)
# 计算交易时间距离2029.6.1的天数
consume['distance'] = standard_day - consume['pay_time']
consume['distance'] = consume['distance']/pd.Timedelta(days=1)

学新通

# 计算R/F/M值
user_features[['recency','frequency','monetary']] = consume.groupby('user_id').agg({'distance':'min','user_id':'size','payment':'sum'})

学新通

2)计算RFM总得分

R分值越低越好,F,M分值越高越好。

# 计算RFM总得分
# 等级离散化
user_features['R_score'] = pd.qcut(user_features['recency'],4,labels=[4,3,2,1])
user_features['F_score'] = pd.qcut(user_features['frequency'],4,labels=[1,2,3,4])
user_features['M_score'] = pd.qcut(user_features['monetary'],4,labels=[1,2,3,4])
# 填充缺失值
user_features[['R_score','F_score','M_score']] = user_features[['R_score','F_score','M_score']].fillna(1)
# 计算总得分
user_features['Total_Score'] = user_features.R_score.astype('int')   user_features.F_score.astype('int')   user_features.M_score.astype('int')

学新通

3)RFM可视化
# RFM可视化分析
# 设置图像大小,将三张图放在一张画布上
fig,[ax1,ax2,ax3] = plt.subplots(1,3,figsize=(16,4))
# 绘制条形图
user_features.groupby('Total_Score')['recency'].mean().plot(kind='bar',colormap='Blues_r',ax=ax1,rot=360)
user_features.groupby('Total_Score')['frequency'].mean().plot(kind='bar',colormap='Blues_r',ax=ax2,rot=360)
user_features.groupby('Total_Score')['monetary'].mean().plot(kind='bar',colormap='Blues_r',ax=ax3,rot=360)
# 设置y轴标签
ax1.set_ylabel('recency')
ax1.set_ylabel('frequency')
ax1.set_ylabel('monetary')
# 自动调整子图间距
plt.tight_layout()
plt.show()

学新通
随着Total_Score的增大,recency的平均值逐渐减少,这也印证了较优质的客户群体,最近一次消费者普遍较近。
随着Total_Score的增大,frequency、monetary的平均值逐渐增大,这也印证了越优质的客户群体,消费频率和消费金额普遍较高。

4. 预测类标签构建

根据提取出的事实类标签和规则类标签,对客户价值等级进行预测。

(1)划分客户价值等级

由于原数据中无客户价值等级的数据,故采用已经得到的RFM的总得分,也就是Total_Score字段对客户价值等级进行划分,设定从中位数分开,将得分高的划分为高价值客户,得分低的划分为低价值用户,分别表示为1和0,添加到新字段user_potential中。

# 预测类标签构建
# 划分客户价值等级
# 根据已得到的RFM总得分进行划分,得分高的划分为高价值客户,得分低的划分为低价值用户,分别表示为1和0,添加到新字段user_potentail中。
labels = ['0','1']
user_features['user_potential'] = pd.qcut(user_features.Total_Score, q=[0,0.5,1], labels=labels)

学新通

(2)数据处理

1)查看空值
学新通
发现数据中有空值,为了后续模型数据的传入,在此需要去除空值,将空值用0替换,代表客户不具有这部分的交易行为。
2)替换空值

# 清除数据中的NAN值,用0替换
user_features['tranfer_cnt'] = user_features['tranfer_cnt'].fillna(0).astype(int)
user_features['tranfer_amt'] = user_features['tranfer_amt'].fillna(0).astype(int)
user_features['tranfer_mean'] = user_features['tranfer_mean'].fillna(0).astype(int)
user_features['business_travel_cnt'] = user_features['business_travel_cnt'].fillna(0).astype(int)
user_features['business_travel_amt'] = user_features['business_travel_amt'].fillna(0).astype(int)
user_features['business_travel_avg_amt'] = user_features['business_travel_avg_amt'].fillna(0).astype(int)

学新通

(3)训练集、测试集的划分

训练集与测试集按4:1的比例划分。

# 训练集、测试集的划分
X = user_features.iloc[:,:-1]
y = user_features.iloc[:,-1]
x_train,x_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=33)
print(x_train.shape,x_test.shape,y_train.shape,y_test.shape)

学新通

(4)构建客户价值等级预测模型

采用简单的逻辑斯蒂二分类模型来进行预测。

# 构建客户价值等级预测模型
clf = LogisticRegression()
# 训练模型
clf.fit(x_train,y_train)
# 预测
y_predict = clf.predict(x_test)
# 计算准确率
score = clf.score(x_test,y_test)
# 以百分数形式输出并保留两位小数
print('%.2f%%'%(score*100))
# 输出分类报告
report = classification_report(y_test,y_predict)
print(report)

学新通
准确率为78.69%。

(5)客户价值等级分布

# 客户价值等级分布
# 计算不同客户价值等级的客户数量
lmt_num = user_features['user_potential'].value_counts()
# 设置图的大小
fig = plt.figure(figsize=(8,6))
# 绘制柱状图,查看客户价值等级取值分布情况
lmt_num.plot(kind = "bar",rot=360,width = 0.15)
# 设置柱形名称
plt.xticks([0,1],['低价值','高价值'])
# 设置x、y轴标签
plt.ylabel("客户数量")
plt.xlabel("客户价值等级")
# 设置标题
plt.title("客户价值等级分布图")

学新通

(6)客户标签间的相关性

# 客户标签间的相关性
# 计算各标签间的皮尔逊相关系数
corr = user_features.corr().abs()
# 设置画布的大小
fig = plt.figure(figsize=(10,10))
# 设置颜色风格
cmap = sns.cubehelix_palette(8,start = 2,rot = 0,dark = 0,light = 0.95)
# 绘制热力图
sns.heatmap(data=corr,annot=True,linewidths=0.05,cmap=cmap)
plt.show()

学新通
可以看到,tranfer_cnt和tranfer_amt、max_consume_amt和high_consumption、business_travel_cnt和business_travel_amt、max_consume_amt和monetary的相关性均较强,相关系数均达到0.8以上,从这些标签代表的含义来看,均属于同属性或者同类别的标签。

(7)客户价值等级与是否拥有高端消费的可视化(交叉表)

# 客户价值等级与是否拥有高端消费的可视化(交叉表)
# 计算交叉表
counts = pd.crosstab(index=user_features['high_consumption'],columns=user_features['user_potential'])
# 重命名索引和列名
counts.index = ['无高端消费','有高端消费']
counts.columns = ['低价值客户','高价值客户']
# 设置画布大小
fig = plt.figure(figsize=(8,6))
# 绘制柱状图
counts.plot(kind = "bar",rot = 360,width = .3)
# 设置x、y轴标签
plt.xlabel('是否拥有高端消费')
plt.ylabel('人数')
# 设置标题
plt.title('客户价值等级与是否拥有高端消费之间的关系')
plt.show()
学新通

学新通
由图可知,在无高端消费的人群中,高价值等级客户的占比相较于低价值等级客户较小,在有高端消费的人群中,高价值等级客户的占比相较于低价值等级客户略大,这说明客户价值等级高的群体更倾向于买贵的物品。

5. 文本类标签构建

(1)文本标签提取方法

本项目用到了两种文本标签提取方法:CountVectorizer()和TfidfVectorizer()。

(2)交易附言合并

# 文本类标签的构建
# 合并交易附言
# 由于直接合并会出现“冰箱支付宝”“火车票支付宝”类似的文本,
# 这是由于在拼接交易附言的时候第一条的最后一个和第二条的第一个拼接在了一起,
# 而我们需要的是他们分别为一个文本标签,故通过cat(sep=' '),将其用空格拼接起来
describe_sum = df.groupby('user_id')['postscript_cutted'].apply(lambda x:x.str.cat(sep=' '))

学新通

(3)CountVectorizer词频矩阵计算

#生成停用词表
stop_words_list = [k.strip() for k in open(r'E:\大三\消费者行为分析\stop_words.txt', encoding='utf-8') if k.strip() != '']

# 建立CountVectorizer模型
count_vec = CountVectorizer(stop_words=stop_words_list,min_df=5,max_df=5000,max_features=100)
# 计算词频矩阵
spares_result_count = count_vec.fit_transform(describe_sum)
#输出稀疏矩阵
print(spares_result_count)
#输出关键词
print('\nvocabulary list:\n\n',count_vec.get_feature_names())
#输出关键词编号
print('\nvocabulary dic:\n\n',count_vec.vocabulary_)

学新通
学新通

(4)TfidfVectorizer词频矩阵计算

#建立TfidfVectorizer模型
tfidf_vec = TfidfVectorizer(stop_words=stop_words_list,min_df=5,max_df=5000,max_features=100)
#计算tfidf矩阵
sparse_result_tfidf = tfidf_vec.fit_transform(describe_sum)
#输出稀疏矩阵
print(sparse_result_tfidf)
#输出关键词
print('\nvocabulary list:\n\n',tfidf_vec.get_feature_names())
#输出关键词编号
print('\nvocabulary dic:\n\n',tfidf_vec.vocabulary_)
#与user_features表进行合并
user_features = pd.concat([user_features,pd.DataFrame(sparse_result_tfidf.toarray(),index=user_features.index)],axis=1)
#输出合并后user_features表的行列数
print('\n 合并后客户标签表的行列数为:\n\n',user_features.shape)
#重命名列名
columns_mapping = {value:key for key,value in tfidf_vec.vocabulary_.items()}
user_features.rename(columns=columns_mapping,inplace=True)
#输出重命名后user_features表的列名
print('\n 合并后客户标签表的列名为:\n\n',user_features.columns.values)
学新通

学新通
学新通
学新通
可以看到我们使用两种模型提取出的文本标签是一样的,从模型中提取出的100个文本标签中,我们可以大致描绘出如下几类人群:

文本标签 对应人群
微波炉、洗衣机、电灶、电烤箱、电热毯、电热水器、电脑、电视机、电风扇、电饭煲、电饼铛、空调 爱好购买电器的人群
专用印章、会议记录本、办公本薄、工作服、打印机、扫描仪、文件套、文件柜、档案袋、考勤机 上班人群
内存条、插线板、电脑、网线、网线转换接头、键盘、鼠标垫 经常接触电脑的人群
化妆用品、手套、手帕、糕点、糖果、羽绒服、裙子 女士人群
切纸刀、卡通杯、口罩、圆规、方便食品、无线装订本、计算器、证书系列、资料册 学生人群
火车票、高铁票 经常出差的人群
(5)描绘用户画像  
1)交易次数最多的客户的画像  
# 描绘用户画像
# 交易次数最多的客户的画像
# 查看交易次数最多的客户id
print(user_features.sort_values('total_transactions_cnt',ascending=False).index[0])
#选取文本
describe_selected = describe_sum[user_features['total_transactions_cnt'].idxmax()]
fig = plt.figure(figsize=(10,10))
#创建词云对象
image1 = PIL.Image.open('E:/大三/消费者行为分析/椭圆.png')
MASK = np.array(image1)
wordcloud = WordCloud(stopwords=stop_words_list,background_color='white',font_path = 'simfang.ttf',mask=MASK,scale=2,collocations=False,random_state=30)
#生成词云
wordcloud.generate(describe_selected)
plt.imshow(wordcloud)
plt.axis("off")
plt.show()
学新通

学新通

学新通
可以看到交易次数最多的客户id为179,他最喜欢买五金工具、筷子、勺子、火车票。

2)id为188的客户画像

# user_id为188的客户画像

# 客户文本标签的分析
# 选取存放文本标签词频的行和列
tfidf_features = user_features.loc[188][-100:]

# 客户数值标签的分析
# 查看该客户的数值标签
number_feature = user_features.loc[188][:50]

# 描绘用户画像
fig = plt.figure(figsize=(20,10))
image1 = PIL.Image.open('E:/大三/消费者行为分析/椭圆.png')
MASK = np.array(image1)
wordcloud = WordCloud(background_color='white',font_path = 'simfang.ttf',mask=MASK,scale=2,collocations=False,random_state=30)
# 生成词云
wordcloud.generate_from_frequencies(tfidf_features)
plt.imshow(wordcloud)
plt.axis("off")
plt.show()
学新通

学新通
图中可知,id为188的客户最常卖的东西为台历架、吸尘器、铜版纸、票夹。

七、精准营销应用

1. 商品兴趣度排行榜的计算

本项目选取学生的人群,对其进行商品兴趣度排行榜的计算,具体步骤为:首先从交易数据中筛选出消费类的数据,再分别从时间、消费金额、tf-idf三个指标对学生人群的商品兴趣度进行计算,然后经过数据归一化后,计算商品兴趣度的总得分,进而得到商品兴趣度的排行榜,得到排行榜后进行top3用户的可视化分析,以此实现对客户的精准营销。

(1)筛选消费类数据

# 精准营销的应用
# 选用学生人群,构建客户基于时间的商品兴趣排行榜
# 筛选出消费类的交易数据
consume = df[(df['payment']>0) & (~df['postscript'].str.contains('转账|提现|转入|还款'))]

学新通

(2)基于时间的商品兴趣度计算

在计算时间衰减兴趣度时,参考艾宾浩斯遗忘曲线,客户消费时间越近则兴趣度越高。利用如下公式计算客户对某商品的兴趣总和,设定衰减因子η为0.5,计算出每个时刻的兴趣度。
学新通
1)计算时间差

# 时间差计算
# 选取观察点
standard_day = pd.Timestamp(2029,6,1)
# 计算月数
consume['distance'] = (standard_day - consume['pay_time'])/pd.Timedelta(days=30)

学新通
2)基于时间的商品兴趣度计算

#基于时间的商品兴趣度计算
eta=0.5
text_list = '切纸刀|卡通杯|口罩|圆规|方便食品|无线装订本|计算器|证书系列|资料册'
# 筛选学生用品的消费记录
student_goods = consume[consume['postscript'].str.contains(text_list)]
#基于时间的商品兴趣度
user_features['time_penalty'] = student_goods.groupby('user_id')['distance'].agg(lambda x:sum(np.exp(-eta*x)))
user_features['time_penalty']

(3)基于消费金额的商品兴趣度计算

在计算消费金额兴趣度时,参考客户的消费金额指标,消费数量越大兴趣度越高。

#基于消费金额的商品兴趣计算
#计算消费金额
user_features['payment_sum'] = student_goods.groupby('user_id')['payment'].sum()

(4)基于tf-idf的商品兴趣度计算

在计算tf-idf兴趣度时,参考客户文本标签的tf-idf值,权重越大兴趣度越高。

# 基于TF-IDF的商品兴趣度计算
#选取字段
student_goods_tfidf = user_features[['切纸刀','卡通杯','口罩','圆规','方便食品','无线装订本','计算器','证书系列','资料册']]
#tfidf求和
user_features['tfidf_sum'] = student_goods_tfidf.sum(axis=1)

(5)数据归一化

  • 对于时间衰减兴趣度采用sigmoid归一化
  • 对消费金额兴趣度和tf-idf兴趣度采用min-max归一化
#数据归一化
#sigmoid归一化
user_features['time_penalty'] = user_features[['time_penalty']].apply(lambda x:1/(1 np.exp(-x)))
#min-max归一化
user_features['payment_sum'] = user_features[['payment_sum']].apply(lambda x:(x-x.min())/(x.max()-x.min()))
user_features['tfidf_sum'] = user_features[['tfidf_sum']].apply(lambda x:(x-x.min())/(x.max()-x.min()))
print(user_features[['time_penalty','payment_sum','tfidf_sum']].head(10))

(6)商品兴趣度排行榜的综合计算

# 商品兴趣度排行榜综合计算
#计算final_score
user_features['final_score'] = user_features['tfidf_sum']   user_features['payment_sum']   user_features['tfidf_sum']
# 输出商品兴趣度排行榜的top10,ascending=False为降序
top10 = user_features.sort_values('final_score',ascending=False).head(10)
print(top10[['time_penalty','payment_sum','tfidf_sum','final_score']])

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhggakea
系列文章
更多 icon
同类精品
更多 icon
继续加载