系列文章目录
- RFM会员价值度模型分析
- 用户行为分析
文章目录
前言
本文通过RFM会员价值度模型分析案例,用户行为分析案例,详解了工作中数据分析流程。
1 RFM会员价值度模型分析案例
1.1 RFM会员价值度模型概念
- 根据会员的价值度对会员分群的模型
- 会员有了不同群体之后可以实现对不同群体的用户使用不同的营销策略
- 三个维度指标
- R -> recency 最近一次消费时间距当前的天数差值, R值越小, 价值度越高
- F -> frequency 一段时间内消费次数, F值越大, 价值度越高
- M -> monetary 一段时间内消费总金额, M值越大, 价值度越高
- 使用场景
- 交易行为的业务 -> 一般就是发生买卖
- 电商
- 旅游 -> 最近一次旅游时间, 一段时间内旅游次数, 消费金额
- 抖音/快手/斗鱼/… -> 最近一次登录时间, 一段时间内登录次数, 分享/点赞/评论
1.2 RFM会员价值度模型实现流程
- 获取一段时间内的数据集, 会员id, 订单时间, 订单金额; 一个会员可能对应多笔订单, 结果是以会员id为维度进行分组计算
- 计算R/F/M的原始值
- R -> 当前日期时间 - 用户最大订单时间, R越小越好
- F -> 一段时间内, 订单次数, 根据会员id分组, 统计次数 F越大越好
- M ->一段时间内, 订单总金额, 根据会员id分组, 统计订单总金额 M越大越好
- 分别对R/F/M三个维度划分区间 -> 打上价值分 1~5分
- 业务情况 -> 专家模型(专家根据自己的主观意愿进行分析)
- 中位数/均值
- 二八原则 -> 20%的人掌握了80%的财富, 考虑quantile
- 对R/F/M三个维度的价值分进行进一步的划分, 减少分类数
- 均值/中位值
- 对用户进行分群
- 三个维度值进行字符串拼接 111, 112, 113, …
- 三个维度值求和, 会员总价值分
1.3 RFM案例代码实现
-
加载数据集
import time # 时间库 import numpy as np # numpy库 import pandas as pd # pandas库 from pyecharts.charts import Bar3D # 3D柱形图 # 加载5个sheet页中的df数据, 保存到列表中 sheet_names = ['2015','2016','2017','2018','会员等级'] sheet_datas = [pd.read_excel('./data/sales.xlsx', sheet_name=i) for i in sheet_names] for i in sheet_names: print(i) df1 = pd.read_excel('data/sales.xlsx', sheet_name='2015') df1.head() # [df1, df2, df3, df4, df5] sheet_datas
-
查看数据集基本情况
# 查看数据基本情况 # 查看描述统计指标 df1.describe() # 统计包含缺失值的行数 # any():判断每列中是否包含True值 -> 缺失值 axis=1:按行 df1.isnull().any(axis=1).sum() # 查看每列的数据类型 df1.dtypes list(zip(['a','b', 'c'], [1, 2, 3])) for i in zip(['a','b', 'c'], [1, 2, 3]): print(i) # 元组拆包后进行循环遍历 for a, b in zip(['a','b', 'c'], [1, 2, 3]): print(a) print(b) # 对5个df的列表和表名列表循环遍历 for each_name, each_data in zip(sheet_names, sheet_datas): print('[data summary for ============={}===============]'.format(each_name)) print('Overview:','\n',each_data.head(4))# 展示数据前4条 print('DESC:','\n',each_data.describe())# 数据描述性信息 # any(axis=1):每行是否有缺失值, 返回True或False print('NA records',each_data.isnull().any(axis=1).sum()) # 包含缺失值条目数 print('Dtypes',each_data.dtypes) # 数据类型
-
数据处理
# 合并保存df列表中的前4个df -> 每年订单数据子集, 合并成一个df # 删除包含缺失值的行数据 2行数据 # 过滤掉订单金额小于等于1的行数据 # 新增一列每年最大提交日期列作为当前时间 # 新增一列 每笔订单的提交日期和最大提交日期的 天数差值 ->计算R值 # 合并保存df列表中的前4个df -> 每年订单数据子集, 合并成一个df # sheet_datas[:-1] -> 列表切片操作, 获取前4个元素 # concat([df1, df2, ...]) data_merge = pd.concat(sheet_datas[:-1]) data_merge.info() # 删除包含缺失值的行数据 2行数据 data_merge.dropna(inplace=True) data_merge.info() # 过滤掉订单金额小于等于1的行数据 data_merge.query('订单金额 > 1', inplace=True) data_merge.info() # 新增一列 年份 列, 根据提交日期列获取年份 data_merge['year'] = data_merge['提交日期'].dt.year data_merge.head() # 新增一列每年最大提交日期列作为当前时间 # 根据年份列分组, 通过transform方法获取每组中的最大提交日期 data_merge['max_year_date'] = data_merge.groupby(by='year')['提交日期'].transform(max) data_merge.head() # 新增一列 每笔订单的提交日期和最大提交日期 的天数差值 ->计算R值 # .dt.days 获取天数差值列中的整数值 data_merge['date_interval'] = (data_merge['max_year_date'] - data_merge['提交日期']).dt.days data_merge.head()
-
计算rfm原始值
# r -> 当前时间和最近提交日期的差值, 最近一次消费时间 # f -> 每年消费订单数量 # m -> 每年消费总金额 # 是以年份和会员id维度进行分组 -> 需要获取不同年份不同会员的分群结果 # 对不同列进行不同聚合操作 agg({列名1:聚合函数1, 列名2:聚合函数2, ...}) # as_index=False:不保留分组列作为索引, 重置索引操作 -> reset_index() rfm_gb = data_merge.groupby(by=['year', '会员ID'],as_index=False).agg({'date_interval':min, '订单号': 'count', '订单金额': sum}) rfm_gb.head() # 修改rfm_gb的列名,修改为r,f,m rfm_gb.rename(columns={'date_interval':'r', '订单号': 'f', '订单金额':'m'}, inplace=True) rfm_gb.head()
-
划分rfm原始值区间
# 分析rfm三列的描述统计指标 rfm_gb[['r', 'f', 'm']].describe().T # 定义rfm划分区间 # r和m -> (最小值-1, 1/4分位值] (1/4分位值, 3/4分位值] (3/4分位值, 最大值] # f -> (0, 2] (2,5] (5, 130] # 要包含划分区间的最小值, cut方法默认是左开右闭, 第一个值=min值-1 r_bins = [-1, 79, 255, 365] f_bins = [0, 2, 5, 130] m_bins = [0, 69, 1199, 206252] # r的labels列表, -1:倒序 [i for i in range(len(r_bins)-1, 0, -1)] [i for i in range(1, len(f_bins))] list1 =[] for i in range(1,10): list1.append(i) list1 # 通过cut方法实现划分 打上1,2,3价值分 # r ->(-1,79]为3分 (79, 255]为2分 (255, 365]为1分 相反对应 # f/m 划分区间和分值对应 # labels就是1,2,3分的分值 # pd.cut(rfm_gb['r'], bins=r_bins, labels=[3, 2, 1]) # pd.cut(rfm_gb['r'], bins=r_bins, labels=[1, 2, 3]) rfm_gb['r_score'] = pd.cut(rfm_gb['r'], bins=r_bins, labels=[i for i in range(len(r_bins)-1, 0, -1)]) rfm_gb['f_score'] = pd.cut(rfm_gb['f'], bins=f_bins, labels=[i for i in range(1, len(f_bins))]) rfm_gb['m_score'] = pd.cut(rfm_gb['m'], bins=m_bins, labels=[i for i in range(1, len(m_bins))]) rfm_gb
-
根据rfm分值进行用户分群
# r_score,f_score和m_score为类别类型列, 不能直接进行拼接操作 rfm_gb['r_score'].astype('str') + rfm_gb['f_score'].astype('str') + rfm_gb['m_score'].astype('str') # 将类别类型列转换成字符串列 rfm_gb['r_score'] = rfm_gb['r_score'].astype(np.str) rfm_gb['f_score'] = rfm_gb['f_score'].astype(np.str) rfm_gb['m_score'] = rfm_gb['m_score'].astype(np.str) # 字符串的拼接操作 rfm_gb['rfm_group'] = rfm_gb['r_score'] + rfm_gb['f_score'] + rfm_gb['m_score'] rfm_gb.head()
1.4 数据可视化
# 获取年份, 用户类别, 用户数量 三列
display_data = rfm_gb.groupby(by=['rfm_group', 'year'], as_index=False)['会员ID'].count()
display_data.head()
# 修改列名 会员ID改为number
display_data.rename(columns={'会员ID':'number'}, inplace=True)
display_data.head()
# 绘制3d柱状图
# 设置柱子的颜色
range_color = ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf',
'#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
# 设置左下方缩放条的最大值, 数据集中number列最大值
range_max = display_data['number'].max()
range_max
[i.tolist() for i in display_data.values]
from pyecharts.commons.utils import JsCode
import pyecharts.options as opts
c = (
Bar3D()#设置了一个3D柱形图对象
.add(
"",#图例
[d.tolist() for d in display_data.values],#数据
xaxis3d_opts=opts.Axis3DOpts(type_="category", name='分组名称'),#x轴数据类型,名称,rfm_group
yaxis3d_opts=opts.Axis3DOpts(type_="category", name='年份'),#y轴数据类型,名称,year
zaxis3d_opts=opts.Axis3DOpts(type_="value", name='会员数量'),#z轴数据类型,名称,number
)
.set_global_opts( # 全局设置
visualmap_opts=opts.VisualMapOpts(max_=range_max, range_color=range_color), #设置颜色,及不同取值对应的颜色
title_opts=opts.TitleOpts(title="RFM分组结果"),#设置标题
)
)
c.render_notebook() #在notebook中显示
1.5 案例结论
-
通过3d柱状图得到一些结论
-
通过代码得到一些结论
# 通过代码得到一些结论 # 统计每类用户占所有用户的比例 rfm_percent = display_data.groupby(by='rfm_group', as_index=False)['number'].sum() # rfm_percent['number'].sum() ->计算number的求和 # s对象和数值常数变量计算 rfm_percent['count_per'] = rfm_percent['number'] / rfm_percent['number'].sum() # 匿名函数中的x值是s对象中的每个值 rfm_percent['count_per'] = rfm_percent['count_per'].apply(lambda x: format(x, '.2%')) # 对number列进行降序 rfm_percent.sort_values(by='number', ascending=False)
1.6 结果保存
-
保存到excel中
rfm_gb.to_excel('sales_rfm_score1.xlsx') # 保存数据为Excel
-
保存到数据库中
# 需要安装pymysql,部分版本需要额外安装sqlalchemy # 导入sqlalchemy的数据库引擎 from sqlalchemy import create_engine # 创建数据库引擎,传入uri规则的字符串 engine = create_engine('mysql+pymysql://root:123456@192.168.88.100:3306/test?charset=utf8') # mysql+pymysql://root:123456@192.168.88.100:3306/test?charset=utf8 # mysql 表示数据库类型 # pymysql 表示python操作数据库的包 # root:123456 表示数据库的账号和密码,用冒号连接 # 192.168.88.100:3306/test 表示数据库的ip和端口,以及名叫test的数据库 # charset=utf8 规定编码格式 # df.to_sql()方法将df数据快速写入数据库 rfm_gb.to_sql('rfm_gb', engine, index=False, if_exists='append') # 第一个参数为数据表的名称 # 第二个参数engine为数据库交互引擎 # index=False 表示不添加自增主键 # if_exists='append' 表示如果表存在就添加,表不存在就创建表并写入
2 用户行为分析案例
2.1 用户行为分析概念
- 获取用户在网站或app等平台的一些数据, 根据数据进行相关的统计和分析, 从而获得其中的一些规律/规则
- 用户行为
- 登录
- 购买
- 点击
- 浏览
- 加购物车
- 转发
- 收藏
- 评论
- …
2.2 如何进行用户行为分析
- 事件分析 -> 研究某行为事件的发生对产品产生的影响以及影响程度
- 4w1h
- 谁在什么时间什么地点通过什么方式做了什么事情
- 收集用户信息, who -> 用户id, 账号, session id
- 收集各种事件, when -> 浏览事件, 点击时间, 下单时间, 支付时间, 完成时间, …
- 收集地址, where -> ip解析地址, 收货地址
- 收集事件, what -> 购买, 加购物, 点赞, …
- 收集使用的方式, how -> app, 网站, 设备信息, 浏览器信息
- 页面点击分析
- 通过统计不同页面的指标, 对页面进行各种分析
- pv -> 页面浏览次数
- uv -> 页面访问人数
- 页面内可点击次数
- 页面内的访问人数
- 占比
- 漏斗模型分析
- 统计各个阶段的转化率
- 用于网站用户行为分析和APP用户行为分析中,在流量监控、产品目标转化等日常数据运营与数据分析工作
- 用户行为路径分析
- 通过用户访问app或网址的路径进行分析
- 规定好访问页面或功能的顺序
- 统计不同页面或功能中的一些转化率
2.3 代码实现
-
数据处理
# 导入模块 import pandas as pd import numpy as np import matplotlib.pyplot as plt import time from datetime import datetime,timedelta,date import warnings warnings.filterwarnings('ignore') # 加载数据集 df = pd.read_csv('data/customer_behavior.csv') df.head() # 去掉没有用的列 Unnamed: 0 # 对day_id和buy_time列转换日期时间类型 # 获取2019-11-05~2019-11-13的数据子集 # 查看是否有缺失值的行数据, 删除 # 提取日期时间列中的部分时间 date, time, hour, day, dayofweek # 去掉没有用的列 Unnamed: 0 data = df.drop(labels=['Unnamed: 0'], axis=1) data.head() # 对day_id和buy_time列转换日期时间类型 data['day_id'] = pd.to_datetime(df['day_id']) data['buy_time'] = data['buy_time'].astype('datetime64[ns]') data.info() # 获取2019-11-05~2019-11-13的数据子集 data1 = data.query('buy_time>="2019-11-05" & buy_time<="2019-11-13"') data1.shape # 查看是否有缺失值的行数据, 删除 data1.isnull().any(axis=1).sum() # 提取日期时间列中的部分时间 date, time, hour, day, dayofweek data1['month'] = data1['day_id'].dt.month data1['hours'] = data1['day_id'].dt.hour data1['times'] = data1['day_id'].dt.time # 默认获取0-6, +1->周一~周日 data1['weekday'] = data1['day_id'].dt.dayofweek + 1 data1.head()
-
计算uv/pv/平均访问量/跳失率
# 计算 pv/uv 数 # 计算 平均访问量=pv/uv # 计算 跳失率=只有点击行为的用户数/总用户数 behavior_count = data1.groupby(by='be_type')['cust_id'].count() behavior_count # pv数 -> 页面点击次数, be_type列的值等于pv的条目数 PV = behavior_count['pv'] PV # uv数 -> 用户id进行去重之后的条目数 UV = len(data1['cust_id'].unique()) UV # 平均访问量 avg_vist_number = round(PV / UV) avg_vist_number print('平均访问量为%d' % avg_vist_number) # 跳失率 # 获取不同行为的数据的cust_id列 s对象 # 点击 data_pv = data1[data1['be_type']=='pv']['cust_id'] # 收藏 data_fav = data1[data1['be_type']=='fav']['cust_id'] # 加购物车 data_cart = data1[data1['be_type']=='cart']['cust_id'] # 购买 data_buy = data1[data1['be_type']=='buy']['cust_id'] # 获取只有点击行为的用户数 pv->[1,2,3,4,5] fav->[1,2] cart->[1,3] buy->[1,4] 只有点击行为的用户为5 # 获取唯一用户id的信息 转换成集合 去重操作 # len(set(data_pv)) # 集合作差 只有pv行为的用户id集合 data_pv_only = set(data_pv) - set(data_fav) - set(data_cart) - set(data_buy) data_pv_only # 只有pv行为的用户数 pv_only = len(data_pv_only) pv_only # 计算跳失率 以百分比形式保留2位小数 str(round((pv_only / UV) * 100, 2)) + '%'
-
按天数统计pv和uv数
# 按天统计用户的pv数 # 获取be_type=pv的数据子集 pv_day_data = data1[data1['be_type']=='pv'] pv_day_data.head() pv_day = pv_day_data.groupby(by='buy_time')['cust_id'].count() pv_day # 按天统计用户的uv数 uv数是去重的结果 # 当前是统计每天的uv数 根据buy_time和cust_id去重后统计 uv_day = pv_day_data.drop_duplicates(subset=['cust_id', 'buy_time']).groupby(by='buy_time')['cust_id'].count() uv_day # 数据可视化 pv_day.plot() attr = pv_day.index v1 = pv_day.values v2 = uv_day.values # 将两个图绘制到一起 #折线图绘制 fig = plt.figure(figsize=(16,12)) plt.subplot(2,1,1) xlabel=attr # x=range(len(xlabel)), y=v1 plt.plot(range(len(xlabel)),v1) plt.xticks(np.arange(9),'') plt.title('日点击量趋势图') plt.ylabel('日pv') for a,b in zip(range(len(xlabel)),v1): # plt.text(x,y,s): x,y为图形的x,y轴的值,s为给图形添加的文字,此时将pv数添加到折线图上展示 plt.text(a, b, b, ha='center', va='bottom', fontsize=10) plt.subplot(2,1,2) plt.plot(range(len(xlabel)),v2) plt.xticks(np.arange(9),('11-05 周二','11-06 周三','11-07 周四','11-08 周五','11-09 周六','11-10 周日','11-11 周一','11-12 周二','11-13 周三'),rotation=45) plt.title('日独立访客数趋势图') plt.ylabel('日uv') for a,b in zip(range(len(xlabel)),v2): # plt.text(x,y,s): x,y为图形的x,y轴的值,s为给图形添加的文字,此时将uv数添加到折线图上展示 plt.text(a, b, b, ha='center', va='bottom', fontsize=10) plt.show()
-
按小时统计pv和uv数
# 按小时统计pv数 pv_hour = data1.groupby(by='hours', as_index=False)['cust_id'].count().rename(columns={'cust_id':'pv'}) pv_hour # 按小时统计uv数 uv_hour = data1.drop_duplicates(subset=['hours', 'cust_id']).groupby(by='hours', as_index=False)['cust_id'].count().rename(columns={'cust_id':'uv'}) uv_hour # 数据可视化 # sharex=True:多图共享x轴 fig, axes = plt.subplots(2,1,sharex=True,figsize=(16,12)) pv_hour.plot(x='hours',y='pv',ax=axes[0]) uv_hour.plot(x='hours',y='uv',ax=axes[1]) # 设置x轴的刻度值和刻度标签 plt.xticks(range(24), np.arange(24)) axes[0].set_title('按小时点击量趋势图') axes[1].set_title('按小时独立访客数趋势图')
-
计算每天的n日留存率
# 计算留存率 # 留存率 = n日留存数 / 当天新用户数 # 统计2019-11-05的3日留存, 2019-11-05新用户数, 统计2019-11-08留存用户数(11-05新用户中又登录的用户) # 定义一个空列表, 存储用户信息 user=[] # 获取2019-11-05的数据子集 data1[data1['buy_time']=='2019-11-05']['cust_id'].unique() # 获取2019-11-05的新用户数据 new_user = set(data1[data1['buy_time']=='2019-11-05']['cust_id'].unique()) - set(user) # 将当天的所有用户添加到user列表中 user.extend(new_user) # 获取3天之后的数据子集, 目的是获取用户数据 # user_nday中既有前3天的用户,也有当天的新用户 user_nday = data1[data1['buy_time']=='2019-11-08']['cust_id'].unique() # a是记录留存用户数, 初始为0个 a = 0 # 判断user_nday中哪些用户是2019-11-05的用户, 如果是说明是留存用户 for i in user_nday: if i in new_user: a+=1 a # 2019-11-05 一共有多少个新用户 b = len(new_user) b # 留存率 a / b
-
封装到函数中
def cal_retention(data, n): # n为n日留存 # 定义空列表, 存储老用户 user=[] date=pd.Series(data.buy_time.unique()).sort_values()[:-n] #时间截取至最后一天的前n天,不截取的话最后的日期是无法计算n日留存率的 retention_rates=[] # 循环遍历日期, 计算每天的留存率 for i in date: new_user=set(data[data.buy_time==i].cust_id.unique())-set(user) #识别新用户,本案例中设初始用户量为零,当前天中如果出现了之前user中的用户,说明此用户是第二次购买不再是新用户,留存率统计的是新用户的,所以需要去掉 user.extend(new_user) #将新用户加入老用户群中 #第n天留存情况 user_nday=data[data.buy_time==i+timedelta(n)].cust_id.unique() #第n天登录的用户情况 a=0 #循环第n天登录的用户,和new_user中的用户对比,如果在new_user中,说明new_user中的用户在第n天又进行了登录,此时这个用户就是留存的用户,a值就加1 for cust_id in user_nday: if cust_id in new_user: a+=1 retention_rate=a/len(new_user) #计算该天第n日留存率 retention_rates.append(retention_rate) # 创建s对象 data_retention = pd.Series(retention_rates, index=date) return data_retention data_retention = cal_retention(data1, 3) data_retention
-
-
计算每日购买人数和购买率
# 每天购买人数和购买率 # 购买人数 -> 发生购买行为的数据中的人数, 人数指定是一个人在一天中发生多次购买记录也记作一个人 # 购买率 -> 购买人数 / 当天总数(包含pv,fav,cart,buy) # 每天购买人数 # 对日期和客户id去重, 获取每天每个用户的购买数据子集 day_buy_user_num = data1[data1['be_type']=='buy'].drop_duplicates(subset=['buy_time', 'cust_id']).groupby(by='buy_time')['cust_id'].count() day_buy_user_num # 每天购买率 = 每天购买人数 / 每天总人数 # 每天总人数 day_active_user_num = data1.drop_duplicates(subset=['buy_time', 'cust_id']).groupby(by='buy_time')['cust_id'].count() # 购买率 day_buy_rate = day_buy_user_num / day_active_user_num day_buy_rate # 数据可视化 plt.figure(figsize=(16,8)) plt.plot(day_buy_user_num.index, day_buy_user_num.values) day_buy_rate.plot()
-
复购率
# 复购率=有复购行为的用户数/有购买行为的用户数 # 复购: 一个用户多天进行购买, 一天有多次购买也记作一次购买 # 统计每个用户购买次数(天数) df_rebuy = data1[data1['be_type']=='buy'].drop_duplicates(subset=['cust_id', 'buy_time']).groupby(by='cust_id')['buy_time'].count() df_rebuy.head() # 复购率, 购买次数大于等于2条目数/总的条目数 df_rebuy[df_rebuy>=2].count() / df_rebuy.count()
-
各阶段转换
# 各个阶段转化率计算 # 加购物车和收藏转化率 = 加购物车和收藏条目数 / 点击条目数 # 购买转化率 = 购买条目数 / 点击条目数 behavior_count # 获取加购车条目数 cart_value = behavior_count['cart'] # 获取收藏条目数 fav_value = behavior_count['fav'] # 计算加购车和收藏的条目数 fav_cart_value = cart_value + fav_value # 获取点击条目数 pv_value = behavior_count['pv'] # 计算加购车和收藏转化率 fav_cart_ratio = fav_cart_value / pv_value fav_cart_ratio # 计算购买转化率 buy_value = behavior_count['buy'] buy_ratio = buy_value / pv_value buy_ratio # 各个阶段条目数漏斗模型 !pip install plotly attr = ['点击', '加入购物车', '收藏', '购买'] # 设置stage标签 # 需要安装 plotly 包, pip install plotly import plotly.express as px # 绘图能看懂会用就好,不需要记 data = dict( # x轴数据列表 number=[pv_value, cart_value, fav_value, buy_value], # y轴数据列表 stage=attr) data fig = px.funnel(data_frame=data, x='number', y='stage') fig.show()
-
不同类别商品分析
# 统计前十不同商品类别的购买条目数 # 统计前十不同商品类别的点击条目数 # 以上两者合并 # 统计不同商品类别的点击,加购物车,收藏,购买条目数, 购买转化率 # 统计前十不同商品类别的购买条目数 product_buy_count = data1[data1['be_type']=='buy'][['cust_id', 'group_id']].groupby(by='group_id')[['cust_id']].count().rename(columns={'cust_id':'销售次数'}) product_buy_count = product_buy_count.sort_values(by='销售次数', ascending=False).head(10) product_buy_count # 统计前十不同商品类别的点击条目数 product_pv_count = data1[data1['be_type']=='pv'][['cust_id', 'group_id']].groupby(by='group_id')[['cust_id']].count().rename(columns={'cust_id':'点击次数'}) product_pv_count = product_pv_count.sort_values(by='点击次数', ascending=False).head(10) product_pv_count # 以上两者合并 横向合并 pd.concat([product_buy_count, product_pv_count], axis=1) # 统计不同商品类别的点击,加购物车,收藏,购买条目数, 购买转化率 # 通过透视表操作 item_behavior = pd.pivot_table(data=data1, index='group_id', columns='be_type', values='cust_id', aggfunc='count').fillna(0) # 计算每类商品的购买转化率, 新增一列 item_behavior['购买转化率'] = item_behavior['buy'] / item_behavior['pv'] item_behavior.sort_values(by='购买转化率', ascending=True)