滴滴搜推算法
一、定义一个树结构、特征结构。写一个决策树对样本打分
逆天啊,上来就是暴击
import numpy as np
class TreeNode:
def __init__(self, feature_index=None, threshold=None, left=None, right=None, score=None):
self.feature_index = feature_index # 用于分裂的特征索引
self.threshold = threshold # 分裂阈值
self.left = left # 左子树
self.right = right # 右子树
self.score = score # 叶子节点的分数
def is_leaf(self):
return self.score is not None
class DecisionTree:
def __init__(self, root):
self.root = root
def score_sample(self, sample):
"""对单个样本进行打分"""
node = self.root
while not node.is_leaf():
if sample[node.feature_index] <= node.threshold:
node = node.left
else:
node = node.right
return node.score
# 示例树(手动构造)
leaf1 = TreeNode(score=0.1)
leaf2 = TreeNode(score=0.7)
leaf3 = TreeNode(score=0.4)
leaf4 = TreeNode(score=0.9)
node2 = TreeNode(feature_index=1, threshold=1.5, left=leaf1, right=leaf2)
node3 = TreeNode(feature_index=2, threshold=2.5, left=leaf3, right=leaf4)
root = TreeNode(feature_index=0, threshold=0.5, left=node2, right=node3)
decision_tree = DecisionTree(root)
# 测试样本
sample1 = np.array([0.3, 2.0, 3.0]) # 走左子树,再走右子树,得分 0.7
sample2 = np.array([0.8, 0.5, 2.0]) # 走右子树,再走左子树,得分 0.4
print(decision_tree.score_sample(sample1)) # 输出: 0.7
print(decision_tree.score_sample(sample2)) # 输出: 0.4
二、itemcf 和 usercf 的使用场景、分别有什么好处
2.1. ItemCF(基于物品的协同过滤)
使用场景
- 适用于商品、电影、音乐、书籍等推荐系统,尤其是商品数量相对固定,而用户行为动态变化的场景。
- 适合短期兴趣推荐,如电商平台的“看了又看”或“买了还买”。
- 适用于内容较丰富但用户行为较少的场景,比如新用户冷启动时。
优点
- 计算相对稳定,商品相似度矩阵变化较小,推荐结果较稳定。
- 适用于用户行为稀疏的数据集,即便单个用户数据较少,也能提供较好的推荐效果。
- 容易解释,能通过物品相似度解释推荐原因(例如:你买了A,所以推荐B)。
- 适合长尾商品推荐,提高物品曝光率。
缺点
- 无法解决用户兴趣变化的问题,例如短期流行趋势较难捕捉。
- 依赖用户的行为数据,如果冷启动商品缺乏行为数据,则无法计算相似度。
- 计算物品相似度可能会受到热门物品的影响,导致热门物品推荐过多。
2.2. UserCF(基于用户的协同过滤)
使用场景
- 适用于社区、社交平台、新闻推荐等场景,尤其是用户互动较多的情况。
- 适合基于社交关系的推荐,如“和你兴趣相似的用户喜欢这个”。
- 适用于需要个性化推荐的场景,如个性化视频推荐。
优点
- 适用于短期兴趣推荐,比如新闻推荐,能够快速适应用户兴趣变化。
- 能挖掘用户之间的相似性,适用于社交推荐,例如好友推荐、共同兴趣群体推荐。
- 对冷启动用户友好,可以利用相似用户的历史行为来提供推荐。
缺点
- 计算量大,用户数量多时计算相似度代价高。
- 依赖用户的行为数据,用户行为过少时难以计算出有效的相似度。
- 用户兴趣变化快时,历史相似用户可能不再合适,导致推荐效果下降。
- 容易受流行用户的影响,可能导致热门用户行为被过度推荐。
2.3. 使用场景对比
维度 | ItemCF | UserCF |
---|---|---|
用户数量 | 用户数远大于物品数时更适用 | 物品数远大于用户数时更适用 |
实时性 | 新用户加入系统影响小 | 新物品加入系统影响小 |
行为密度 | 在用户行为较丰富的场景表现更好 | 在用户行为较稀疏的场景更稳定 |
场景案例 | 电商商品推荐、内容推荐 | 社交推荐、小众兴趣发现 |
- 结合两者可实现更好的推荐效果,如混合推荐(Hybrid Recommendation)。
三、双塔召回一味的打压负样本有什么问题?
在推荐系统中,负样本通常是 用户未交互的物品,但其中可能包含用户潜在感兴趣的物品(即 硬负样本 Hard Negatives)。
3.1. 这里首先要理解什么叫打压负样本?
在双塔召回中,打压负样本通常是指通过采样或损失函数设计,使模型能够更好地区分正样本和负样本,实际上是让模型更关注负样本的学习,更好识别到负样本。
eg:
1. 增加难负样本(hard negative)的比例
2. 在损失函数中给负样本更大权重(如对比学习中)
3. 进行负样本挖掘(negative mining)
3.2. 可能带来的问题
3.2.1. 召回多样性下降 (用户未交互的item不一定是真负样本(可能只是没曝光))
- 如果负样本被过分打压,模型可能学会简单地记住某些类别的物品 永远不推荐,这可能会导致召回多样性降低。
- 例如,用户可能对某个类别的物品 偶尔感兴趣,但如果模型一味打压该类别的物品,它们可能永远不会被召回。
3.2.2. 可能损害硬负样本(Hard Negative)的贡献
- 硬负样本(如用户可能感兴趣但未交互的物品)可以提供有价值的监督信号。
- 过度打压负样本可能会让模型强行拉开所有负样本的距离,而忽略了其中一些“接近正样本”的负样本,影响推荐效果。
3.2.3. 过拟合(忽略掉全局分布,过度拟合特定的负样本)
- 过度强调负样本的区分,会使模型过于依赖当前训练数据中的负样本分布,而忽略潜在的 泛化能力。
四、为什么mmoe要加极化,这样容易导致波动增加。
这里我没太理解极化,chatgpt说,极化是指:某些专家始终被选中,而其他专家几乎不被选中(即门控权重接近 1 或 0),就会导致极化现象。
那我理解极化就是指每个门控gate的输出不经过激活函数,直接输出logit,做为每个experts的权重。
五、53. 最大子数组和(力扣hot100_数组)
这道题没法使用滑动窗口,因为存在负数,滑入一个数后,结果可能变大,也可能变小。
- 思路1:前缀和
这道题和121. 买卖股票的最佳时机一样,都是求最大子数组和。我们可以维护一个最小前缀和,用当前前缀和 减去维护的 最小前缀和 ,就得到最大数组和。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
ans = -inf
min_pre_sum = pre_sum = 0
for x in nums:
pre_sum += x # 当前的前缀和
ans = max(ans, pre_sum - min_pre_sum) # 减去前缀和的最小值
min_pre_sum = min(min_pre_sum, pre_sum) # 维护前缀和的最小值
return ans
- 动态规划
维护 dp[i] 表示以 nums[i] 结尾的最大子数组和。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
dp = [0] * len(nums)
dp[0] = nums[0]
for i in range(1, len(nums)):
dp[i] = max(dp[i - 1], 0) + nums[i]
return max(dp)