搜广推校招面经六十三

发布于:2025-04-01 ⋅ 阅读:(20) ⋅ 点赞:(0)

字节广告算法

一、学过Kmeans么?写一下损失函数,每个簇的中心点怎么选择,推导一下Kmeans的参数

不亏是字节,上来就是暴击。

  • K-Means 通过最小化平方误差来寻找簇中心,使用欧几里得距离作为度量标准。
  • 簇中心可以随机初始化,也可以通过Kmeans++的初始化方法,减少陷入局部最优解问题。并且通过计算簇内样本均值来更新。

1.1. K-Means 损失函数

K-Means 的目标是最小化簇内样本到簇中心的平方距离总和,损失函数(目标函数)定义如下:
J = ∑ i = 1 k ∑ x j ∈ C i ∥ x j − μ i ∥ 2 J = \sum_{i=1}^{k} \sum_{x_j \in C_i} \| x_j - \mu_i \|^2 J=i=1kxjCixjμi2

其中:

  • k k k 是簇的个数
  • C i C_i Ci 代表第 i i i 个簇
  • x j x_j xj 是属于第 i i i 个簇的样本点
  • μ i \mu_i μi 是簇 C i C_i Ci 的中心(均值)
  • ∥ x j − μ i ∥ 2 \| x_j - \mu_i \|^2 xjμi2 代表欧几里得距离的平方

1.2. 簇中心的选择

  1. 随机初始化:随机选取 k k k 个数据点作为初始簇中心 μ 1 , μ 2 , . . . , μ k \mu_1, \mu_2, ..., \mu_k μ1,μ2,...,μk
  2. 迭代更新
    • 分配样本:根据当前簇中心,将每个样本 x j x_j xj 归入最近的簇 C i C_i Ci,即:
      C i = { x j ∣ arg ⁡ min ⁡ i ∥ x j − μ i ∥ 2 } C_i = \{ x_j \mid \arg\min_{i} \| x_j - \mu_i \|^2 \} Ci={xjargiminxjμi2}

    • 更新簇中心:计算每个簇的新中心,取簇内所有样本点的均值:

μ i = 1 ∣ C i ∣ ∑ x j ∈ C i x j \mu_i = \frac{1}{|C_i|} \sum_{x_j \in C_i} x_j μi=Ci1xjCixj

  • 重复上述步骤,直到簇中心收敛或满足终止条件

1.3. 参数推导

1.3.1 目标函数对簇中心 μ i \mu_i μi 求导

目标函数为:
J = ∑ i = 1 k ∑ x j ∈ C i ∥ x j − μ i ∥ 2 J = \sum_{i=1}^{k} \sum_{x_j \in C_i} \| x_j - \mu_i \|^2 J=i=1kxjCixjμi2

对簇中心 μ i \mu_i μi 求偏导:
∂ J ∂ μ i = ∑ x j ∈ C i 2 ( μ i − x j ) \frac{\partial J}{\partial \mu_i} = \sum_{x_j \in C_i} 2(\mu_i - x_j) μiJ=xjCi2(μixj)

令偏导数为 0:
∑ x j ∈ C i 2 ( μ i − x j ) = 0 \sum_{x_j \in C_i} 2(\mu_i - x_j) = 0 xjCi2(μixj)=0

整理得:
μ i = 1 ∣ C i ∣ ∑ x j ∈ C i x j \mu_i = \frac{1}{|C_i|} \sum_{x_j \in C_i} x_j μi=Ci1xjCixj
这表明,每个簇的中心是该簇中所有数据点的均值。

1.3.2 迭代收敛性

K-Means 在每次迭代中都会降低目标函数值 J J J,因此收敛性是保证的。但由于其是基于随机初始化的,可能会收敛到局部最优解,因此可采用 K-Means++ 进行优化,即:

  1. 选取一个数据点作为第一个簇中心。
  2. 依概率 p p p 选择新的簇中心:
    p ( x ) = D ( x ) 2 ∑ D ( x ) 2 p(x) = \frac{D(x)^2}{\sum D(x)^2} p(x)=D(x)2D(x)2
    其中 D ( x ) D(x) D(x) 是数据点到最近簇中心的距离。
    K-Means++ 能有效减少初始中心的不稳定性,提高收敛效果。

1.4. 代码实现

见【搜广推校招面经二十三

二、写一下逻辑回归的表达式,参数怎么推导

2.1. 逻辑回归的基本表达式

逻辑回归(Logistic Regression)用于二分类问题,其基本形式如下:
P ( Y = 1 ∣ X ) = σ ( W T X + b ) P(Y=1 | X) = \sigma(W^T X + b) P(Y=1∣X)=σ(WTX+b)
其中:

  • X X X 是输入特征向量,
  • W W W 是权重向量,
  • b b b 是偏置项,
  • σ ( z ) \sigma(z) σ(z)sigmoid 函数,定义如下:

σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+ez1
由于 σ ( z ) \sigma(z) σ(z) 的值范围在 (0,1) 之间,因此逻辑回归输出的是一个概率值,通常设定阈值(如 0.5)进行分类。

2.2. 似然函数与对数似然函数

给定一组训练数据 { ( X i , Y i ) } i = 1 n \{(X_i, Y_i)\}_{i=1}^{n} {(Xi,Yi)}i=1n,样本的联合概率为:
L ( W , b ) = ∏ i = 1 n P ( Y i ∣ X i ) = ∏ i = 1 n σ ( W T X i + b ) Y i ( 1 − σ ( W T X i + b ) ) ( 1 − Y i ) L(W, b) = \prod_{i=1}^{n} P(Y_i | X_i) = \prod_{i=1}^{n} \sigma(W^T X_i + b)^{Y_i} (1 - \sigma(W^T X_i + b))^{(1 - Y_i)} L(W,b)=i=1nP(YiXi)=i=1nσ(WTXi+b)Yi(1σ(WTXi+b))(1Yi)
取对数得到对数似然函数:
ℓ ( W , b ) = ∑ i = 1 n [ Y i log ⁡ σ ( W T X i + b ) + ( 1 − Y i ) log ⁡ ( 1 − σ ( W T X i + b ) ) ] \ell(W, b) = \sum_{i=1}^{n} \left[ Y_i \log \sigma(W^T X_i + b) + (1 - Y_i) \log (1 - \sigma(W^T X_i + b)) \right] (W,b)=i=1n[Yilogσ(WTXi+b)+(1Yi)log(1σ(WTXi+b))]

2.3. 梯度计算(参数推导)

W W W 求偏导:

利用链式法则,对数似然函数关于 W W W 的梯度为:
∂ ℓ ∂ W = ∑ i = 1 n ( Y i − σ ( W T X i + b ) ) X i \frac{\partial \ell}{\partial W} = \sum_{i=1}^{n} \left( Y_i - \sigma(W^T X_i + b) \right) X_i W=i=1n(Yiσ(WTXi+b))Xi

b b b 求偏导:

∂ ℓ ∂ b = ∑ i = 1 n ( Y i − σ ( W T X i + b ) ) \frac{\partial \ell}{\partial b} = \sum_{i=1}^{n} \left( Y_i - \sigma(W^T X_i + b) \right) b=i=1n(Yiσ(WTXi+b))

2.4. 参数更新(梯度下降)

利用梯度下降(Gradient Descent)更新参数:
W ← W + α ∑ i = 1 n ( Y i − σ ( W T X i + b ) ) X i W \leftarrow W + \alpha \sum_{i=1}^{n} (Y_i - \sigma(W^T X_i + b)) X_i WW+αi=1n(Yiσ(WTXi+b))Xi

b ← b + α ∑ i = 1 n ( Y i − σ ( W T X i + b ) ) b \leftarrow b + \alpha \sum_{i=1}^{n} (Y_i - \sigma(W^T X_i + b)) bb+αi=1n(Yiσ(WTXi+b))
其中:

  • α \alpha α 为学习率(learning rate)。

若使用 随机梯度下降(SGD),则每次仅用一个样本更新:
W ← W + α ( Y i − σ ( W T X i + b ) ) X i   b ← b + α ( Y i − σ ( W T X i + b ) ) W \leftarrow W + \alpha (Y_i - \sigma(W^T X_i + b)) X_i \\ \ \\ b \leftarrow b + \alpha (Y_i - \sigma(W^T X_i + b)) WW+α(Yiσ(WTXi+b))Xi bb+α(Yiσ(WTXi+b))

2.5. 代码实现

见【搜广推校招面经二十三

三、L1、L2正则化公式,分别适用于什么场景、从数学角度讲一下两者区别

3.1. L1正则化(Lasso Regression)

L1 正则化是对模型的损失函数加上参数的 L1 范数(即绝对值之和)的惩罚项:
J ( θ ) = L ( θ ) + λ ∑ i = 1 n ∣ θ i ∣ J(\theta) = L(\theta) + \lambda \sum_{i=1}^{n} |\theta_i| J(θ)=L(θ)+λi=1nθi

适用场景
  • 特征选择:L1 正则化会让某些特征的权重变为 0,从而起到特征筛选的作用,适用于高维稀疏数据。
  • 稀疏模型:如果希望得到一个稀疏解(sparse solution),如在文本分类或基因数据分析中,L1 正则化是不错的选择。

3.2. L2 正则化(Ridge Regression)

L2 正则化是在损失函数中添加参数的 L2 范数(即平方和)的惩罚项:
J ( θ ) = L ( θ ) + λ ∑ i = 1 n θ i 2 J(\theta) = L(\theta) + \lambda \sum_{i=1}^{n} \theta_i^2 J(θ)=L(θ)+λi=1nθi2

适用场景
  • 防止过拟合:L2 正则化不会使参数变为 0,而是会让所有参数趋向较小的值,从而降低模型的复杂度,减少过拟合的风险。
  • 适用于相关性较高的特征:如果输入特征之间存在较高的相关性,L2 正则化比 L1 更稳定,因为它不会完全去掉某个特征,而是让所有特征的权重缩小。

3.3 数学区别

正则化类型 惩罚项 对参数的影响 计算梯度
L1 正则化 ∑ θ i \sum \theta_i θi 使部分权重变为 0,得到稀疏解 梯度不连续,更新时可能直接设为 0
L2 正则化 ∑ θ i 2 \sum \theta_i^2 θi2 使权重变小,但不会完全变为 0 梯度连续,参数缩小但仍保留

具体来看:

  • L1 的梯度:
    ∂ J ∂ θ i = ∂ L ∂ θ i + λ ⋅ s i g n ( θ i ) \frac{\partial J}{\partial \theta_i} = \frac{\partial L}{\partial \theta_i} + \lambda \cdot sign(\theta_i) θiJ=θiL+λsign(θi)
    由于 sign ( θ i ) \text{sign}(\theta_i) sign(θi) 只有三种取值(-1, 0, 1),导致 L1 正则化的梯度在 0 处不连续,因此在优化过程中部分参数可能被直接置为 0。

  • L2 的梯度:
    ∂ J ∂ θ i = ∂ L ∂ θ i + 2 λ θ i \frac{\partial J}{\partial \theta_i} = \frac{\partial L}{\partial \theta_i} + 2\lambda\theta_i θiJ=θiL+2λθi
    L2 正则化会使参数逐步缩小,但不会变为 0。

3.4. 总结

  • L1 正则化 适用于 特征选择,会让部分参数变为 0,从而得到稀疏模型。
  • L2 正则化 适用于 防止过拟合,不会让参数变 0,而是让它们趋于较小的值,提高模型的泛化能力。
  • 在深度学习中,L2(权重衰减)更常用,而在稀疏特征数据中,L1 更合适。

四、39. 组合总和(力扣hot100_回溯)

在这里插入图片描述

  • 思路:字节考的题还是很难得,从八股都看得出来。算法题也是直接来也给回溯。
  • 代码:
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        ans = []
        path = []

        def dfs(i: int, left: int) -> None:
            if left == 0:
                # 找到一个合法组合
                ans.append(path.copy())
                return

            if i == len(candidates) or left < 0:
                return

            # 不选
            dfs(i + 1, left)

            # 选
            path.append(candidates[i])
            dfs(i, left - candidates[i])
            path.pop()  # 恢复现场

        dfs(0, target)
        return ans

网站公告

今日签到

点亮在社区的每一天
去签到