搜广推校招面试经验分享——第64期回顾
滴滴搜推算法
一、定义一个树结构、特征结构。写一个决策树对样本打分
逆天啊,上来就是暴击
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(基于物品的协同过滤)
使用场景
优点
缺点
2.2. UserCF(基于用户的协同过滤)
使用场景
优点
缺点
2.3. 使用场景对比
维度 | ItemCF | UserCF |
---|---|---|
用户数量 | 用户数远大于物品数时更适用 | 物品数远大于用户数时更适用 |
实时性 | 新用户加入系统影响小 | 新物品加入系统影响小 |
行为密度 | 在用户行为较丰富的场景表现更好 | 在用户行为较稀疏的场景更稳定 |
场景案例 | 电商商品推荐、内容推荐 | 社交推荐、小众兴趣发现 |
三、双塔召回一味的打压负样本有什么问题?
在推荐系统中,负样本通常是 用户未交互的物品,但其中可能包含用户潜在感兴趣的物品(即 硬负样本 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_数组)
这道题没法使用滑动窗口,因为存在负数,滑入一个数后,结果可能变大,也可能变小。
这道题和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)
作者:Y1nhl