ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

用户画像标签体系:从行为日志到可计算人群的完整链路

用户画像标签体系:从行为日志到可计算人群的完整链路 简介用户画像是互联网精细化运营与精准营销的关键基础。这份PDF资料系统讲解用户画像建模方法适合数据分析师、数据产品经理及大数据开发人员阅读。内容从画像基础概念出发依次介绍统计类、规则类、机器学习挖掘类三类标签的构建逻辑并梳理了Spark、Hive、HBase、Redis、Elasticsearch等常见数据架构组件以及ETL分层加工、标签存储和八大覆盖模块。全书还覆盖用户画像从目标解读、需求调研到模型验收上线的完整开发流程能够帮助读者建立从数据仓库到画像应用的整体认知。资源为1个PDF文件大小795KB已有1015人学习。对于希望掌握用户标签体系建设、个性化推荐与精准营销落地方法的读者而言是一份结构清晰、便于快速入门的参考资料。1. 用户画像是把离散行为压缩成可计算的结构接触过用户画像项目的人大多有过这种经历数据仓库里积累了上亿条行为日志却不知道用户到底想要什么。用户画像在这类场景下的意义不是把「男、25岁、北京」这类静态属性堆成一张宽表而是把离散的浏览、点击、下单、投诉事件压缩成一组可计算、可解释、可迭代的结构化标签。换句话说画像做的是信息降维而不是数据搬运。这套「用户画像基础」想解决的问题很直接当业务方问「我们的核心用户是谁、该怎么运营」时你能否用一套确定性的流程从原始日志推到标签、从标签推到人群、从人群推到运营策略。本文顺着「标签体系 → 权重计算 → 工程落地 → 效果评估」这条链路展开适合数据工程师、数据分析师和做用户增长的同学参考。里面涉及的参数和方法都是我实际项目中验证过的方案你可以在自己的数据上直接改参数复现。2. 用户画像的标签体系从原始数据到可解释的标签2.1 画像标签的四层结构用户画像的底层不是算法而是标签的分层设计。常见做法是把标签分成四层事实标签、规则标签、模型标签、预测标签。事实标签来自用户主动提交或系统记录的数据比如注册时填写的性别、设备型号、首次下单时间。这类标签准确率接近100%但覆盖面有限——不是每个用户都愿意填生日也不是每个游客都会登录。规则标签是在事实标签和行为数据之上用明确的业务规则计算出来的。比如「高活跃用户 最近7天登录次数 ≥ 5 且 日均使用时长 ≥ 30 分钟」。这类标签的好处是口径完全透明业务方可以参与讨论和调整。模型标签则依赖机器学习算法比如用聚类把用户分成「价格敏感型」「品质优先型」「冲动消费型」或者用协同过滤算出用户的潜在品类偏好。预测标签是第四层一般是模型输出的概率值比如「未来30天流失概率 0.73」。2.1.1 标签的唯一标识与版本管理标签要能落地必须在设计阶段就解决两个问题命名唯一性、口径版本化。命名唯一性保证「高活跃」在A部门是7天登录5次、在B部门是30天登录20次的情况下不会产生歧义。版本化保证标签的计算逻辑可以回溯——当算法或规则调整后历史数据怎么对比。我一般用「标签域_标签名_版本号」的格式比如loyalty_high_active_v3。2.2 标签计算的第一个可执行示例从原始行为日志到事实标签是画像链路里最基础也最容易出错的一步。假设你有一张行为日志表user_behavior_log字段包括user_id、event_type、item_id、category_id、ts。要计算用户的品类偏好标签可以用 SQL 直接聚合-- 计算每个用户近30天在各品类的浏览和购买权重 WITH category_stats AS ( SELECT user_id, category_id, SUM(CASE WHEN event_type buy THEN 5 WHEN event_type cart THEN 3 WHEN event_type click THEN 1 END) AS category_score, COUNT(DISTINCT item_id) AS item_cnt, MAX(ts) AS last_ts FROM user_behavior_log WHERE ts date_sub(current_date, 30) GROUP BY user_id, category_id ), ranked AS ( SELECT user_id, category_id, category_score, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY category_score DESC) AS rn FROM category_stats ) SELECT user_id, category_id, category_score FROM ranked WHERE rn 3这段 SQL 的核心逻辑是行为加权购买行为权重为5、加购为3、点击为1按用户聚合出每个品类的总得分再取每个用户得分最高的3个品类作为偏好标签。权重系数5/3/1不是拍脑袋定的它表示了一次购买行为对应约五次点击的价值。你可以根据自己业务的转化率调整如果你们的点击到购买转化率是1%那么一次购买权重要拉到60以上才合理。2.3 事实标签的清洗门槛标签计算前必须处理脏数据。常见问题包括user_id为空、ts超出合理时间范围、category_id不在商品类目表里。这些脏数据如果不过滤会直接污染后续的模型标签训练。建议在标签计算的公共层里加白名单过滤而不是每个标签任务自己写一次。另一个容易踩的坑是时区日志里的ts如果是 UTC 时间而业务口径用的是北京时间聚合时会把每天的边界切歪。统一在 ETL 入口转成东八区时间再落表能避免后面所有标签的时间错位问题。3. 用户画像的权重计算与模型打分从统计到机器学习3.1 时间衰减因子让旧行为自动降权行为数据天然有时效性——用户三个月前买的婴儿奶粉不代表他现在还需要。常见做法是在标签权重计算中引入时间衰减因子用半衰期函数控制历史行为的衰减速度。我常用的是指数衰减import pandas as pd import numpy as np def time_decay_weight(days_since: int, half_life: float 7.0) - float: 计算时间衰减权重。 days_since: 行为发生距今天数 half_life: 半衰期天数默认7天即7天后权重减半 return 0.5 ** (days_since / half_life) # 示例某用户近30天的行为明细 behavior_data [ {event: click, days_since: 1, base_weight: 1}, {event: buy, days_since: 10, base_weight: 5}, {event: buy, days_since: 25, base_weight: 5}, ] total_score 0.0 for b in behavior_data: decay time_decay_weight(b[days_since], half_life15) weighted b[base_weight] * decay total_score weighted print(f{b[event]}: base{b[base_weight]}, decay{decay:.3f}, weighted{weighted:.3f}) print(ftotal score {total_score:.3f})代码里的half_life是核心参数。半衰期越短旧行为被遗忘得越快。比如做「近期购买意向」标签半衰期设3天做「长期品类偏好」半衰期设30天。日志显示半衰期设7天时30天前的购买行为只剩约4%的权重基本可以忽略设15天时还能保留约25%的贡献。具体数值取决于业务节奏——生鲜电商和房产品类的决策周期完全不同这个参数要按品类单独调。3.2 RFM 模型在画像标签里的落地RFMRecency, Frequency, Monetary是用户分群最经典的统计模型在画像工程里通常作为「用户价值分层」标签的计算基础。它的三个维度分别对应最近一次消费时间、消费频率、消费金额。问题是原始 RFM 是连续值不能直接当标签用。常见做法是先做分位数切分再组合成群体import pandas as pd # 假设 df 包含 user_id, recency_days, frequency_cnt, monetary_amt def rfm_segment(df: pd.DataFrame) - pd.DataFrame: 用分位数将 RFM 三指标转为高/中/低三档再组合成用户价值标签。 df df.copy() # 三分位切分recency 越小越好所以排序方向相反 df[r_level] pd.qcut(df[recency_days], 3, labels[high, mid, low]) df[f_level] pd.qcut(df[frequency_cnt], 3, labels[low, mid, high]) df[m_level] pd.qcut(df[monetary_amt], 3, labels[low, mid, high]) # 组合规则重要价值用户 R高 F高 M高 def seg(row): if row[r_level] high and row[f_level] high and row[m_level] high: return 重要价值用户 if row[f_level] high and row[m_level] high: return 重要发展用户 if row[r_level] high and row[m_level] high: return 重要保持用户 if row[r_level] high and row[f_level] high: return 重要挽留用户 return 一般用户 df[user_segment] df.apply(seg, axis1) return dfpd.qcut按分位数切分而不是等距切分好处是数据偏态严重时比如头部大客户消费金额极高人群分布依然均匀。切分档位可以是2档或4档3档在业务沟通时最直观——高/中/低三档非黑即白之外留了中间地带。实际使用时要注意RFM 的分位数边界需要定期重算因为用户群体的消费结构会随季节变化。建议每个月更新一次分段阈值而不是用固定数值。3.3 贝叶斯平滑解决稀疏行为的问题RFM 依赖用户有足够的历史消费行为但大量新用户只有一两次点击。这时候直接算频率和金额得到的结果极不稳定——今天点了一下就是「高活跃」明天没点就变成「低活跃」。对这类稀疏行为我会用贝叶斯平滑Beta-Binomial 模型做修正本质是把个体观测值向群体先验靠拢def bayesian_smooth(pos: int, total: int, alpha: float 1.0, beta: float 1.0) - float: 用 Beta(alpha, beta) 先验平滑点击率。 pos: 正向行为数如点击 total: 总行为数如曝光 返回平滑后的概率估计 if total 0: return alpha / (alpha beta) # 后验 Beta(posalpha, total-posbeta) 的均值 return (pos alpha) / (total alpha beta) # 对比两个用户的原始点击率 vs 平滑后点击率 users [ {name: 新用户A, clicks: 1, exposures: 2}, {name: 老用户B, clicks: 50, exposures: 100}, ] for u in users: raw u[clicks] / u[exposures] smoothed bayesian_smooth(u[clicks], u[exposures], alpha10, beta90) print(f{u[name]}: raw{raw:.2f}, smoothed{smoothed:.2f}) # 输出新用户A raw0.50, smoothed0.10 # 老用户B raw0.50, smoothed0.45注意观察输出两个用户原始点击率都是0.5但平滑后差异明显。新用户样本量太小结果被先验全局平均点击率10%强力拉低老用户样本充足平滑后仍接近原始值。alpha10, beta90的含义是「我假设全局点击率在10%左右且这个先验相当于100次曝光的数据量」。先验强度越大小样本用户的结果越向群体均值靠拢。这个参数在画像里特别重要因为模型标签的稳定性直接决定后续策略是否可信。3.4 聚类模型标签的稳定性验证当你决定用 KMeans 做用户分群时必须意识到聚类结果对随机种子和特征量纲敏感。同一批用户换一个随机种子分群结果可能完全不同。我会在特征工程阶段做两件事一是标准化所有特征用 StandardScaler 而不是 MinMaxScaler因为 KMeans 假设特征方差在不同维度上有不同重要性二是用 Silhouette Score 做 K 值选择而不是凭经验定 K。from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler from sklearn.metrics import silhouette_score import numpy as np # 假设 features 是用户特征矩阵shape (n_users, n_features) scaler StandardScaler() X_scaled scaler.fit_transform(features) # 搜索 K 值范围从 3 到 8 for k in range(3, 9): km KMeans(n_clustersk, random_state42, n_init10) labels km.fit_predict(X_scaled) score silhouette_score(X_scaled, labels) print(fK{k}, silhouette{score:.4f})n_init10表示 KMeans 会从10个不同的初始质心开始取最优结果降低随机性。Silhouette Score 的范围是 -1 到 1大于0.15 就可以接受0.25以上算分群质量较好。如果所有 K 值的得分都低于0.1问题大概率不在 K 的选择而是特征本身没有区分度——这时候先回头改特征不要硬调 K。4. 用户画像的工程落地ID-Mapping、存储选型与实时更新4.1 ID-Mapping 是画像系统的地基画像的数据源来自多个端未登录用户的浏览器 cookie、登录后的 user_id、App 的设备 ID如 IDFA 或 OAID、手机号、微信 openid。同一个用户在五个端有五个 ID不做打通的话画像就是五张碎片化的表。主流的实现方式是构建 ID 图谱用图数据结构维护所有 ID 之间的关联边通过连通分量算法把同一个人的多个 ID 归并到一个统一的profile_id下。# 简化版 ID-Mapping用并查集做连通分量合并 class UnionFind: def __init__(self): self.parent {} def find(self, x): if x not in self.parent: self.parent[x] x while self.parent[x] ! x: self.parent[x] self.parent[self.parent[x]] x self.parent[x] return x def union(self, x, y): rx, ry self.find(x), self.find(y) if rx ! ry: self.parent[rx] ry # 示例同一个用户的 cookie、user_id、phone 关联 uf UnionFind() uf.union(cookie_abc123, user_8848) uf.union(user_8848, phone_13800001111) uf.union(cookie_xyz789, phone_13800001111) # 查询cookie_abc123 和 cookie_xyz789 是否为同一用户 print(uf.find(cookie_abc123) uf.find(cookie_xyz789)) # True并查集是 ID-Mapping 最常用的算法原因是大规模图连通分量计算可以做到近似 O(n) 复杂度。实际生产环境里关联边的权重不是等价的——手机号与 user_id 的关联可信度很高而 cookie 与 user_id 的关联可能因为多设备登录产生噪声需要结合设备指纹、登录状态、时间窗口做加权。4.2 画像存储选型对比标签计算完成后要考虑存储和查询的匹配。以下是三类常见存储引擎在画像场景下的对比存储方案适用场景优势代价HBase大规模标签的 KV 查询单行随机读写快水平扩展强复杂条件过滤弱ClickHouse标签宽表分析与人群圈选列式存储亿级用户聚合秒级返回高频单点更新不擅长Redis实时画像如风控/推荐毫秒级延迟内存成本高不适合全量Elasticsearch多维组合查询与筛选全文检索和聚合能力强数据量大时索引膨胀明显我的经验是全量离线画像数亿用户、几百个标签放 ClickHouse按profile_id分片标签做成稀疏宽表。在线实时查询走 Redis只把高频访问的标签子集放内存。两者之间用消息队列同步更新事件。如果用 HBaserowkey 设计要按profile_id做哈希散列避免热点用户集中在同一台 Region Server。4.3 批流一体的画像更新机制离线画像每天凌晨用 Spark 全量计算一次T1 更新到标签库。但「用户刚下了一单画像里还是三周前的偏好」这种滞后在推荐、风控场景是致命的。标准做法是拆两层离线批计算算全量标签实时流计算只更新增量标签。-- 离线批计算每天全量重算用户活跃等级 INSERT OVERWRITE TABLE dwd_user_profile_daily SELECT profile_id, CASE WHEN cnt_7d 10 THEN 高活跃 WHEN cnt_7d 3 THEN 中活跃 ELSE 低活跃 END AS active_level, ${bizdate} AS dt FROM ( SELECT profile_id, COUNT(*) AS cnt_7d FROM dwd_user_behavior WHERE dt date_sub(${bizdate}, 7) GROUP BY profile_id );实时侧用 Flink 消费用户行为 Kafka 消息维护一个 Redis hashkey 为profile_idfield 为recent_30d_click_cnt。每次行为事件到达时执行HINCRBY。查询实时标签时先取实时计数再与离线标签合并——比如「实时高活跃」的规则是离线活跃等级为「中」且实时计数超过阈值。这种分层计算比完全推翻重建更节省资源也更容易调优。5. 用户画像的评估指标与冷启动技巧5.1 画像质量的三个核心指标画像做完不是终点要回答「这个画像到底准不准」。我一般在项目里盯三个指标准确率、覆盖率、时效性。准确率通过抽样人工标注验证随机抽 500 个用户让运营同学对照真实行为判断标签是否符合直觉。覆盖率指标签非空的用户占全体用户的比例比如性别覆盖率只有 30%说明有大量用户因为没有注册信息而缺失这类标签的运营价值有限。时效性衡量标签更新延迟离线画像的延迟以天计实时画像以分钟计。每类标签都要明确自己的时效承诺不能拿离线标签做实时推荐。5.2 用 A/B 测试反向验证画像有效性最好的验证方式是让业务直接使用画像用效果说话。做法是把用户随机分成两组实验组用画像标签做定向推送对照组用默认分发策略跑两周看转化率差异。以「高价值用户」标签为例如果实验组的点击率显著高于对照组p 值小于0.05说明标签真实刻画了高价值人群的特征。如果差异不显著先别急着说算法没用——查一下标签的覆盖率是不是太低了或者样本量是否不够两周就得出稳定结论。5.3 冷启动用户的画像兜底策略新用户没有任何行为数据画像的常规链路完全失效。常见的处理方式是用先验分布兜底新用户直接赋予全站用户画像的平均值。比如全站用户的平均品类偏好分布是「3C 30%、家居25%、服饰45%」新用户初始偏好就按这个比例设置。当新用户产生第一次行为后用贝叶斯更新逐步修正初始画像。这个方案的价值在于算法侧的推荐系统、运营侧的推送策略都能以「存在初始画像」为前提做统一逻辑不需要为冷启动另写一套分支代码。具体实现时兜底画像可以打进标签表里的默认行标记sourceprior等真实行为数据积累到阈值后再替换为sourcereal。本文还有配套的精品资源点击获取
返回列表