数据概览
py
# 数据概览
print("\n数据概览:")
print(f"时间范围:{df['time'].min()} 至 {df['time'].max()}")
print(f"用户数:{df['user_id'].nunique()}")
print(f"行为类型分布:\n{df['behavior_type'].value_counts()}")
.nunique()
全称为 "number of unique "(唯一值数量),用于快速计算某列中不同值的个数
典型应用场景:
- 计算独立用户数(UV)
- 统计不同商品/类目的数量
- 分析唯一访问次数等
相关方法对比:
方法 | 描述 | 示例 |
---|---|---|
.nunique() | 返回唯一值数量 | user_id.nunique() → 1000(个独立用户) |
.unique() | 返回唯一值数组 | user_id.unique() → array([1, 2, 3, ...]) |
.value_counts() | 返回各值出现次数 | user_id.value_counts() → 用户1: 50次,用户2: 30次... |
- 计算关键指标
py
# 独立用户数(UV)
uv = df['user_id'].nunique()
# 独立商品数
items_count = df['item_id'].nunique()
# 日均UV
daily_uv = df.groupby('date')['user_id'].nunique()
- 分析用户行为质量
py
# 计算人均行为次数
total_actions = len(df) # 总次数
unique_users = df['user_id'].nunique() # 人数
avg_actions = total_actions / unique_users # 人均
- 结合分组分析
py
# 各行为类型的独立用户数
behavior_uv = df.groupby('behavior_type')['user_id'].nunique()
# 每小时独立用户数
hourly_uv = df.groupby('hour')['user_id'].nunique()
- 漏斗分析
py
funnel = {
'曝光': df[df['behavior_type']=='pv']['user_id'].nunique(),
'加购': df[df['behavior_type']=='cart']['user_id'].nunique(),
'购买': df[df['behavior_type']=='buy']['user_id'].nunique()
}
- 用户留存分析
py
# 计算次日留存
day1_users = df[df['date']=='2023-01-01']['user_id'].unique()
day2_users = df[df['date']=='2023-01-02']['user_id'].unique()
retention = len(set(day1_users) & set(day2_users)) / len(day1_users)
Q:为什么 nunique()
结果比预期少?
A:可能原因:
- 数据中存在空值(
NaN
不会被计数,除非用dropna=False
) - 用户ID存在重复或错误(如测试账号)
py
# 包含空值的计数
uv_with_nan = df['user_id'].nunique(dropna=False)
# 检查数据质量
print(df['user_id'].isna().sum()) # 空值数量
print(df['user_id'].value_counts().head()) # 高频ID
数据清洗
py
# 数据清洗
df.dropna(inplace=True) # 处理缺失数据
df.drop_duplicates(subset=['user_id','item_id','time'], keep='first', inplace=True) # 去重
df['datetime'] = pd.to_datetime(df['time']) # 时间格式转换
df['date'] = pd.to_datetime(df['time']).dt.date # 从时间戳提取日期
pd.to_datetime()
是 Pandas 中将输入转换为标准时间格式的函数
参数 | 示例 | 用途 | 产品分析场景 |
---|---|---|---|
format | format='%m/%d/%Y' | 指定输入格式 | 处理美国格式日期 |
unit | unit='ms' | 时间戳单位 | 处理JS生成的毫秒时间戳 |
errors | errors='coerce' | 错误处理 | 自动过滤无效日期 |
dayfirst | dayfirst=True | 日在前格式 | 处理欧洲日期如15/07/2024 |
- 原始数据清洗
python
# 电商订单时间处理(多种原始格式)
df['order_time'] = pd.to_datetime(df['raw_time'], format='%Y/%m/%d %H:%M:%S')
- 行为分析时间提取
python
# 从时间戳提取关键维度
df['date'] = pd.to_datetime(df['timestamp']).dt.date # 日期
df['hour'] = pd.to_datetime(df['timestamp']).dt.hour # 小时
- 处理混合格式
python
# 自动推断多种格式(如"2024-07-15"和"15/07/24")
df['time'] = pd.to_datetime(df['raw_time'], infer_datetime_format=True)
- 电商大促分析
python
# 计算用户响应时间(从浏览到购买)
df['view_time'] = pd.to_datetime(df['view_timestamp'])
df['buy_time'] = pd.to_datetime(df['buy_timestamp'])
df['response_time'] = (df['buy_time'] - df['view_time']).dt.total_seconds()
- 用户活跃时段分析
python
# 原始数据:'time'列为字符串或时间戳
df['datetime'] = pd.to_datetime(df['time'])
df['hour'] = df['datetime'].dt.hour
# 24小时活跃分布
hourly_uv = df.groupby('hour')['user_id'].nunique()
hourly_uv.plot(kind='bar', title='用户活跃时段分布')
- 关键业务时间字段校验
python
# 检查是否有未来时间或极旧时间
dates = pd.to_datetime(df['order_time'])
invalid_dates = dates[(dates > pd.Timestamp.now()) | (dates < pd.Timestamp('2000-01-01'))]
Q:报错OutOfBoundsDatetime
A:可能原因:时间超出Timestamp范围
python
pd.to_datetime(df['time'], errors='coerce') # 将超界值转为NaT
定义行为类型编码规则
python
# 定义行为类型编码规则
behavior_map = {
1: '曝光', 2: '加购', 3: '收藏', 4: '购买',
'1': '曝光', '2': '加购', '3': '收藏', '4': '购买',
'pv': '曝光', 'cart': '加购', 'fav': '收藏', 'buy': '购买'
}
# 统一转换(兼容数字/英文编码)
df['behavior'] = df['behavior_type'].map(behavior_map)
.map()
是一个Series 对象的方法 ,用于根据给定的映射关系替换 Series 中的每个值。
例如:将原始的行为类型编码(数字或英文)统一转换为中文描述。
- 映射转换
将 Series 中的每个元素按照指定的映射关系进行转换
python
# 示例:将1→'曝光',2→'加购'...
df['behavior'] = df['behavior_type'].map(behavior_map)
- 使用函数映射
python
# 将购买金额分段
df['price_level'] = df['price'].map(lambda x: '高价' if x > 100 else '低价')
- 通过另一个Series映射
python
# 从其他表获取映射关系
id_to_name = pd.Series(['曝光','加购'], index=[1,2])
df['behavior'] = df['behavior_type'].map(id_to_name)
- 处理未知值
python
# 未知编码转为'其他'
df['behavior'] = df['behavior_type'].map(behavior_map).fillna('其他')
Q:映射后出现 NaN
A:原因:原始值不在映射字典中
python
# 方法1:填充默认值
df['behavior'] = df['behavior_type'].map(behavior_map).fillna('未知行为')
# 方法2:检查缺失值
missing = df[df['behavior'].isna()]['behavior_type'].unique()
print("未映射的值:", missing)
Q:映射速度慢
python
# 对大数据集更高效的方法
df['behavior'] = df['behavior_type'].replace(behavior_map)
建议:
- 映射表统一管理
将behavior_map
保存在单独配置文件中,方便多份代码复用:
python
# config.py
BEHAVIOR_MAP = {
1: '曝光',
2: '加购',
...
}
# analysis.py
from config import BEHAVIOR_MAP
df['behavior'] = df['behavior_type'].map(BEHAVIOR_MAP)
- 验证映射完整性
python
# 检查原始值是否全部被覆盖
unmapped = set(df['behavior_type'].unique()) - set(behavior_map.keys())
assert len(unmapped) == 0, f"未映射的值:{unmapped}"
基础指标计算
python
# 基础指标计算
daily_data = df.groupby('date').agg(
uv=('user_id', 'nunique'), # 对user_id去重计数 → UV (对user_id进行nunique)
pv=('user_id', 'count') # 对user_id直接计数 → PV (对user_id进行count)
)
.agg()
是 aggregate (聚合)的缩写,用于对分组后的数据执行多种聚合计算。
.agg()
可以对数据:
- 同时计算多个指标(如UV、PV)
- 对不同列应用不同计算(如对用户ID去重计数,对访问次数直接计数)
- 自定义聚合逻辑(支持内置函数或自定义函数)
- 多列不同计算
python
df.groupby('date').agg(
uv=('user_id', 'nunique'),
avg_price=('price', 'mean'), # 计算均价
max_time=('timestamp', 'max') # 最晚访问时间
)
- 同列多指标
python
df.groupby('category').agg(
price_stats=('price', ['min', 'max', 'median']),
user_variety=('user_id', 'nunique')
)
- 自定义函数
python
# 计算购买转化率(购买用户/活跃用户)
def conversion_rate(group):
return (group['behavior'] == '购买').sum() / len(group)
df.groupby('date').apply(conversion_rate)
- 电商场景核心指标
python
daily_kpis = df.groupby('date').agg(
uv=('user_id', 'nunique'),
pv=('pageview_id', 'count'),
gmv=('order_amount', 'sum'),
conversion=('is_purchase', 'mean') # 转化率
).reset_index()
- 用户分群分析
python
user_segments = df.groupby('user_id').agg(
first_date=('date', 'min'),
last_date=('date', 'max'),
purchase_count=('order_id', 'nunique'),
avg_spend=('amount', 'mean')
)
Q:列名冲突
A:原因:多个聚合使用相同列名
python
df.groupby('date')['user_id'].agg(
UV='nunique',
PV='count'
)
Q:空值影响
python
df.groupby('date').agg(
uv=('user_id', lambda x: x.notna().nunique())
)
用户转化漏斗分析
python
# 用户转化漏斗分析
fig = px.funnel(funnel_data.reset_index(), # 数据(需包含行为阶段和用户数)
x='user_id', # 各阶段的用户量(决定漏斗宽度)
y='behavior', # 行为阶段(决定漏斗高度方向)
title='用户行为漏斗分析')
fig.write_html("C:\Temp\funnel.html") # 保存HTML文件
参数 | 作用 | 您的数据示例 |
---|---|---|
x | 各阶段的量级 | 曝光:8170用户 → 购买:3869用户 |
y | 行为阶段顺序 | 曝光 → 加购 → 收藏 → 购买 |
funnel (漏斗)是一种专门用于展示多阶段转化过程 的图表类型。.funnel()
是 Plotly Express 库中用于创建漏斗图的函数。
- 多维度对比
python
# 对比不同用户群的漏斗
px.funnel(df, x='user_id', y='behavior', color='user_type')
Q:漏斗阶段倒置
A:原因:行为阶段未正确排序
python
funnel_data = funnel_data.sort_values('user_id', ascending=False)
Q:数据不匹配
A:原因:确保x为数值列,y为分类列
python
print(funnel_data.dtypes)
# 应显示: user_id:int, behavior:object
建议:
- 用渐变色表示转化方向
python
import plotly.express as px
# 基础渐变色(按阶段顺序):用户量大的阶段颜色深,量小的颜色浅
fig = px.funnel(
funnel_data.reset_index(),
x='user_id',
y='behavior',
color='user_id', # 关键:用用户数作为颜色依据
color_continuous_scale='Blues', # 使用蓝色渐变
title='用户行为漏斗(按量级渐变)'
)
fig.show()
# 自定义阶段颜色映射:每个阶段固定颜色,绿色→红色表示转化路径;适合强调关键流失点
stage_colors = { # 定义颜色梯度(从绿到红表示转化率下降)
'曝光': '#2ECC71', # 绿色
'加购': '#F1C40F', # 黄色
'收藏': '#E67E22', # 橙色
'购买': '#E74C3C' # 红色
}
fig = px.funnel(
funnel_data.reset_index(),
x='user_id',
y='behavior',
color='behavior', # 按行为类型着色
color_discrete_map=stage_colors # 自定义颜色映射
)
fig.update_layout(showlegend=True)
# 动态计算颜色(基于转换率):红色(低转化率)→ 绿色(高转化率);直观显示各阶段效率
funnel_data['conversion_rate'] = funnel_data['user_id'] / funnel_data['user_id'].iloc[0] # 计算各阶段相对于曝光的转化率
fig = px.funnel(
funnel_data.reset_index(),
x='user_id',
y='behavior',
color='conversion_rate', # 用转化率作为颜色依据
color_continuous_scale=['red', 'yellow', 'green'], # 自定义渐变
range_color=[0, 1], # 颜色范围0%~100%
title='用户行为漏斗(按转化率渐变)'
)
fig.update_coloraxes(colorbar_title='转化率')
- 3D漏斗效果
python
fig.update_traces(
marker=dict(line=dict(width=1, color='gray')),
opacity=0.8 # 增加透明度增强层次感
)
- 交互增强
python
fig.update_layout(hovermode="x unified") # 悬停显示详细信息
转化率分析
python
# 转化率分析
if '曝光' in funnel_data.index and '购买' in funnel_data.index: # 检查数据中是否存在"曝光"和"购买"两个关键节点
conversion_rate = funnel_data['购买'] / funnel_data['曝光'] # 转化率=购买人数 ÷ 曝光人数
print(f"\n曝光→购买转化率:{conversion_rate:.2%}")
完整代码
py
import pandas as pd
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import plotly.express as px
# 显示设置
pd.options.display.max_columns=999 # 随便设置一个大的数字,可以让隐藏的信息都显示出来
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 微软雅黑
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示为方块的问题
# 数据示例
df = pd.read_csv('C:\Temp\淘宝用户行为.csv')
print(df.head()) # 查看前5行
# 数据概览
print("\n数据概览:")
print(f"时间范围:{df['time'].min()} 至 {df['time'].max()}")
print(f"用户数:{df['user_id'].nunique()}")
print(f"行为类型分布:\n{df['behavior_type'].value_counts()}")
# 数据清洗
df.dropna(inplace=True) # 处理缺失数据
df.drop_duplicates(subset=['user_id','item_id','time'], keep='first', inplace=True) # 去重
df['datetime'] = pd.to_datetime(df['time'])
df['date'] = pd.to_datetime(df['time']).dt.date # 时间格式转换
# 定义行为类型编码规则
behavior_map = {
1: '曝光', 2: '加购', 3: '收藏', 4: '购买',
'1': '曝光', '2': '加购', '3': '收藏', '4': '购买',
'pv': '曝光', 'cart': '加购', 'fav': '收藏', 'buy': '购买'
}
# 统一转换(兼容数字/英文编码)
df['behavior'] = df['behavior_type'].map(behavior_map)
# 基础指标计算
daily_data = df.groupby('date').agg(
uv=('user_id', 'nunique'), # 去重用户数
pv=('user_id', 'count') # 总访问量
)
# 行为分布统计(两种方式对比)
print("\n行为记录数(总次数):")
print(df['behavior'].value_counts())
print("\n独立用户数(去重):")
funnel_data = df.groupby('behavior')['user_id'].nunique().sort_values(ascending=False) # 计算各行为用户数
print(funnel_data)
# 可视化
daily_data.plot(title='日活跃用户趋势', figsize=(10,5)) # 绘制UV/PV趋势图
plt.xlabel('日期')
plt.ylabel('数量')
plt.savefig('C:\Temp\uv_pv.png') # 保存图片
# 用户转化漏斗分析
fig = px.funnel(funnel_data.reset_index(),
x='user_id',
y='behavior',
title='用户行为漏斗分析') # 绘制漏斗图
fig.write_html("C:\Temp\funnel.html") # 保存HTML文件
# 用户分群
user_rfm = df[df['behavior']=='购买'].groupby('user_id').agg( # 计算每个用户的最近购买日、购买频次
last_date=('date', 'max'),
frequency=('item_id', 'count')
)
user_rfm['high_value'] = user_rfm['frequency'] > user_rfm['frequency'].quantile(0.8) # 标记高价值用户(前20%)
user_rfm.to_csv('C:\Temp\用户价值分层.csv', encoding='utf-8-sig') # 保存为CSV文件
# 用户活跃时段分析
df['hour'] = pd.to_datetime(df['time']).dt.hour # 提取小时
hourly_activity = df.groupby('hour')['user_id'].nunique() # 按小时统计独立用户数
hourly_activity.plot(kind='bar', title='用户活跃时段分布')
plt.xlabel('小时')
plt.ylabel('独立用户数')
plt.savefig('C:\Temp\用户活跃时段分布.png') # 保存图片
# 转化率分析
if '曝光' in funnel_data.index and '购买' in funnel_data.index:
conversion_rate = funnel_data['购买'] / funnel_data['曝光']
print(f"\n曝光→购买转化率:{conversion_rate:.2%}")
数据来源:淘宝用户行为_数据集-阿里云天池