Python用户画像分析实战:从原始数据到可视化洞察
·
一、数据加载:先把数据读进来
1.1 导入必备库
import pandas as pd # 数据处理神器,没有它啥也干不了
import numpy as np # 数值计算库,pandas底层靠它
1.2 读取行为数据(大文件分块读取)
原始数据有1300多万行,直接读可能内存撑不住,所以用分块读取的方式:
# chunksize=10000 表示每次只读1万行,分批加载
data = pd.read_csv('action.csv', chunksize=10000)
chunks = [] # 准备一个空列表,用来装每一块数据
for chunk in data: # 遍历每一块
chunk = pd.DataFrame(chunk) # 转成DataFrame格式
chunks.append(chunk) # 把这一块塞进列表里
# 把所有小块拼成一个大表(就像拼积木一样)
action = pd.concat(chunks)
# 只保留我们需要的5列,其他的不要(省内存)
action = action[['user_id', 'sku_id', 'time', 'type', 'cate']]
为什么要分块? 1300万行数据直接读可能占500MB+内存,电脑容易卡。分块读取虽然代码多一点,但稳!
1.3 看看数据长什么样
action.info()
输出结果告诉我们:
- 总共 13,199,934 行(1300多万条行为记录)
- 5列:
user_id(用户ID)、sku_id(商品ID)、time(时间)、type(行为类型)、cate(品类) - 占用内存约 503.5 MB
二、数据清洗:脏数据得收拾干净
数据清洗是分析的第一步,就像做菜前要洗菜一样。
2.1 检查空值
action.isnull().sum()
结果:5列都是0空值,数据还算干净,不用填空。
2.2 检查重复值
action.duplicated().sum()
# 结果:7262534(726万条重复!超过一半是重复的)
2.3 删除重复行
# inplace=True 表示直接在原表上改,不用重新赋值
action.drop_duplicates(inplace=True)
726万条重复数据! 删完之后只剩593万条,说明原始数据质量堪忧,清洗这步绝对不能省。
2.4 检查异常值
action.describe()
看统计摘要,检查有没有离谱的值(比如负数的用户ID、超大的时间戳等),这里数据还算正常。
2.5 处理字段类型
# user_id从浮点数转成整数(用户ID不该有小数点)
action['user_id'] = action['user_id'].astype('int64')
# time从字符串转成时间格式(转完才能做时间计算)
action['time'] = pd.to_datetime(action['time'])
action.head()
| user_id | sku_id | time | type | cate |
|---|---|---|---|---|
| 287842 | 75018 | 2016-03-31 23:59:01 | 6 | 9 |
| 208266 | 31662 | 2016-03-31 23:59:04 | 1 | 8 |
| 209390 | 118799 | 2016-03-31 23:59:05 | 6 | 8 |
三、特征提取:找出"高潜用户"
高潜用户 = 最有可能复购的用户。我们的思路是:找到那些购买时间距首次交互时间较长的用户,说明他们深思熟虑后才买,这类用户更容易复购。
3.1 理解行为类型(type字段)
action['type'].unique()
# 结果:array([6, 1, 4, 2, 3, 5])
action['type'].value_counts()
| type | 数量 | 含义(推测) |
|---|---|---|
| 6 | 326万 | 浏览(最多,大家都在逛) |
| 1 | 241万 | 点击 |
| 2 | 15万 | 加购物车 |
| 3 | 7万 | 删购物车 |
| 5 | 2.2万 | 收藏 |
| 4 | 1.2万 | 购买(最少,真正掏钱的) |
3.2 只看"购买"行为
# type==4 就是购买行为,把购买记录单独拎出来
action_type4 = action[action['type'] == 4]
action_type4.head()
3.3 只分析品类4(简化分析)
# 为了方便理解,只筛选一个品类来分析
# 实际工作中可以分析所有品类,这里只是演示
action_type4 = action_type4[action_type4['cate'] == 4]
# 结果:2764条购买记录
3.4 找出每个用户最近一次购买时间
# 按user_id分组,取每组的最大时间(就是最近一次购买时间)
ac_lastbuytime = action_type4.groupby(by='user_id')['time'].apply(lambda x: x.max())
ac_lastbuytime.head()
| user_id | 最近购买时间 |
|---|---|
| 200053 | 2016-04-13 20:16:00 |
| 200054 | 2016-04-14 08:22:00 |
| 200092 | 2016-04-04 09:29:00 |
3.5 找出每个用户最早与商品的交互时间
# 把"最近购买时间"和"全部行为数据"合并,这样就能知道每个用户的所有行为
ac_all_buy = pd.merge(ac_lastbuytime, action, on='user_id')
# 按user_id分组,取最小时间(就是最早一次交互时间)
ac_firsttime = ac_all_buy.groupby('user_id')['time_y'].apply(lambda x: x.min())
3.6 计算时间差——核心指标!
# 把"最近购买时间"和"最早交互时间"合并到一张表
df = pd.merge(ac_lastbuytime, ac_firsttime.to_frame(), on='user_id')
df.columns = ['buytime', 'ac_time'] # 改个好看的名字
# 计算天数差:购买时间 - 首次交互时间
df['days'] = (pd.to_datetime(df['buytime']) - pd.to_datetime(df['ac_time'])).dt.days
df.head()
| user_id | buytime | ac_time | days |
|---|---|---|---|
| 200053 | 2016-04-13 20:16:00 | 2016-04-01 18:16:48 | 12 |
| 200054 | 2016-04-14 08:22:00 | 2016-04-07 13:25:56 | 6 |
| 200092 | 2016-04-04 09:29:00 | 2016-04-01 08:48:09 | 3 |
days是什么意思? 比如用户200053,4月1号第一次浏览商品,4月13号才下单,中间隔了12天。这个天数越长,说明用户决策越谨慎。
3.7 筛选高潜用户
# 筛选时间差>1天的用户(交互超过1天才购买的,就是高潜用户)
high_pot = df[df['days'] > 1]
high_pot
# 结果:1882个高潜用户(总共2364个购买用户中)
为什么选>1天? 当天就买的用户可能是冲动消费,不容易复购;想了一两天以上才买的,更可能成为忠实用户。
四、合并用户画像数据
现在我们有了高潜用户列表,还需要知道这些用户的年龄、性别、等级等信息。
4.1 读取用户数据
# 读取用户基本信息表
user = pd.read_csv('user.csv')
user.head()
| user_id | age | sex | user_lv_cd | browse_num | addcart_num | delcart_num | buy_num | favor_num | click_num |
|---|---|---|---|---|---|---|---|---|---|
| 200001 | 6.0 | 2.0 | 5 | 212.0 | 22.0 | 13.0 | 1.0 | 0.0 | 414.0 |
| 200002 | -1.0 | 0.0 | 1 | 238.0 | 1.0 | 0.0 | 0.0 | 0.0 | 484.0 |
字段含义:
age:年龄段编码(-1表示未知,数字越大年龄越大)sex:性别(0/1/2,其中0可能是女性居多)user_lv_cd:用户等级(1-5,5最高)browse_num:浏览次数addcart_num:加购次数delcart_num:删购次数buy_num:购买次数favor_num:收藏次数click_num:点击次数
4.2 检查数据质量
user.shape
# (105321, 10) -- 10万+用户,10个字段
user.isnull().sum()
| 字段 | 空值数 |
|---|---|
| user_id | 0 |
| age | 3 |
| sex | 3 |
| browse_num | 141 |
| addcart_num | 141 |
| ... | 141 |
# 看看空值占比
user.isnull().mean()
# 空值最多只占0.13%,千分之一,影响很小
4.3 删除空值
# 空值占比千分之一,对结果影响较小,直接删除
user.dropna(inplace=True)
4.4 合并高潜用户和行为数据
# 用user_id做关联,把用户信息和购买时间差合并到一起
user_high = pd.merge(user, high_pot, on='user_id')
user_high
# 结果:1882行 × 13列
# 保存一份,方便后续使用
user_high.to_csv('user_high.csv')
五、可视化分析:用图表说话
数据准备好了,开始画图!我们用 pyecharts 和 Plotly 两种工具来画。
5.1 用户等级占比(饼图)
# 先统计各等级的人数
user_lv_count = user_high['user_lv_cd'].value_counts()
user_lv_count
# 等级5: 1187人, 等级4: 545人, 等级3: 147人, 等级2: 3人
用pyecharts画饼图:
from pyecharts.charts import *
import pyecharts.options as opts
# 准备数据:把等级和人数配对
num = user_lv_count.values.tolist() # [1187, 545, 147, 3]
lev = user_lv_count.index.tolist() # [5, 4, 3, 2]
# 配对成 [("等级5", 1187), ("等级4", 545), ...] 的格式
data_pair1 = [("等级" + str(i), j) for i, j in zip(lev, num)]
# 画饼图
pie = (
Pie()
.add("占比", data_pair=data_pair1) # 填入数据
.set_global_opts(
tooltip_opts=opts.TooltipOpts(is_show=True, formatter='{b}:{d}%'), # 鼠标悬停显示百分比
title_opts={'text': '高潜用户各等级占比'} # 标题
)
)
pie.render_notebook()
洞察: 等级5的用户占63%(1187/1882),说明高潜用户以老用户为主,这很合理——等级越高越信任平台,复购意愿越强。
5.2 年龄分布(柱状图)
# 统计各年龄段人数
user_age_count = user_high['age'].value_counts()
# 年龄3.0: 1012人, 年龄4.0: 485人, 年龄-1.0: 169人, 年龄2.0: 136人, 年龄5.0: 57人, 年龄6.0: 23人
用pyecharts画柱状图:
from pyecharts.globals import ThemeType
bar = (
Bar(init_opts=opts.InitOpts(theme='white')) # 白色主题,干净清爽
.add_xaxis(user_age_count.index.tolist()) # x轴:年龄段
.add_yaxis('年龄分布', user_age_count.values.tolist()) # y轴:人数
)
bar.render_notebook()
洞察: 年龄段3和4的用户最多(占近80%),这是平台的消费主力人群。-1是未知年龄,也有169人。
5.3 性别分布(圆环图)
# 统计各性别人数
user_sex_count = user_high['sex'].value_counts()
# 性别0: 984人, 性别2: 751人, 性别1: 147人
# 配对数据
data_pair2 = list(zip(user_sex_count.index.tolist(), user_sex_count.values.tolist()))
用pyecharts画圆环图:
pie2 = (
Pie()
.add("占比", data_pair=data_pair2, radius=['30%', '60%']) # 内半径30%,外半径60%,就是圆环(甜甜圈)效果
.set_global_opts(
tooltip_opts=opts.TooltipOpts(is_show=True, formatter='{b}:{d}%'),
title_opts={'text': '高潜用户性别占比'}
)
)
pie2.render_notebook()
5.4 年龄分布直方图(Plotly版)
import plotly.express as px
# 直方图能更精细地看到年龄的分布情况
fig = px.histogram(
user_high,
x='age', # x轴:年龄
nbins=20, # 把数据分成20个区间
title='用户年龄分布', # 标题
labels={'age': '年龄'}, # 轴标签
height=500
)
fig.show()
5.5 性别分布圆环图(Plotly版)
fig = px.pie(
user_high,
names='sex', # 按性别分组
title='用户性别分布',
labels={'sex': '性别'},
height=500,
hole=0.5 # hole=0.5就是在中间挖个洞,变成甜甜圈图
)
fig.show()
六、总结:用户画像分析的核心思路
整个分析流程可以概括为以下几步:
原始数据 → 数据清洗 → 特征提取 → 用户分群 → 可视化洞察
关键发现
| 维度 | 发现 | 业务建议 |
|---|---|---|
| 用户等级 | 等级4-5占92% | 高潜用户以老用户为主,重点维护老用户关系 |
| 年龄 | 年龄段3-4占80% | 这是消费主力,针对这个年龄段做精准营销 |
| 性别 | 性别0占52%,性别2占40% | 两大性别群体都需要关注,可做差异化推荐 |
| 决策周期 | 平均决策天数较长 | 高潜用户偏理性消费,内容营销比促销更有效 |
分析方法总结
- 分块读取大文件:
pd.read_csv(chunksize=N)+pd.concat() - 数据清洗三件套:
isnull()查空值 +duplicated()查重复 +describe()查异常 - 分组聚合:
groupby()+apply(lambda x: x.max/min())找最值 - 表合并:
pd.merge()按关键字段关联多张表 - 时间差计算:
(time1 - time2).dt.days算天数差 - 可视化:pyecharts画交互式图表,Plotly画快速探索图
更多推荐



所有评论(0)