# ====================== 0. 环境配置与库导入 ======================
import numpy as np
import pandas as pd
import warnings
from datetime import datetime
import matplotlib.pyplot as plt
import sklearn
%matplotlib inline
# 忽略警告信息
warnings.filterwarnings('ignore')
# 解决中文显示问题
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
# ====================== 1. 数据加载与预处理 ======================
# 注意:需将此处路径替换为实际数据路径
df = pd.read_csv('taobao_persona.csv') # 读取原始数据
# 1.1 数据抽样(原数据2300万+条,抽样30%降低计算量)
df = df.sample(frac=0.3, random_state=None).reset_index(drop=True) # frac=抽样比例,random_state=随机种子固定结果
print(f"抽样后数据量:{df.shape}") # 输出:(约700万, 6)
# 1.2 删除缺失值过多的地理信息列
df.drop('user_geohash', axis=1, inplace=True) # axis=1表示列,inplace=True直接修改原数据
# 1.3 拆分时间字段(原time格式为'2014-11-21 22',拆分为日期和小时)
df['date'] = pd.to_datetime(df['time'].str[:10]) # 提取前10位为日期,转换为datetime类型
df['hour'] = df['time'].str[11:].astype(int) # 提取小时部分,转换为整数
# 1.4 划分时段标签(凌晨、上午、中午、下午、晚上)
df['hour_group'] = pd.cut(
df['hour'],
bins=[-1, 5, 10, 13, 18, 24], # 区间划分(左闭右开),-1是为了包含0点
labels=['凌晨', '上午', '中午', '下午', '晚上'] # 时段标签
)
# ====================== 2. 初始化用户标签表 ======================
# 提取唯一用户ID
users = df['user_id'].unique()
labels = pd.DataFrame({'user_id': users}) # 创建空白标签表
# ====================== 3. 构建用户行为标签 ======================
# ---------------------- 3.1 浏览行为标签 ----------------------
def build_browse_labels(df, labels):
"""生成浏览相关标签"""
# 筛选浏览行为(behavior_type=1)
browse = df[df['behavior_type'] == 1]
# 3.1.1 浏览活跃时间段
# 按用户和时段分组,统计浏览次数
browse_time = browse.groupby(['user_id', 'hour_group'])['item_id'].count().reset_index()
browse_time.columns = ['user_id', 'hour_group', 'browse_count']
# 找到每个用户浏览次数最多的时段
max_browse_count = browse_time.groupby('user_id')['browse_count'].max().reset_index()
max_browse_count.columns = ['user_id', 'max_browse_count']
# 合并最大值,筛选出活跃时段
browse_active = pd.merge(browse_time, max_browse_count, on='user_id')
browse_active = browse_active[browse_active['browse_count'] == browse_active['max_browse_count']]
# 处理并列情况(多个时段次数相同),用逗号连接
browse_active = browse_active.groupby('user_id')['hour_group'].agg(lambda x: ','.join(x)).reset_index()
browse_active.columns = ['user_id', 'browse_active_time']
# 合并到标签表
labels = pd.merge(labels, browse_active, on='user_id', how='left')
return labels
# ---------------------- 3.2 购买行为标签 ----------------------
def build_buy_labels(df, labels):
"""生成购买相关标签"""
# 筛选购买行为(behavior_type=4)
buy = df[df['behavior_type'] == 4]
# 3.2.1 购买活跃时间段
buy_time = buy.groupby(['user_id', 'hour_group'])['item_id'].count().reset_index()
buy_time.columns = ['user_id', 'hour_group', 'buy_count']
max_buy_count = buy_time.groupby('user_id')['buy_count'].max().reset_index()
max_buy_count.columns = ['user_id', 'max_buy_count']
buy_active = pd.merge(buy_time, max_buy_count, on='user_id')
buy_active = buy_active[buy_active['buy_count'] == buy_active['max_buy_count']]
buy_active = buy_active.groupby('user_id')['hour_group'].agg(lambda x: ','.join(x)).reset_index()
buy_active.columns = ['user_id', 'buy_active_time']
labels = pd.merge(labels, buy_active, on='user_id', how='left')
# 3.2.2 近30天购买次数
buy_counts_30 = buy.groupby('user_id')['item_id'].count().reset_index()
buy_counts_30.columns = ['user_id', 'counts_30_buy']
labels = pd.merge(labels, buy_counts_30, on='user_id', how='left')
return labels
# ---------------------- 3.3 商品类别相关标签 ----------------------
def build_category_labels(df, labels, behavior_type, label_name):
"""通用商品类别标签生成函数(可复用至浏览/收藏/加购/购买)"""
df_behavior = df[df['behavior_type'] == behavior_type]
cate_counts = df_behavior.groupby(['user_id', 'item_category'])['item_id'].count().reset_index()
cate_counts.columns = ['user_id', 'item_category', f'{label_name}_count']
max_cate_count = cate_counts.groupby('user_id')[f'{label_name}_count'].max().reset_index()
max_cate_count.columns = ['user_id', f'max_{label_name}_count']
cate_most = pd.merge(cate_counts, max_cate_count, on='user_id')
cate_most = cate_most[cate_most[f'{label_name}_count'] == cate_most[f'max_{label_name}_count']]
# 将 item_category 转换为字符串类型再进行拼接
cate_most = cate_most.groupby('user_id')['item_category'].agg(lambda x: ','.join(map(str, x))).reset_index()
cate_most.columns = ['user_id', f'cate_most_{label_name}']
labels = pd.merge(labels, cate_most, on='user_id', how='left')
return labels
# 调用构建浏览行为标签函数
labels = build_browse_labels(df, labels)
# 调用构建购买行为标签函数
labels = build_buy_labels(df, labels)
print("检查 counts_30_buy 列是否存在:", 'counts_30_buy' in labels.columns) # 添加调试信息
# 调用通用函数生成各类别标签
labels = build_category_labels(df, labels, behavior_type=1, label_name='browse') # 浏览最多类别
labels = build_category_labels(df, labels, behavior_type=2, label_name='collect') # 收藏最多类别
labels = build_category_labels(df, labels, behavior_type=3, label_name='cart') # 加购最多类别
labels = build_category_labels(df, labels, behavior_type=4, label_name='buy') # 购买最多类别
# ====================== 4. 构建时间相关行为标签 ======================
# 4.1 近30天活跃天数(按用户统计不同日期的数量)
active_days_30 = df.groupby('user_id')['date'].nunique().reset_index()
active_days_30.columns = ['user_id', 'counts_30_active']
labels = pd.merge(labels, active_days_30, on='user_id', how='left')
# 4.2 最后一次浏览距今天数(假设当前日期为2014-12-19,文档中数据截止到2014-12-18)
last_browse_day = df[df['behavior_type']==1].groupby('user_id')['date'].max().reset_index()
last_browse_day['days_browse'] = (datetime(2014, 12, 19) - last_browse_day['date']).dt.days
labels = pd.merge(labels, last_browse_day[['user_id', 'days_browse']], on='user_id', how='left')
# ====================== 5. 构建用户属性标签 ======================
# 5.1 是否复购用户(购买次数>1为复购)
if 'counts_30_buy' in labels.columns:
labels['buy_again'] = labels['counts_30_buy'].apply(lambda x:
'是' if x > 1 else
'否' if x == 1 else
'未购买')
else:
print("counts_30_buy 列不存在,无法生成 buy_again 标签")
# 5.2 访问活跃度(以30天活跃天数>20天为高活跃)
labels['user_active_level'] = '高'
labels.loc[labels['counts_30_active'] <= 20, 'user_active_level'] = '低'
# ====================== 6. 数据可视化(答辩展示重点) ======================
# 6.1 活跃时间段分布对比
plt.figure(figsize=(16, 6))
# 填充 NaN 值
labels['browse_active_time'] = labels['browse_active_time'].fillna('无数据')
labels['buy_active_time'] = labels['buy_active_time'].fillna('无数据')
# 浏览活跃时段
plt.subplot(1, 2, 1)
labels['browse_active_time'].value_counts().plot(kind='bar', title='用户浏览活跃时间段分布')
plt.xlabel('活跃时段')
plt.ylabel('用户数')
# 购买活跃时段
plt.subplot(1, 2, 2)
labels['buy_active_time'].value_counts().plot(kind='bar', title='用户购买活跃时间段分布')
plt.xlabel('活跃时段')
plt.ylabel('用户数')
plt.tight_layout()
plt.show()
# 6.2 复购用户比例
plt.figure(figsize=(8, 6))
labels['buy_again'].value_counts().plot(kind='pie', autopct='%1.1f%%', title='复购用户比例')
plt.ylabel('') # 去除y轴标签
plt.show()
# 6.3 购买活跃度分布
plt.figure(figsize=(10, 4))
# 填充 NaN 值
if 'counts_30_buy' in labels.columns:
labels['counts_30_buy'] = labels['counts_30_buy'].fillna(0)
labels['counts_30_buy'].hist(bins=20, edgecolor='black')
plt.title('近30天购买次数分布')
plt.xlabel('购买次数')
plt.ylabel('用户数')
plt.show()
else:
print("counts_30_buy 列不存在,无法绘制购买活跃度分布直方图")
# ====================== 7. 结果输出 ======================
# 保存完整标签表
labels.to_csv('淘宝用户画像标签表.csv', index=False)
print("用户画像构建完成,结果已保存至:淘宝用户画像标签表.csv")
# 打印前5条结果示例
print("\n标签表示例:")
print(labels.head())
请根据代码给出整体流程图