机器学习面试问题总结

在此记录下常见的机器学习面试问题。

判别式模型和生成式模型的区别?

判别方法:由数据直接学习决策函数 Y = f(X),或者由条件分布概率 P(Y|X)作为预测模型,即判别模型。
生成方法:由数据学习联合概率密度分布函数 P(X,Y),然后求出条件概率分布P(Y|X)作为预测的模型,即生成模型。
由生成模型可以得到判别模型,但由判别模型得不到生成模型。
常见的判别模型有:K近邻、SVM、决策树、感知机、线性判别分析(LDA)、线性回归、传统的神经网络、逻辑斯蒂回归、boosting、条件随机场
常见的生成模型有:朴素贝叶斯、隐马尔可夫模型、高斯混合模型、文档主题生成模型(LDA)、限制玻尔兹曼机

什么时候使用归一化/标准化

如果对输出结果范围要求,用归一化;如果数据较为稳定,不存在极端的最大最小值,用归一化;如果存在噪音和异常值,可以使用标准化处理。归一化和标准化的而区别在于,归一化是统一到一定的区间(由极值决定),而标准化和整体样本由很大关系。

极大似然估计和最小二乘法区别

对于最小二乘法,当从模型总体随机抽取n组样本观测值后,最合理的参数估计量应该使得模型能最好地拟合样本数据,也就是估计值和观测值之差的平方和最小。
而对于最大似然法,当从模型总体随机抽取n组样本观测值后,最合理的参数估计量应该使得从模型中抽取该n组样本观测值的概率最大。
在最大似然法中,通过选择参数,使已知数据在某种意义下最有可能出现,而某种意义通常指似然函数最大,而似然函数又往往指数据的概率分布函数。与最小二乘法不同的是,最大似然法需要已知这个概率分布函数,这在实践中是很困难的。一般假设其满足正态分布函数的特性,在这种情况下,最大似然估计和最小二乘估计相同。
最小二乘法以估计值与观测值的差的平方和作为损失函数,极大似然法则是以最大化目标值的似然概率函数为目标函数,从概率统计的角度处理线性回归并在似然概率函数为高斯函数的假设下同最小二乘建立了的联系。

什么是偏差和方差?

偏差:描述的是预测值(估计值)的期望与真实值之间的差距。偏差越大,越偏离真实数据
方差:描述的是预测值的变化范围,离散程度,也就是离其期望值的距离。方差越大,数据的分布越分散
Bias:误差,对象是单个模型,期望输出与真实标记的差别(可以解释为描述了模型对本训练集的拟合程度)
Variance:方差,对象是多个模型(这里更好的解释是换同样规模的训练集,模型的拟合程度怎么样;也可以说方差是刻画数据扰动对模型的影响,描述的是训练结果的分散程度)
从同一个数据集中,用科学的采样方法得到几个不同的子训练集,用这些训练集训练得到的模型往往并不相同。
参数w变大,会使模型变得更复杂(即过拟合情况),拟合的更好,故偏差会变小;而对于数据的扰动会更加敏感,所以方差会变大。

L2与L1的区别?为什么能能防止过拟合?

L1会趋向于产生少量的特征,而其他的特征都是0,而L2会选择更多的特征,这些特征都会接近于0。Lasso在特征选择时候非常有用,而Ridge就只是一种规则化而已。在所有特征中只有少数特征起重要作用的情况下,选择Lasso比较合适,因为它能自动选择特征。而如果所有特征中,大部分特征都能起作用,而且起的作用很平均,那么使用Ridge也许更合适。

更小的权值\(w\),从某种意义上说,表示网络的复杂度更低,对数据的拟合刚刚好(这个法则也叫做奥卡姆剃刀),
过拟合的时候,拟合函数的系数往往非常大,为什么?如下图所示,过拟合,就是拟合函数需要顾忌每一个点,最终形成的拟合函数波动很大。在某些很小的区间里,函数值的变化很剧烈。这就意味着函数在某些小区间里的导数值(绝对值)非常大,由于自变量值可大可小,所以只有系数足够大,才能保证导数值很大。
而正则化是通过约束参数的范数使其不要太大,所以可以在一定程度上减少过拟合情况。

另外,L2与L1的区别在于,L1正则是拉普拉斯先验,而L2正则则是高斯先验。它们都是服从均值为0,协方差为\(1λ\)。当λ=0时,即没有先验)没有正则项,则相当于先验分布具有无穷大的协方差,那么这个先验约束则会非常弱,模型为了拟合所有的训练集数据, 参数w可以变得任意大从而使得模型不稳定,即方差大而偏差小。λ越大,标明先验分布协方差越小,偏差越大,模型越稳定。即,加入正则项是在偏差bias与方差variance之间做平衡tradeoff。

为什么L1正则是拉普拉斯先验,而L2正则则是高斯先验?

先看下最原始的线性回归:
假设\(y=Xw+\epsilon\),\(\epsilon\)服从高斯分布,则有:
\[
p(\epsilon^{(i)})=\frac{1}{\sqrt{2 \pi} \sigma} \exp (-\frac{ (\epsilon^{(i)})^2}{2 \sigma^2})
\]
得:
\[
p(y^{(i)}|x^{(i)};\theta)=\frac{1}{\sqrt{2 \pi} \sigma}\exp(-\frac{ (y^{(i)}-w^T x^{(i)})^2}{2 \sigma^2})
\]
由最大似然估计(MLE):
\[
L(w)=p(\hat y|X;w) \= \prod_{i=1}^m p(y^{(i)}|x^{(i)};\theta) \= \prod_{i=1}^m \frac{1}{\sqrt{2 \pi} \sigma} \exp(-\frac{ (y^{(i)}-w^T x^{(i)})^2}{2 \sigma^2})
\]
取对数:
\[
l(w)=\log L(w) \=\log \prod_{i=1}^m \frac{1}{\sqrt{2 \pi} \sigma} \exp(-\frac{ (y^{(i)}-w^T x^{(i)})^2}{2 \sigma^2}) \=\sum_{i=1}^m \log \frac{1}{\sqrt{2 \pi} \sigma} \exp(-\frac{ (y^{(i)}-w^T x^{(i)})^2}{2 \sigma^2}) \=m \log \frac{1}{\sqrt{2 \pi} \sigma} -\frac{1}{{\sigma}^2} \cdot \frac{1}{2} \sum_{i=1}^m (y^{(i)}-w^T x^{(i)})^2
\]

即:
\[
w_{MLE} = arg \min_w \sum_{i=1}^m (y^{(i)}-w^Tx^{(i)})^2
\]

这就导出了我们原始的 least-squares 损失函数,但这是在我们对参数 \(w\) 没有加入任何先验分布的情况下。在数据维度很高的情况下,我们的模型参数很多,模型复杂度高,容易发生过拟合。
这个时候,我们可以对参数 \(w\) 引入先验分布,降低模型复杂度。

我们对参数\(w\) 引入协方差为\(\alpha\)的零均值高斯先验。
\[
L(w) = p(\hat y|X;w)p(w) \=\prod_{i=1}^m p(y^{(i)}|x^{(i)};\theta) p(w) \=\prod_{i=1}^m \frac{1}{\sqrt{2 \pi} \sigma} \exp(-\frac{ (y^{(i)}-w^T x^{(i)})^2}{2 \sigma^2}) \prod_{j=1}^n \frac{1}{\sqrt{2 \pi \alpha}} \exp{(-\frac{(w^{(j)})^2}{2 \alpha})} \=\prod_{i=1}^m \frac{1}{\sqrt{2 \pi} \sigma} \exp(-\frac{ (y^{(i)}-w^T x^{(i)})^2}{2 \sigma^2}) \frac{1}{\sqrt{2 \pi \alpha}} \exp{(-\frac{w^T w}{2 \alpha})}
\]
取对数:
\[
l(w)=log L(w) \=m \log \frac{1}{\sqrt{2 \pi} \sigma}+n \log{\frac{1}{\sqrt{2 \pi \alpha}}} -\frac{1}{{\sigma}^2} \cdot \frac{1}{2} \sum_{i=1}^m (y^{(i)}-w^T x^{(i)})^2 -\frac{1}{\alpha} \cdot \frac{1}{2} w^T w \\Rightarrow w_{MAP_{Gussian}} = argmin_w (\frac{1}{{\sigma}^2} \cdot \frac{1}{2} \sum_{i=1}^m (y^{(i)}-w^T x^{(i)})^2 + \frac{1}{\alpha} \cdot \frac{1}{2} w^T w)
\]
等价于:
\[
J_R(w)=\frac{1}{n} ||y-w^TX||_2 + \lambda ||w||_2
\]
即,对参数引入 高斯先验 等价于L2正则化
那么拉普拉斯分布(Laplace distribution)呢?
拉普拉斯分布为:
\[
f(x|\mu,b)=\frac{1}{2b}\exp(-\frac{|x-\mu|}{b})
\]

[拉普拉斯分布][base64str1]

重复之前的推导过程我们很容易得到:
\[
w_{MAP_{Loplace}} = argmin_w (\frac{1}{{\sigma}^2} \cdot \frac{1}{2} \sum_{i=1}^m (y^{(i)}-w^T x^{(i)})^2 + \frac{1}{b^2} \cdot \frac{1}{2} ||w||_1)
\]
该问题通常被称为 LASSO (least absolute shrinkage and selection operator) 。LASSO 仍然是一个凸优化问题,不具有解析解。它的优良性质是能产生稀疏性,导致\(w\)中许多项变成零。即,对参数引入 拉普拉斯先验 等价于L1正则化。

Lasso回归如何求解?

Lasso回归有时也叫做线性回归的L1正则化,和Ridge回归的主要区别就是在正则化项,Ridge回归用的是L2正则化,而Lasso回归用的是L1正则化。由于L1范数用的是绝对值之和,在零点处不可求导,所以使用非梯度下降法进行求解,如 坐标轴下降法(coordinate descent)和最小角回归法( Least Angle Regression, LARS)。          

  • 坐标轴下降法
    坐标下降算法每次选择一个维度进行参数更新,维度的选择可以是随机的或者是按顺序。
    当一轮更新结束后,更新步长的最大值少于预设阈值时,终止迭代。
    坐标下降优化方法是一种非梯度优化算法。在整个过程中依次循环使用不同的坐标方向进行迭代,一个周期的一维搜索迭代过程相当于一个梯度迭代。坐标轴下降法的数学依据为:对于一个可微凸函数\(f(w)\),其中w为\(n*1\)的向量,如果对于一个解\(w*\),使得\(f(w)\)在某个坐标轴上\(w\)都能达到最小值,则w*就是f(w)的全局的最小值点。
    梯度下降法是利用目标函数的导数(梯度)来确定搜索方向的,该梯度方向可能不与任何坐标轴平行。而坐标下降法是利用当前坐标方向进行搜索,不需要求目标函数的导数,只按照某一坐标方向进行搜索最小值,两者都是迭代方法,且每一轮迭代,都需要O(\(mn\))的计算量(m为样本数,n为系数向量的维度)。
  • 最小角回归法
    最小角回归法运用到了前向选择法(选取余弦距离最小的值进行投影,计算残差,迭代这个过程,直到残差达到我们的较小值或者已经遍历了整个变量)和前向梯度算法(选取余弦距离最小的值的样本方向进行移动一定距离,计算残差,重复这个迭代过程)的综合,做法就是取投影方向和前向梯度算法的残差方向形成的角的平分线方向,进行移动。对前向梯度算法和前向选择算法做了折中,保留了前向梯度算法一定程度的精确性,同时简化了前向梯度算法一步步迭代的过程。

怎么处理多分类问题?

拆解法;有三种:一对一(OvO)、一对其余(OvR)、多对多(MvM);
一对一是将N个类两两配合,从而产生N(N-1)/2个分类任务,最终结果通过投票产生:即把被预测得最多的类别作为最终分类结果。
一对其余则是每次讲一个类的样例作为正例、所有其他类的样例作为反例来训练N个分类器。在测试时时,若仅有一个分类器预测为正例,则对应的类别标记作为最终的分类结果,若有多个,则考虑各个分类器的预测置信度,选择置信度最大的类别作为分类结果。它需要训练N个分类器,但当类别很多时,OvO的训练时间开销通常比OvR更小。
多对多是每次讲若干个类作为正类,若干个其他类作为反类。需要特殊的设计,比如‘纠错输出码’:
假设一个数据集一共有K类,我们使用L种两类分类器(不仅仅是SVM),就会得到L个分类结果,每个结果用+1和-1来表示。这样,对于K类数据集,我们就可以学习到一个\(K*L\)的矩阵。然后,来了一个测试样本,我们就用同一样的方法得到测试样本的长度为L的向量,拿这个向量和\(K*L\)矩阵中的每一行做Hamming distance,距离最小的即为该测试样本的分类结果。

boosting和bagging的区别?

1)样本选择上:
Bagging:训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的.
Boosting:每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化.而权值是根据上一轮的分类结果进行调整.
2)样例权重:
Bagging:使用均匀取样,每个样例的权重相等
Boosting:根据错误率不断调整样例的权值,错误率越大则权重越大.
3)预测函数:
Bagging:所有预测函数的权重相等.
Boosting:每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重.
4)并行计算:
Bagging:各个预测函数可以并行生成
Boosting:各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果.

如何从偏差和方差的角度解释bagging和boosting的原理?

偏差指的是算法的期望预测与真实值之间的偏差程度,反映了模型本身的拟合能力;方差度量了同等大小的训练集的变动导致学习性能的变化,刻画了数据扰动所导致的影响。
Bagging对样本重采样,对每一重采样得到的子样本集训练一个模型,最后取平均。由于子样本集的相似性以及使用的是同种模型,因此各模型有近似相等的bias和variance。由于\(E[\frac{\sum X_i}{n}]=E[X_i]\),所以bagging后的bias和单个子模型的接近,一般来说不能显著降低bias。另一方面,若各子模型独立,则有\(Var[\frac{\sum X_i}{n}]=\frac{Var[X_i]}{n}\),此时可以显著降低variance。若各子模型完全相同,则\(Var[\frac{\sum X_i}{n}]=Var[X_i]\),此时不会降低variance。bagging方法得到的各子模型是有一定相关性的,属于上面两个极端状况的中间态,因此可以一定程度降低variance。
boosting从优化角度来看,是用forward-stagewise这种贪心法去最小化损失函数,由于采取的是串行优化的策略,各子模型之间是强相关的,于是子模型之和并不能显著降低variance。所以说boosting主要还是靠降低bias来提升预测精度。

哪些机器学习算法不需要做归一化处理?

概率模型不需要归一化,因为它们不关心变量的值,而是关心变量的分布和变量之间的条件概率,如决策树、RF。而像SVM、LR、KNN、KMeans之类的最优化问题就需要归一化。

特征选择基本原则

数据预处理完成之后,我们需要选择有意义的特征,输入机器学习的算法和模型进行训练,通常来说,从两个方面考虑来选择特征

  • 特征是否发散:如果一个特征不发散,例如方差接近于0,也就是说样本在这个特征上基本上没有差异,这个特征对于样本的区分并没有什么用。
  • 特征与目标的相关性:这点比较显见,与目标相关性高的特征,应当优选选择。

根据特征选择的形式又可以将特征选择方法分为3种:

  • Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。
  • Wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。
  • Embedded:嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于Filter方法,但是是通过训练来确定特征的优劣。

随机森林如何评估特征重要性

随机森林中进行特征重要性的评估思想为:
判断每个特征在随机森林中的每颗树上做了多大的贡献,然后取个平均值,最后比一比特征之间的贡献大小。其中关于贡献的计算方式可以是基尼指数或袋外数据错误率。
以基于袋外数据为例,
对于一棵树 ,用OOB样本可以得到误差 \(e1\),然后随机改变OOB中的第 \(j\) 列,保持其他列不变,对第 \(j\) 列进行随机的上下置换,得到误差 \(e2\)。至此,可以用 \(e1-e2\) 来刻画特征 \(j\) 的重要性。其依据就是,如果一个特征很重要,那么其变动后会非常影响测试误差,如果测试误差没有怎么改变,则说明特征\(j\)不重要。
而该方法中涉及到的对数据进行打乱的方法通常有两种:
1)是使用uniform或者gaussian抽取随机值替换原特征;
2)是通过permutation的方式将原来的所有N个样本的第 i 个特征值重新打乱分布(相当于重新洗牌)。

xgboost怎么给特征评分?

在训练的过程中,通过Gini指数选择分离点的特征,一个特征被选中的次数越多,那么该特征评分越高。
特征评分可以看成是被用来分离决策树的次数

k折交叉验证中k取值多少有什么关系

在理想情况下,我们认为K折交叉验证可以降低模型的方差,从而提高模型的泛化能力,通俗地说,我们期望模型在训练集的多个子数据集上表现良好,要胜过单单在整个训练数据集上表现良好。(但实际上,由于我们所得到K折数据之间并非独立而存在相关性,K折交叉验证到底能降低多少方差还不确定,同时带来的偏差上升有多少也还存疑。)
完全不使用交叉验证是一种极端情况,即K=1。在这个时候,所以数据都被用于训练,模型很容易出现过拟合,因此容易是低偏差、高方差(low bias and high variance)。
留一法是K折的另一种极端情况,即K=n。随着K值的不断升高,单一模型评估时的方差逐渐加大而偏差减小。但从总体模型角度来看,反而是偏差升高了而方差降低了。
所以当K值在1到n之间的游走,可以理解为一种方差和偏差妥协的结果。
2017年的一项研究给出了另一种经验式的选择方法,作者建议k=log(n) 且保证n/K>3d ,n代表了数据量,d代表了特征数。
1、使用交叉验证的根本原因是数据集太小,而较小的K值会导致可用于建模的数据量太小,所以小数据集的交叉验证结果需要格外注意。建议选择较大的K值。
2、当模型稳定性较低时,增大K的取值可以给出更好的结果
3、相对而言,较大的K值的交叉验证结果倾向于更好。但同时也要考虑较大K值的计算开销。

xgboost在什么地方做的剪枝,怎么做的?

答:XGBoost 先从顶到底建立所有可以建立的子树,再从底到顶反向进行剪枝。

lightgbm和xgboost有什么区别?他们的loss一样么? 算法层面有什么区别?

lightgbm:基于Histogram的决策树算法;Leaf-wise的叶子生长策略;Cache命中率优化;直接支持类别特征(categorical Feature)
xgboost:预排序;Level-wise的层级生长策略;特征对梯度的访问是一种随机访问。

原文地址:https://www.cnblogs.com/hellojamest/p/11159219.html

时间: 2024-10-03 03:25:55

机器学习面试问题总结的相关文章

90天,从Java转机器学习面试总结

前 言 辗转几年Java开发,换了几份工作,没一个稳定的学习.工作过程.中间也相亲几次,都是没啥结果.换工作频繁也严重打乱了和姑娘接触的节奏.糟心工作连着遇到几次,也怪自己眼光有问题. 2018也找了2次工作,中间有4.5个月没有工作.看了个世界杯,看了个亚运会.也怪自己这段时间一直是换工作.找工作,节奏太乱了.当然,节奏不乱也可能不会比现在好吧.谁说的准呢? Java转机器学习--为啥呢? 主要有以下三方面原因: 1.Java感觉遇到瓶颈.Spring.Mytatis.设计模式等等,源码看不动

机器学习面试--算法评价指标

机器学习分为三个阶段: 第一阶段:学习模型.采用学习算法,通过对训练集进行归纳学习得到分类模型: 第二阶段:测试模型.将已经学习得到的分类模型用于测试集,对测试集中未知类别的实例进行分类. 第三阶段:性能评估.显然,通过测试集产生的分类未必是最佳的,这就导致对测试集的分类可能产生错误.而人们希望尽量得到信呢个最佳的分类模型,就是的对分类器性能评价至关重要.只有通过优秀的评价标准才能选择出性能更好的分类器. 不同机器学习算法的评价指标: 回归评估 回归是对连续的实数值进行预测,即输出值是连续的实数

机器学习面试--一句话概括传统ML算法

机器学习过程主要包括:数据的特征提取.数据预处理.训练模型.测试模型.模型评估改进等几部分 传统机器学习算法主要包括以下五类: 回归:建立一个回归方程来预测目标值,用于连续型分布预测 分类:给定大量带标签的数据,计算出未知标签样本的标签取值 聚类:将不带标签的数据根据距离聚集成不同的簇,每一簇数据有共同的特征 关联分析:计算出数据之间的频繁项集合 降维:原高维空间中的数据点映射到低维度的空间中 1 线性回归:找到一条直线预测目标值 2 逻辑回归:找到一条直线来分类数据 3 KNN:用距离度量最相

机器学习面试常见问题

(1) 无监督和有监督算法的区别? 有监督学习: 对具有概念标记(分类)的训练样本进行学习,以尽可能对训练样本集外的数据进行标记(分类)预测.这里,所有的标记(分类)是已知的.因此,训练样本的岐义性低. 无监督学习: 对没有概念标记(分类)的训练样本进行学习,以发现训练样本集中的结构性知识.这里,所有的标记(分类)是未知的.因此,训练样本的岐义性高.聚类就是典型的无监督学习. (2) SVM 的推导,特性?多分类怎么处理? SVM是最大间隔分类器,几何间隔和样本的误分次数之间存在关系,,其中 从

BAT机器学习面试1000题系列(41-45题)

41.线性分类器与非线性分类器的区别以及优劣 如果模型是参数的线性函数,并且存在线性分类面,那么就是线性分类器,否则不是.常见的线性分类器有:LR,贝叶斯分类,单层感知机.线性回归常见的非线性分类器:决策树.RF.GBDT.多层感知机SVM两种都有(看线性核还是高斯核)线性分类器速度快.编程方便,但是可能拟合效果不会很好非线性分类器编程复杂,但是效果拟合能力强 42.数据的逻辑存储结构(如数组,队列,树等)对于软件开发具有十分重要的影响,试对你所了解的各种存储结构从运行速度.存储效率和适用场合等

机器学习校招

作者:辛俊波链接:https://www.zhihu.com/question/29291174/answer/44180349来源:知乎著作权归作者所有,转载请联系作者获得授权. 非大大,作为刚经历过校招的人说几句.1)笔试:投过的所有机器学习的校招岗位中,没有一个,哪怕是一个笔试环节是涉及到机器学习的.清一色全是常规的计算机专业基础知识.以百度为例,全是大题,前面几道简单题,简答的程序语言基础,操作系统等.后面全是编程大题,主要考察数据结构和算法 2)面试:一开始大多都是介绍自己做过的项目,

我所知道的面试手册

达内 Java 企业面试题精选 达内 20 本教材里面的最后一本,偏 Java 语言和 Web 框架. Github 下载 Gitee 下载 传智播客面试宝典 传智播客总结的面试宝典,里面有 Android.C++.Java.PHP.大数据五种. CSDN 下载 数据结构与算法/leetcode/lintcode题解 本文档为数据结构和算法学习笔记,全文大致分为以下三大部分: Part I为数据结构和算法基础,介绍一些基础的排序/链表/基础算法 Part II为 OJ 上的编程题目实战,按题目的

文章集合--作者篇--中【转】

汪君: 机器学习预测乳腺肿瘤性质(1) 机器学习预测乳腺肿瘤性质(2) 机器学习预测乳腺肿瘤性质(3)——贝叶斯分类器 机器学习预测乳腺肿瘤性质(4)——神经网络 机器学习预测乳腺肿瘤性质(5) 机器学习预测乳腺肿瘤性质(6) 机器学习预测乳腺肿瘤性质(7) 订车宝: 七周:第一周数据分析师思维学习笔记 七周:第二周业务学习笔记(内附练习汽车经销店整车销售分析模型) 七周:第三周Excel学习 七周:第四周数据可视化学习笔记 七周:第五周MySQL学习笔记 七周:第六周统计学(基础)笔记 七周:

大想法-(收藏)

1. 第一弹 AI科技评论 ECCV2018|CornerNet:目标检测算法新思路(分享自知乎网) 视频中的目标检测与图像中的目标检测具体有什么区别 (分享自知乎网) 视频中的目标检测与图像中的目标检测具体有什么区别? (分享自知乎网) 目标检测一个最新综述[格式与一般的按照paper年份来组织的不同,是按照不同组件和方法论来组织] 深度学习大讲堂 - [CVPR2018]物体检测中的结构推理网络(分享自知乎网) https://mp.weixin.qq.com/s/9fFjVSiMg-Lwd