目录
正在加载目录...

Pinterest MLE OA 巨难OA | Codesignal 三题

Pinterest MLE OA 巨难OA | Codesignal 三题

Pinterest MLE OA 一共 10 道题,前 6 题主要是偏基础的机器学习理论题,难度不算特别偏,系统复习过教材或大学 lecture notes 基本可以覆盖;第 7 题是手算神经网络前向传播,给定 input 和 weights 计算最终输出,最后一个节点使用 sigmoid activation 需要特别注意;最后 2 题是用基础 Python 做模型实现,我当时遇到的是用 individual decision trees 构建 random forest,以及实现 decision tree 的 validation 和 model fit,题目讲得比较清晰、实现路径也直接,但整体时间非常紧张,需要控制好节奏。

Pinterest MLE OA 选择题

选择题应该都是原题,我尽力回忆一下: 1. TP/FP/etc这些eval metrics的计算,题目会给几个表格的数据,然后要根据数据的值选出符合要求的那批; 2. ensemble相关,是否能提高可解释性之类的; 3. 训练的时候acc高但测试的时候acc低是为什么,典型的过拟合; 4. classification的loss func有那些,CE之类的东西; 5. 模型很多参数变成0了是怎么回事 然后要手算一道神经网络的输出,一定一定要准备好纸笔和计算器!!需要算sigmoid,然后因为有很多中间值,没办法用脑子记,一定要用纸笔。

Pinterest MLE OA Code

Q1:

题意:给定一个整数数组 rawData 和一个整数 localArea,要求找出所有满足“局部最大值”条件的元素下标(0-based)。某个位置 i 是局部最大值,当且仅当从 rawData[i] 向左最多取 localArea 个元素、向右最多取 localArea 个元素,这两侧分别都构成严格递减序列,且不允许出现相等或更大的邻居。最终返回所有符合条件的下标,并按升序排列。

思路:本质是在看某个点左右是不是“一路往下走”,先从左到右、从右到左各扫一遍,预处理出每个位置能连续严格递减(或递增方向对应)多长,这样到某个位置时,只要对比一下左右能覆盖的长度够不够localArea。

代码:

def solution(rawData, localArea):
    n = len(rawData)
    L = [0] * n
    R = [0] * n
    
    for i in range(1, n):
        L[i] = L[i-1] + 1 if rawData[i] > rawData[i-1] else 0
    
    for i in range(n-2, -1, -1):
        R[i] = R[i+1] + 1 if rawData[i] > rawData[i+1] else 0
    
    res = []
    for i in range(n):
        kl = min(localArea, i)
        kr = min(localArea, n-1-i)
        if L[i] >= kl and R[i] >= kr:
            res.append(i)
    
    return res

Q2:

题意:要求在给定的代码框架下,从零实现 Bagging分类算法的核心步骤:对每个基分类器用有放回抽样(bootstrap)从训练集生成与原数据等大小的样本,分别训练模型,然后对测试集进行预测,并通过多数投票得到最终类别(若出现票数相同则选标签值较小的类别)。输入包括训练特征 x_train、训练标签 y_train、测试特征 x_test 和基分类器数量 n_estimators,需要返回测试集的预测类别数组;抽样必须用 randint(0, n) 生成索引且只在初始位置使用随机种子。

思路:每个基分类器都对训练集做一次“有放回抽样”,用这份子数据单独训练一棵决策树;预测时,让所有树对同一个测试样本各自投票,最后选票数最多的类别,平票就选编号小的

代码:

from random import randint, seed
from sklearn.tree import DecisionTreeClassifier


def bootstrap(n: int) -> list[int]:
    return [randint(0, n-1) for _ in range(n)]


def fit(classifiers: list[DecisionTreeClassifier], x: list[list[float]], y: list[int]):
    n = len(x)
    for i, clf in enumerate(classifiers):
        idx = bootstrap(n)
        xs = [x[j] for j in idx]
        ys = [y[j] for j in idx]
        clf.fit(xs, ys)

def predict(classifiers: list[DecisionTreeClassifier], x: list[list[float]]) -> list[int]:
    preds = [list(clf.predict(x)) for clf in classifiers]
    res = []
    for votes in zip(*preds):
        cnt = {}
        for v in votes:
            cnt[v] = cnt.get(v, 0) + 1
        best = max(cnt.keys(), key=lambda k: (cnt[k], -k))
        res.append(int(best))
    return res

def solution(x_train: list[list[float]], y_train: list[int], x_test: list[list[float]], n_estimators: int) -> list[int]:
    seed(42)
    classifiers = [DecisionTreeClassifier(random_state=0) for _ in range(n_estimators)]
    fit(classifiers, x_train, y_train)
    return predict(classifiers, x_test)

Q3:

题意:要求在给定代码框架下,从零实现一个 Gaussian Naive Bayes 分类器(只能使用 numpymath),包括:按类别计算每个特征的均值和方差,计算各类别的先验概率,实现高斯概率密度函数,然后根据贝叶斯公式计算后验概率,并为每个测试样本选择后验概率最大的类别作为预测结果。输入为训练特征 x_train、训练标签 y_train 和测试特征 x_test,输出为测试集的预测类别数组;只能在指定的 # implement this 部分补充代码。

思路:先看一遍训练集,算出每个类别出现的概率(先验),并记住每个类别下各项特征的平均值和波动情况(均值和方差);等新样本来了,用高斯分布公式套,看这个样本在哪个类别下出现的可能性最高(对数似然最大),最后把它归到可能性最大的那一类即可。

代码:

class NaiveBayesClassifier:
    def get_descriptives(
        self,
        x_train: npt.NDArray[np.float64],
        y_train: npt.NDArray[np.int64]
    ) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
        n_feat = x_train.shape[1]
        self.C = int(y_train.max()) + 1
        m = np.zeros((self.C, n_feat), dtype=float)
        v = np.ones((self.C, n_feat), dtype=float)
        for c in range(self.C):
            idx = (y_train == c)
            if idx.any():
                sub = x_train[idx]
                m[c] = sub.mean(axis=0)
                v[c] = sub.var(axis=0)
        self.mean = m
        self.variance = v
        return self.mean, self.variance

    def get_priors(self, y_train: npt.NDArray[np.int64]) -> npt.NDArray[np.float64]:
        n = y_train.shape[0]
        self.prior = np.zeros(self.C, dtype=float)
        for c in range(self.C):
            self.prior[c] = np.sum(y_train == c) / n
        return self.prior

    def gaussian_density(self, class_idx: np.int64, x: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
        mu = self.mean[int(class_idx)]
        var = self.variance[int(class_idx)].copy()
        eps = 1e-9
        var = var + eps
        coef = 1.0 / np.sqrt(2.0 * math.pi * var)
        expo = np.exp(-0.5 * ((x - mu) ** 2) / var)
        return coef * expo

    def get_prediction(self, x: npt.NDArray[np.float64]) -> int:
        best = -1
        bestv = -1e300
        tiny = 1e-12
        for c in range(self.C):
            p = self.prior[c]
            if p <= 0:
                val = -1e300
            else:
                dens = self.gaussian_density(c, x)
                val = math.log(p) + float(np.sum(np.log(dens + tiny)))
            if val > bestv:
                bestv = val
                best = c
        return int(best)

    def fit(self, x_train: npt.NDArray[np.float64], y_train: npt.NDArray[np.int64]) -> None:
        self.get_descriptives(x_train, y_train)
        self.get_priors(y_train)

    def predict(self, x_test: npt.NDArray[np.float64]) -> list[int]:
        predictions = [self.get_prediction(x) for x in x_test]
        return predictions

准备小结

如果你也在准备 Pinterest Intern 或其他大厂的 OA/VO,可以直接联系 interviewAid 了解对应的面试辅助和陪跑支持。如果你想找我辅助面试,或者用 Pinterest 面经 中的原题 mock,感受最真实的feedback,欢迎戳我。

全网唯一一家支持 L6 以上 system design mock,只放真实面经。

求职辅助服务,是关于时间和品质的较量。咨询interviewAid,获取最专业的Tech求职辅助。

正文完