简介:电商用户行为分析是一份面向大数据分析方向毕业设计或相关课题研究的可运行源码包,围绕2017年11月25日至12月3日淘宝用户超1亿条行为记录,梳理了数据导入、清洗、异常值处理、Hive分析及可视化全流程,重点呈现用户流量、行为转化率、行为习惯、RFM高价值用户识别和商品维度分析等内容。包内共20个文件,压缩包约16.37MB,以Python脚本、JSON结果、Markdown说明文档为主,同时包含CSV样例数据和Shell安装脚本,便于快速搭建运行环境、理解分析逻辑并复用代码。目前已吸引85人学习下载,适合准备电商数据分析类毕设、希望掌握大数据分析整体项目框架的学生或从业者参考。除了完整源码和数据集,还提供论文级说明与迁移指南,可帮助读者复现项目方法,并在Hive数据分析、用户画像构建和可视化呈现等方面获得可直接落地的思路与实现。
电商用户行为分析:一套可以直接跑的数据分析源码
说实话,做数据分析这几年,我见过太多“Excel拉个透视表就当用户分析”的项目。真要落地到用户分层、转化漏斗、留存预测这些业务动作上,光靠几张静态报表根本不够。最近我把之前给某电商团队做的一套用户行为分析方案整理成了可运行的源码,今天把整套思路和关键实现拆开讲一遍,项目本身不大,但数据清洗、RFM分层、漏斗转化、留存分析、商品偏好这些核心模块都齐了,跑一遍就能用在自己项目上。适合刚接触用户增长分析的数据分析师,也适合产品经理、运营同学拿去做参考,更重要的是——源码可以直接跑,不是那种贴了半截还得自己脑补的demo。
1.1 这套源码到底能做什么
先说清楚项目边界。这套分析基于的是电商平台最常见的用户行为日志数据,就是那种每行记录一个用户行为的明细表,包含用户ID、行为类型(浏览、加购、收藏、支付)、商品ID、行为时间、商品类目和金额字段。源码覆盖了从数据载入、清洗到产出分析结论的完整链路,具体包括几个层面:整体流量看板(PV、UV、支付用户数)、用户转化漏斗(浏览→加购→收藏→支付)、RFM用户价值分层、用户生命周期留存分析,以及商品维度的品牌和品类偏好挖掘。每一块都有对应的代码、可视化图表和输出结果解释,不是光画个图就完了,每个分析结果旁边都附了“这个数字能指导什么业务动作”的解读。
我做这套项目的核心动机其实很简单。市面上的用户行为分析要么用BI工具拖拽,要么直接用付费分析平台,对中小团队来说成本和灵活性都是问题。用Python写一套可复用、可改参数的分析脚本,既能跑数据出结论,又能随时增加分析维度,源码在手里,业务问题随时可以定制。这次开源出去的版本,数据采用公开的电商行为数据集格式,你可以直接从网上找到对应CSV来测,也可以替换成自己业务库的导出数据,只要字段对得上,代码几乎不用大改。
1.2 技术选型:为什么是 Python + Pandas 而不是别的
先说一个很多新手会问的问题:这套东西为什么不用SQL一把梭,或者直接用Tableau?答案是——分析场景不同。SQL适合固定口径的报表查询,但一旦涉及RFM这种需要先算每个用户的R、F、M三个分值再分层,又要把分层结果回写到明细数据里的复杂逻辑,SQL写起来会非常绕。而Tableau这类BI工具做展示很顺手,可它的计算逻辑是黑盒,出了问题不好排查,更没法方便地做批量回测和参数调优。
这套源码我选的是Python 3.9 + Pandas 2.0 + Matplotlib/Seaborn的组合。Pandas处理千万行级别的数据完全没压力,RFM这种分组聚合计算用groupby配合自定义函数几行就能搞定。可视化部分用Matplotlib和Seaborn是因为它们和Pandas的DataFrame无缝衔接,直接传入列就能出图,不需要额外的ETL。整个项目跑完一轮(包括加载数据和生成全部图表)在一台普通MacBook Pro上大约3分钟,这个效率对于日常分析完全够用。
提示:如果你的数据量真正到了亿级,那确实需要考虑Spark或者ClickHouse,但对绝大多数电商团队来说,Pandas纯内存计算反而是最省事、最容易调试的方案。
2. 数据准备与核心指标拆解
2.1 输入数据长什么样
这套源码的核心输入是行为日志表和商品信息表。行为日志表我按最常见的电商埋点格式设计,核心字段包括:
| 字段名 | 含义 | 示例值 |
|---|---|---|
| user_id | 用户ID | 100001 |
| behavior_type | 行为类型 | pv / cart / fav / buy |
| item_id | 商品ID | 2354 |
| category_id | 商品类目ID | 475 |
| timestamp | 行为时间(毫秒级) | 1511544070691 |
| brand_id | 品牌ID | 2891 |
商品信息表则包含商品ID、类目、品牌、价格区间、上架时间等属性。两张表通过item_id关联。如果你是自己导数据,把业务库里的订单表、日志表按照这个结构整理成CSV就行,注意时间字段需要统一格式,这个源码里我做了兼容处理,秒级和毫秒级时间戳都能自动识别。
这里有一个实际项目里特别容易踩坑的地方:行为日志和订单数据经常是两个系统导出的,用户ID的编码规则可能不一样。日志里是"U12345"带前缀的字符串,订单里是纯数字,两表一关联就会丢数据。我的建议是,在数据清洗阶段就统一用户ID格式,源码里专门写了格式化函数,把所有ID统一转为整数类型,避免后续所有分析的关联键不一致。
2.2 核心指标的选取逻辑
做用户行为分析最忌讳的就是指标堆砌。这套源码里我聚焦了五个核心分析维度,每个维度对应的都是明确的业务问题:
第一,流量与转化概览,回答“平台当前的用户规模和转化效率是什么水平”。第二,转化漏斗,回答“用户在哪个环节流失最严重,最值得优化”。第三,RFM分层,回答“哪些用户是高质量高价值用户,哪些即将流失,哪些是沉睡用户”。第四,留存分析,回答“各渠道进来的用户,第一周、第二周、一个月后还剩下多少”。第五,商品偏好,回答“卖得好的商品集中在什么品类和品牌,用户加购最多的是什么”。
为什么是这几个指标而不是其他?关键在于它们构成了一个闭环:流量看整体现状,漏斗找问题环节,RFM做用户分群和精细化运营,留存验证长期价值,商品分析落到货品策略。这五块组合起来,基本能覆盖电商运营周报里80%的数据需求。相比之下,有些项目上来就算什么人均浏览深度、跳出率、页面停留时长,这些指标不是没用,而是它们更适合产品体验优化场景,对当前这套以用户价值分析为核心的源码来说,信息增益有限,所以我在代码里刻意没有加入,避免输出一大堆图表让读者抓不住重点。
3. 核心代码实现:从原始日志到业务洞察
3.1 数据加载与清洗
源码的第一步是数据载入,这一步看似简单,但里面有几个处理细节是新手上路最容易出问题的地方。时间戳的转换、数据去重、字段类型修正、异常值过滤,这些前置动作做不好,后面所有的分析口径都会歪。
import pandas as pd import numpy as np from datetime import datetime # 读取行为日志和商品信息 behavior = pd.read_csv('data/user_behavior.csv', sep=',') items = pd.read_csv('data/item_info.csv', sep=',') # 时间戳统一处理:兼容秒级和毫秒级 def convert_timestamp(ts): ts = int(ts) if ts > 10**12: # 毫秒级 return datetime.fromtimestamp(ts / 1000) return datetime.fromtimestamp(ts) behavior['event_time'] = behavior['timestamp'].apply(convert_timestamp) behavior['event_date'] = behavior['event_time'].dt.date # 去重,防止埋点重复上报 behavior = behavior.drop_duplicates().reset_index(drop=True) # 过滤异常记录:金额为负、用户ID为空等 behavior = behavior[behavior['user_id'].notna()] print(f"清洗后数据量: {len(behavior):,} 行")这里我特别说明一下去重的逻辑。很多团队做用户分析的时候没有对原始日志做去重,导致后面计算的PV虚高。实际操作中我发现,同一个用户在短时间内对同一件商品的重复浏览,可能是页面刷新造成的,也可能是用户真的来回对比。源码里我给了一个保守的去重方案:完全重复的记录直接删除,如果想去掉更激进的去重(比如用户5分钟内对同一商品重复浏览只算一次),可以在代码里加一个时间窗口的groupby判断,这个逻辑我注释在了代码中,按需放开就行。
3.2 RFM用户分层:最经典的精细化运营模型
RFM模型是整个源码里我最看重的一块。它的思路很简单:用最近一次购买时间(Recency)、购买频率(Frequency)和购买金额(Monetary)三个维度给用户打分,然后根据分数组合把用户分成不同层级。这套模型看起来简单,但落地的时候有不少细节,比如分数的阈值怎么定,层级怎么命名,不同行业的判断标准差异很大,所以源码里我把阈值设成可配置参数。
# 按用户聚合RFM指标 def compute_rfm(df): # 以当前数据最大日期作为基准日 current_date = df['event_date'].max() rfm = df[df['behavior_type'] == 'buy'].groupby('user_id').agg( recency=('event_date', lambda x: (current_date - x.max()).days), frequency=('event_date', 'count'), monetary=('amount', 'sum') ).reset_index() return rfm rfm_df = compute_rfm(behavior) # 打分:这里使用分位数切分,避免人为硬编码阈值 def score_by_quantile(series, reverse=False): qs = series.quantile([0.25, 0.5, 0.75]) def score_val(v): if reverse: # recency越小越好 if v <= qs[0.25]: return 4 elif v <= qs[0.5]: return 3 elif v <= qs[0.75]: return 2 return 1 else: # frequency/monetary越大越好 if v >= qs[0.75]: return 4 elif v >= qs[0.5]: return 3 elif v >= qs[0.25]: return 2 return 1 return series.apply(score_val) rfm_df['r_score'] = score_by_quantile(rfm_df['recency'], reverse=True) rfm_df['f_score'] = score_by_quantile(rfm_df['frequency']) rfm_df['m_score'] = score_by_quantile(rfm_df['monetary']) # 分层规则 def rfm_segment(row): if row['r_score'] >= 3 and row['f_score'] >= 3 and row['m_score'] >= 3: return '高价值用户' elif row['r_score'] <= 2 and row['f_score'] >= 3 and row['m_score'] >= 3: return '沉睡高价值用户' elif row['r_score'] >= 3 and row['f_score'] <= 2 and row['m_score'] <= 2: return '新用户' elif row['r_score'] <= 2 and row['f_score'] <= 2 and row['m_score'] <= 2: return '流失用户' else: return '潜力用户' rfm_df['segment'] = rfm_df.apply(rfm_segment, axis=1)关于阈值切分,我多说一句经验。很多教程直接告诉你R≤3天打4分、3-7天打3分这种固定规则,但实际业务里不同品类的购买周期差异巨大——卖日用品的和卖大家电的,购买频率根本不是一个量级。所以源码里我选择用分位数(quantile)切分,让数据自己说话,这样换一个数据集、换一个行业,代码不用改,分层逻辑依然成立。如果你有明确的业务经验,比如运营明确告诉你“3个月内没复购就算流失”,也可以直接把打分函数改成硬编码阈值,这部分预留了修改接口。
3.3 用户转化漏斗:定位流失最严重的环节
漏斗分析是电商运营的日常操作,但很多人做的漏斗其实有个口径问题:到底是用“会话”做漏斗还是用“用户”做漏斗?用会话做漏斗,适合分析单次访问的转化路径,比如落地页→详情页→下单;用用户做漏斗,适合分析用户在整段时间内的行为转化,比如浏览过商品的人里最终有多少人完成了支付。这套源码做的是用户级漏斗,逻辑是把用户按行为类型分组,统计每个环节的用户数,再计算环节之间的转化率。
# 用户级漏斗统计 funnel_data = {} for behavior_type in ['pv', 'cart', 'fav', 'buy']: user_count = behavior[behavior['behavior_type'] == behavior_type]['user_id'].nunique() funnel_data[behavior_type] = user_count funnel_df = pd.DataFrame(list(funnel_data.items()), columns=['stage', 'user_count']) funnel_df['conversion_rate'] = funnel_df['user_count'] / funnel_df['user_count'].iloc[0] * 100 funnel_df['step_rate'] = funnel_df['user_count'].shift(1) / funnel_df['user_count'] * 100这个漏斗的逻辑是:先看有多少用户发生过浏览行为,然后看这些用户里有多少加购,再看多少收藏,最后看多少完成支付。每一个环节的用户数都是独立统计的,不是累计的——比如“加购用户数”指的是发生过加购行为的独立用户数,而不是“浏览且加购”的用户数。两者各有适用场景,但“独立用户数”更直观,能直接回答“平台里到底有多少用户愿意加购”这个基础问题。
从实践来看,漏斗分析真正有价值的地方不在总转化率,而在两个递进率之间的差值。比如浏览到加购的转化率是8%,加购到支付的转化率是45%,那说明用户加购意愿还行但支付转化不错,问题可能出在商品详情页吸引力不够上;反过来,浏览到加购有20%,加购到支付只有15%,那说明详情页没问题,但可能是价格、支付流程或者物流费用把用户劝退了。源码在输出漏斗图的同时,也会自动打印每一个环节的递进转化率,方便直接对照分析。
3.4 留存分析与商品偏好
留存分析这块,源码按“日留存”和“周留存”两种维度计算。日留存适合看短期产品迭代效果和活动拉新质量,周留存更适合看电商平台的自然留存水平,因为电商用户的访问周期天然比内容产品要长。
# 计算每个用户的活跃日期 user_active = behavior[['user_id', 'event_date']].drop_duplicates() # 生成用户首日活跃日期 first_active = user_active.groupby('user_id')['event_date'].min().reset_index() first_active.columns = ['user_id', 'first_date'] # 合并得到用户活跃日与首日的时间差(天) user_cohort = user_active.merge(first_active, on='user_id') user_cohort['days_diff'] = (user_cohort['event_date'] - user_cohort['first_date']).dt.days # 留存矩阵 retention = user_cohort[user_cohort['days_diff'].between(0, 30)] retention_matrix = retention.pivot_table( index='first_date', columns='days_diff', values='user_id', aggfunc='nunique', fill_value=0 )留存矩阵的核心是以用户首次活跃日期为基准,看这批用户在后续第N天还有多少人回来。实操中我一般会输出留存矩阵的热力图,横轴是首次活跃后的第几天,纵轴是首次活跃日期,颜色深浅代表留存用户数或留存率。这里有一个关键细节:每个日期的新用户基数不同,直接比较用户数没有意义,所以源码里会自动把留存矩阵转换成留存率(每个格子除以当天的首日用户数),这样不同日期的留存曲线才具有可比性。
商品偏好分析相对简单。源码里按商品维度统计了浏览量、加购量、支付量,然后计算“加购转化率”(加购用户数/浏览用户数)和“支付转化率”(支付用户数/浏览用户数),这两个指标能直接筛选出“高意向但低转化”的商品,是运营做促销选品、客服做回访的黄金清单。同时在商品分析模块里我还加了品类维度的交叉分析,帮助判断哪些品类的流量承接做得最好。
3.5 可视化输出:让分析结果自己说话
说实话,代码写得再漂亮,最后业务方看不懂也是白搭。所以这套源码在可视化上花了心思,输出全部自动保存为PNG图片到result目录,并且每张图都做了中英文标签适配。核心图表包括:每日PV/UV趋势折线图、用户转化漏斗图、RFM四象限散点图、留存热力图、商品类目Top10柱状图。
import matplotlib.pyplot as plt import seaborn as sns plt.rcParams['font.sans-serif'] = ['SimHei'] # 支持中文显示 plt.rcParams['axes.unicode_minus'] = False # 每日PV/UV趋势 daily = behavior.groupby('event_date').agg( pv=('user_id', 'count'), uv=('user_id', 'nunique') ).reset_index() fig, ax1 = plt.subplots(figsize=(12, 6)) ax1.plot(daily['event_date'], daily['pv'], color='#2E86AB', label='PV') ax1.plot(daily['event_date'], daily['uv'], color='#A23B72', label='UV') ax1.set_xlabel('日期') ax1.set_ylabel('数量') ax1.legend() plt.title('每日PV/UV趋势', fontsize=14) plt.xticks(rotation=45) plt.tight_layout() plt.savefig('result/daily_trend.png', dpi=150)如果你用的是Mac或者Linux服务器,中文字体可能渲染不出来,解决方法是把SimHei改成系统里已安装的中文字体名称,或者干脆用英文标签。源码里我把字体设置放在一个config区域,换环境改一处就行,不用到处找。
4. 运行环境与实操步骤
4.1 依赖安装与目录结构
项目运行环境非常简单,Python 3.9以上版本,安装Pandas、Matplotlib、Seaborn三个库就够了。建议使用虚拟环境隔离依赖:
conda create -n ecommerce_analysis python=3.9 conda activate ecommerce_analysis pip install pandas matplotlib seaborn源码目录结构是这样的:
├── data/ │ ├── user_behavior.csv # 用户行为日志 │ └── item_info.csv # 商品信息表 ├── result/ # 分析结果输出目录 ├── config.py # 全局配置(阈值、字体、路径) ├── data_process.py # 数据加载与清洗 ├── metrics.py # 指标计算(RFM、漏斗、留存等) ├── visualization.py # 图表绘制 └── main.py # 主入口,一键执行完整分析main.py是整个项目的调度中心,顺序执行数据加载、清洗、指标计算、可视化,最后输出一份汇总的CSV报告和所有图表。全程不需要任何人工干预,非常适合放在服务器上定时跑(比如每天凌晨自动更新运营报表)。
4.2 从零到一运行项目
实际演示一遍。假设你已经把user_behavior.csv和item_info.csv放到了data目录下,在项目根目录执行:
python main.py终端会依次输出:数据加载的行数、清洗后剩余行数、RFM分层各类用户的数量、漏斗各环节的用户数和转化率、留存率的Top几行预览,最后提示“分析完成,结果已保存至result/目录”。整个流程走完大约2-3分钟,取决于数据量的大小。我用一份100万行的公开数据集跑过一轮,耗时1分48秒,内存占用约1.2GB,可以说相当克制了。
如果你想把分析结果接入自己的报表系统,可以修改main.py的末尾部分,把CSV汇总结果写入MySQL或者发送到钉钉/企业微信机器人。源码里我预留了一个send_to_webhook的函数模板,里面写了请求体的格式示例,接入的时候只需要填上webhook地址和消息模板即可。
5. 常见问题与排查技巧实录
5.1 我踩过的那些坑
这套源码在打磨过程中,我先后遇到过几个比较典型的问题,专门写出来供你参考。
第一个坑是时间戳精度不一致。公开数据集里有一批时间戳是秒级,另一批是毫秒级,直接统一除以1000转换,会导致一部分时间提前了约47年,整个留存分析直接报废。排查过程其实不复杂——我先输出转换后时间的最大值和最小值,发现最小值是1970年代,立刻意识到是精度问题。解决方案就是我上面写的兼容性转换函数,按数值大小判断精度,这个问题算是解决了。
第二个坑是内存溢出。我记得第一次跑全量2000万行数据的时候,Pandas直接把16GB内存吃满了,电脑风扇狂转。后来排查发现主要瓶颈在RFM计算那一步,因为要对购买记录做多次groupby和merge。解决办法是优先过滤掉不需要的行(比如只保留有购买行为的用户来做RFM,而不是对全量行为做),然后再计算。源码里我用了这个思路,在compute_rfm函数里先df[df['behavior_type'] == 'buy']过滤,再进入聚合,性能提升非常明显。
第三个坑是中文图表乱码。代码刚写完在Windows上跑一切正常,换到Linux服务器直接变方块。原因是服务器上没有中文字体,Matplotlib找不到合适的字体渲染。这个没什么技术含量,但确实容易卡住新手,解决方式是提前查一下系统有哪些字体,如果连SimHei都没有,就下载一个开源的文泉驿微米黑,装完之后清除Matplotlib缓存再运行。
5.2 问题排查速查表
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 图表中文显示为方块 | 系统缺少中文字体 | 安装中文字体,修改config.py字体配置 |
| 留存矩阵中日期错乱 | 时间戳精度不一致 | 使用兼容转换函数,统一转为datetime |
| 运行内存不足 | 数据量过大 | 先过滤无用字段,分块读取,或启用Pandas分块处理 |
| RFM分层结果全是同一类 | 阈值切分失效 | 检查是否有极端值,尝试用log变换后再分位数 |
| 漏斗转化率超过100% | 环节之间用户不是包含关系 | 确认漏斗口径,建议统计独立用户数 |
| 秒级时间戳被识别成毫秒 | 数值判断逻辑不正确 | 检查threshold阈值设置,10^12判断毫秒 |
最后分享一个私藏技巧。跑完整个分析之后,别急着关项目,把daily_trend.png和retenion_heatmap.png拿给业务同事看的时候,我习惯同时附上两份CSV:一份是RFM分层后的用户明细表,另一份是漏斗各环节用户数明细。这样运营同学可以直接用RFM分层表做用户包的圈选,不需要自己再写一遍取数逻辑。我觉得一套分析源码的真正价值不只是出几张好看的图,而是把分析结果变成业务方可直接使用的数据资产,这才是电商用户行为分析该有的样子。
本文还有配套的精品资源,点击获取