Jiahong 的个人博客

凡事预则立,不预则废


  • Home

  • Tags

  • Archives

  • Navigation

  • Search

ML——模型评估指标总结

各种模型评估指标总结,持续更新


分类模型

  • 参考:https://www.cnblogs.com/zongfa/p/9431807.html

Accuracy,准确率

  • 公式:$$ \text{Accuracy} = \frac{TP+TN}{TP+TN+FP+FN} $$
  • 直观,但不利于不平衡样本

Recall,召回率

  • 公式:$$ \text{Recall} = \frac{TP}{TP+FN} $$

Precision,精确率

  • 公式:$$ \text{Precision} = \frac{TP}{TP+FP} $$

F1 Score

  • 公式:$$ \text{F1 Score} = \frac{2 * \text{Precision} * \text{Recall}}{\text{Precision}+\text{Recall}} $$
  • 综合考虑模型”求精“和”求全“的能力
  • 关键词:F1-Score, F1 Score, F1 分数

AUC

  • 形式化定义:AUC是ROC曲线下方的面积,其中ROC曲线的横坐标是伪阳性率(也叫假正类率,False Positive Rate),纵坐标是真阳性率(真正类率,True Positive Rate)
  • 本质:任意取两个样本,一个正样本和一个负样本( \( \forall x^+, x^-\) ),模型预测正样本为正的概率分为 \(Score_\theta(y=1|x^+)\),模型预测正样本为正的概率分为 \(Score_\theta(y=1|x^-)\),则AUC为:
    $$ AUC_\theta = P(Score_\theta(y=1|x^+)>Score_\theta(y=1|x^-))$$
  • 真实实现时,可以统计所有正负样本对,若正样本预估值大于负样本,则累计分数+1,最后用累计分数除以所有可能的正负样本对数量
    $$ AUC_\theta = \frac{Count(S_+>S_-)}{Count(S_+) * Count(S_-)}$$
  • 具体代码实现:
    • 将样本按照预估分数倒序排列,从大到小
    • 定义四个变量:正样本总数 \(M\),负样本总数 \(N\),已访问负样本数量 \(X=0\),正样本大于负样本的样本对数量 \(Z=0\)
    • 依次访问所有样本:
      • 若为正样本,则 \(Z = Z + (N-X)\)
      • 若为负样本,则 \(X = X + 1\)
    • 最后计算: \(AUC = \frac{Z}{M * N}\)

回归模型

  • 参考:https://www.cnblogs.com/HuZihu/p/10300760.html
  • 参考:https://blog.csdn.net/guolindonggld/article/details/87856780

MSE

  • MSE (Mean Square Error,均方误差)
  • 也常用作损失函数
    $$\text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2$$
    • \(n\):样本数量
    • \(y_i\):第 \(i\) 个样本的真实值
    • \(\hat{y}_i\):第 \(i\) 个样本的预测值

RMSE

  • RMSE (Root Mean Square Error,根均方误差)
    $$\text{RMSE} = \sqrt{\frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2}$$

MAE

  • MAE (Mean Absolute Error,平均绝对误差)
    $$\text{MAE} = \frac{1}{n} \sum_{i=1}^{n} |y_i - \hat{y}_i|$$

MAPE

  • MAPE (Mean Absolute Percentage Error,平均绝对百分比误差)
    $$\text{MAPE} = \frac{1}{n} \sum_{i=1}^{n} \left| \frac{y_i - \hat{y}_i}{y_i} \right| \times 100%$$
    • 注:这个指标对分母要求很高,分母存在极小值时指标波动会非常大
      • 比如当 \(y_i=0\) 时,MAPE 无定义,这是其核心缺陷

SMAPE

  • SMAPE (Symmetric Mean Absolute Percentage Error,对称平均绝对百分比误差)
    $$\text{SMAPE} = \frac{1}{n} \sum_{i=1}^{n} \frac{|y_i - \hat{y}_i|}{\frac{1}{2}(|y_i| + |\hat{y}_i|)} \times 100%$$
    • 结果范围为 \([0, 200%]\)
  • SMAPE 也有简化版定义:分母直接用 \(|y_i| + |\hat{y}_i|\),此时公式为
    $$\text{SMAPE} = \frac{2}{n} \sum_{i=1}^{n} \frac{|y_i - \hat{y}_i|}{|y_i| + |\hat{y}_i|} \times 100%$$
    • 结果范围为 \([0, 100%]\)
  • 两种形式均常见,均被广泛使用,需根据场景选择

WMAPE

  • WMAPE (Weighted Mean Absolute Percentage Error,加权平均绝对百分比误差)
    $$\text{WMAPE} = \frac{\sum_{i=1}^{n} |y_i - \hat{y}_i|}{\sum_{i=1}^{n} |y_i|} \times 100%$$
  • WMAPE 也有按自定义权重 \(w_i\) 的通用形式:
    $$\text{WMAPE} = \frac{\sum_{i=1}^{n} w_i |y_i - \hat{y}_i|}{\sum_{i=1}^{n} w_i |y_i|} \times 100%$$
    • 默认权重 \(w_i=1\) 时退化为之前的公式
    • WMAPE 解决了 MAPE 中 \(y_i=0\) 无定义的问题
  • WMAPE 是 MAPE 的加权改进版,避免了分母为 0 的问题,更适合实际业务场景

排序模型

  • 参考:https://www.cnblogs.com/by-dream/p/9403984.html

DCG

  • DCG(Discounted Cumulative Gain,累计收益折扣)
  • 核心作用:衡量排序结果的质量,考虑位置对价值的衰减(越靠前的结果权重越高)
    $$\text{DCG}_p = \sum_{i=1}^{p} \frac{\text{rel}_i}{\log_2(i + 1)}$$
  • 等价形式(更常用,便于与 IDCG 对齐):
    $$\text{DCG}_p = \text{rel}_1 + \sum_{i=2}^{p} \frac{\text{rel}_i}{\log_2(i)}$$
    • \(p\): 排序结果的截断位置(如 Top-10 则 \(p=10\))
    • \(\text{rel}_i\): 第 \(i\) 个位置结果的相关性分数(通常为非负整数,如0=不相关、1=相关、2=高度相关)
    • \(\log_2(i+1)$/$\log_2(i)\): 位置折扣因子,体现“越靠前的结果越重要”的特性
  • 补充:DCG 还有另一种常见形式(引入指数缩放相关性):
    $$\text{DCG}_p = \sum_{i=1}^{p} \frac{2^{\text{rel}_i} - 1}{\log_2(i + 1)}$$
    • 该形式会放大高相关性结果的权重,适用于对“高度相关结果”更敏感的场景(如搜索排序)

NDCG

  • NDCG(Normalized Discounted Cumulative Gain,归一化累计收益折扣)
  • 核心作用:将 DCG 归一化到 [0,1] 区间,消除不同查询/任务间的结果尺度差异,便于跨场景比较
    $$\text{NDCG}_p = \frac{\text{DCG}_p}{\text{IDCG}_p}$$
    • \(\text{IDCG}_p\)(Ideal DCG,理想累计收益折扣):将所有结果按相关性从高到低完美排序后得到的 \(\text{DCG}_p\),即当前数据集下的最大可能 DCG 值,计算公式为:
      $$\text{IDCG}_p = \sum_{i=1}^{|REL_p|} \frac{\text{rel}^*_i}{\log_2(i + 1)} \quad (\text{或对应DCG的等价形式})$$
      • \(\text{rel}^*_i\) 为第 \(i\) 个位置的理想相关性分数,\(|REL_p|\) 为前 \(p\) 个位置中理想排序的结果数量
  • NDCG 的取值范围为 \([0,1]\): \(\text{NDCG}_p=1\) 表示排序结果完全理想,\(\text{NDCG}_p=0\) 表示排序结果完全无价值;
  • 当所有结果均无相关性(\(\text{rel}_i=0\))时,\(\text{DCG}_p=\text{IDCG}_p=0\),此时约定 \(\text{NDCG}_p=1\);
  • DCG/NDCG 是排序任务(如推荐系统、搜索引擎)的核心评估指标, \(p\) 的选择需贴合业务场景(如推荐系统常用 Top-5/Top-10,搜索常用 Top-20)

AP(Average Precision)与 MAP(Mean Average Precision)

  • AP 和 mAP 指标可参考:

校准模型

  • 参考:推荐系统(2)—— 评估指标
  • 参考:阿里妈妈展示广告预估校准技术演进之路

COPC

  • COPC(Click over Predicted Click)
    • COPC = 实际的点击率/模型预测的点击率
    • COPC 主要衡量model整体预估的偏高和偏低,同样越接近1越好,一般情况下在1附近波动
    • COPC 指标在展示广告上应用多一些

PCOC

  • PCOC(Predicted Click over Click)
    • PCOC = 模型预估的点击率/实际点击率,与COPC用途相同
    • COPC的倒数

PCOC指标是校准之后的点击率与后验点击率(近似真实概率)的比值,越接近于1,意味着在绝对值上越准确,大于1为高估,小于1为低估,是一种常用的高低估评价指标。但是PCOC存在一定局限性,举个例子:2万个样本,其中1万个样本的预估概率是0.2,后验概率是0.4,计算出PCOC是0.2/0.4=0.5,是显著低估的,另1万个样本PCOC是0.8/0.6= 1.3,明显是高估的。所以校准效果并不好,但是样本放一起看,校准后概率是(0.2+0.8)/2=0.5,后验概率是(0.4+0.6)/2=0.5,整体PCOC是1.0,表现完全正常。所以单一PCOC指标不能表征样本各维度下的校准水平。


净胜率模型

  • ANLP
    • 参考:论文《Scalable Bid Landscape Forecasting in Real-time Bidding》
    • 链接:https://arxiv.org/pdf/2001.06587.pdf

ML——直推式学习和归纳式学习

本文解释 直推式学习(Transductive Learning) 和 归纳式学习(Inductive Learning) 的区别


归纳式学习 (Inductive Learning)

  • 一句话定义 :通过训练数据学习一个通用的模型 ,然后将该模型应用于未知的测试数据
  • 目标 :从具体样本中归纳(名字来源)出一般规律,适用于任何未来的数据
  • 特点 :
    • 训练阶段和测试阶段是分开的
    • 模型在训练时不知道测试数据的具体情况
  • 典型场景 :大多数监督学习任务(如图像分类、文本分类等)
  • 核心特点 :训练时测试数据不可见

直推式学习 (Transductive Learning)

  • 一句话定义 :利用训练数据和特定的测试数据(未标注)共同学习,直接(名字来源)预测这些测试数据的标签
  • 目标 :针对当前已知的测试数据优化预测,而非构建通用模型
  • 特点 :
    • 训练时已知测试数据的特征(但无标签),利用这些信息优化预测
    • 模型仅适用于当前的测试数据,不能直接泛化到新数据
  • 典型场景 :半监督学习、图节点分类(如社交网络用户分类)
  • 核心特点 :训练时测试数据可见

附录:举例-垃圾邮件分类

  • 任务定义 :判断邮件是否为垃圾邮件

归纳式学习

  • 仅用已标注的训练数据(带“垃圾/正常”标签的邮件)训练一个模型(如SVM、神经网络)
  • 将模型应用于未来收到的任何新邮件

直推式学习

  • 同时利用已标注邮件和未标注邮件的特征分布(如词频、发件人)训练模型
  • 模型发现未标注邮件中某些特征与训练数据中的垃圾邮件相似,直接预测它们的标签
  • 特别说明 :模型针对这批特定的测试邮件优化 ,但不保证对新邮件的效果

为什么需要直推式学习?

  • 一般来说,大部分场景都使用归纳式学习即可
  • 当测试数据分布与训练数据分布不同时,直推式学习可以通过利用测试数据的特征分布提升当前任务的性能,但牺牲泛化性
  • 特别地,当训练数据和测试数据本身具有一定结构(如图数据、时空数据)时,直推式学习可以利用这些结构信息对无标签的测试数据做预测

Math——假设检验

本文介绍各种常见假设检验方法及使用示例

  • 参考链接1:知乎:T检验、F检验、卡方检验详细分析及应用场景总结
  • 参考链接2:知乎视频:5分钟带你了解卡方检验

卡方检验

《概率论与数理统计》

p-value的含义

  • 在假设检验中,对p-value的的一种直观理解:在假设 \(H_0\):假设目标样本属于某个正太分布,这个样本不是从这个正太分布中采样的概率就是p值(即p值的本质是一个概率)
    • 进一步的理解,已知一个正太分布和一个目标样本,那么这个目标样本对应的p值就是:重新在这个正太分布中重新采样一个新样本,新样本离中心位置 \(u_0\) 的距离大于等于目标样本的概率(该概率就是正太分布的两边区间积分和)
    • p值越小,说明这个目标样本越不可能是从这个正太分布采样出来的,越应该拒绝原假设 \(H_0\) (即越应该接受 \(H_A\)

Math——奇异值分解-SVD

本文从不同角度给出奇异值分解的物理意义

  • 参考知乎回答1:奇异值的物理意义是什么?
  • 参考知乎回答2:人们是如何想到奇异值分解的?

公式说明

$$A=U\Sigma V^{T}$$

  • \(U,V\) 都是正交矩阵, \(\Sigma\) 是对角矩阵,对角上的元素是矩阵 \(A\) 的奇异值
  • 若保留对角元素最大的K个值
    • \(K=r=Rank(A)\) 时为紧奇异值分解,对应的是无损压缩,此时由于奇异值保留数量与原始矩阵相同,能做到对原始矩阵A的完全还原
    • \(K< r=Rank(A)\) 时为截断奇异值分解,对应的是有损压缩,此时由于奇异值保留数量比原始矩阵的小,做不到对原始矩阵A的完全还原,但是如果K足够大就能做到对矩阵A的较完美近似

图像处理方面

  • 直观上可以理解为奇异值分解是将矩阵分解为若干个秩一矩阵之和,用公式表示就是:
    $$A=\sigma_{1}u_{1}v_{1}^{T}+\sigma_{2}u_{2}v_{2}^{T}+…+\sigma_{r}u_{r}v_{r}^{T}$$
    • 式子中每一项的系数 \(\sigma\) 就是奇异值
    • \(u,v\) 都是列向量,每一个 \(uv^{T}\) 都是秩为1的矩阵
    • 奇异值按照从小到大排列
  • 从公式中按照从大到小排序后,保留前面系数最大的项目后效果
    • 对于一张450x333的图片,只需要保留前面的50项即可得到相当清晰的图像
    • 从保留项1到50,图片越来越清晰
  • 结论:
    • 奇异值越大的项,越能体现出来图片的效果 ,奇异值隐含着某种对于A矩阵来说很重要的信息
    • 加权的秩一矩阵能体现整个大矩阵的值,奇异值就是对应秩一矩阵对于A矩阵的权重

线性变换方面

几何含义

  • 对于任何的一个矩阵,我们要找到一组两两正交单位向量序列,使得矩阵作用在此向量序列上后得到新的向量序列保持两两正交.奇异值的几何含义为:这组变换后的新的向量序列的长度

更直观的几何含义

  • 公式:
    $$\mathbb{E}_{m}={y\in C^{m}: y=Ax, x\in C^{n},\left | x\right |_{2}=1}$$
  • 二维矩阵A:
    • 矩阵A将二维平面中的单位圆变换为椭圆,而两个奇异值正好是椭圆的半轴长度.
  • m维矩阵
    • 矩阵A将高维平面中的单位球变换为超椭球,矩阵的奇异值恰好就是超椭球的每条半轴长度.

奇异值分解的降维理解

代码编写

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    ##encoding=utf-8
    import numpy as np

    A = np.array([[4, 5, 6], [4, 5, 6], [8, 10, 12], [4, 5, 6]])

    print("原始矩阵:")
    print(A)

    U, Sigma, Vt = np.linalg.svd(A)
    U = np.array(U)
    Sigma = np.array(Sigma)
    Vt = np.array(Vt)

    print("分解后的原始U,S,V:")
    print(U)
    Sigma_ = np.zeros((4, 3), dtype=np.float64)
    Sigma_[:3][:3] = np.diag(Sigma)
    print Sigma_
    print(Vt)

    # 不做任何处理,直接恢复原始矩阵
    A_ = np.dot(np.dot(U, Sigma_), Vt)
    print(A_)

    # 原始矩阵的秩为1,所以可以拆解到只剩下一个奇异值,压缩到一维,也能完整恢复原始矩阵,实现将4x3的矩阵变成两个向量+一个数字,当矩阵维度变大时,这里的压缩会更加明显
    U = U[:, :1]
    Sigma_ = Sigma_[:1, :1]
    Vt = Vt[:1, :]

    print("降维后的U,S,V:")
    print(U)
    print(Sigma_)
    print(Vt)
    A_ = np.dot(np.dot(U, Sigma_), Vt)
    print("降维后的恢复矩阵,与原矩阵相同:")
    print(A_)
  • 结果

    原始矩阵:
    [[ 4 5 6]
    [ 4 5 6]
    [ 8 10 12]
    [ 4 5 6]]
    分解后的原始U,S,V:
    [[-3.77964473e-01 -9.25820100e-01 1.52792960e-16 0.00000000e+00]
    [-3.77964473e-01 1.54303350e-01 9.12870929e-01 0.00000000e+00]
    [-7.55928946e-01 3.08606700e-01 -3.65148372e-01 -4.47213595e-01]
    [-3.77964473e-01 1.54303350e-01 -1.82574186e-01 8.94427191e-01]]
    [[2.32163735e+01 0.00000000e+00 0.00000000e+00]
    [0.00000000e+00 1.22295087e-15 0.00000000e+00]
    [0.00000000e+00 0.00000000e+00 5.18334466e-32]
    [0.00000000e+00 0.00000000e+00 0.00000000e+00]]
    [[-0.45584231 -0.56980288 -0.68376346]
    [ 0.02454097 0.75988299 -0.64959647]
    [-0.88972217 0.31289378 0.3324033 ]]
    [[ 4. 5. 6.]
    [ 4. 5. 6.]
    [ 8. 10. 12.]
    [ 4. 5. 6.]]
    降维后的U,S,V:
    [[-0.37796447]
    [-0.37796447]
    [-0.75592895]
    [-0.37796447]]
    [[23.21637353]]
    [[-0.45584231 -0.56980288 -0.68376346]]
    降维后的恢复矩阵,与原矩阵相同:
    [[ 4. 5. 6.]
    [ 4. 5. 6.]
    [ 8. 10. 12.]
    [ 4. 5. 6.]]

Math——样本方差和总体方差的关系

本文介绍随机变量样本均值方差和整体均值方差的关系,同时还介绍样本和均值的方差和总体方差的关系

  • 其他参考链接:在统计学里如何理解样本均值的方差等于总体方差➗n? - 蘇雲的回答 - 知乎

样本方差与总体方差的关系

  • 其他证明方式:
    • 上式中,如果总体方差未知 ,想要用样本方差来作为总体方差的无偏估计 ,则样本方差的定义是应该是
      $$ S^2 = \frac{1}{n-1}\sum_i^n(X_i-\bar{X})^2$$
      • 注:分母必须是 \(n-1\) 时,样本方差才是总体方差的无偏估计

样本方差为什么要除以n-1?

  • 样本方差的定义:
    $$
    \sigma^2 \approx S^2 = \frac{1}{n-1}\sum_i^n(X_i-\bar{X})^2
    $$
  • 为什么样本方差是乘以 \(\frac{1}{n-1}\) 而不是 \(\frac{1}{n}\) ?
    • 因为这样使用 \(\frac{1}{n}\) 会低估总体方差,此时样本方差不是总体方差的无偏估计
    • 样本方差低估了总体方差的原因是因为从总体里面抽出来的数据会更倾向于集中,极端情况下,一个样本对应的方差为0
  • 换个视角想,是因为我们不知道总体的均值,所以计算方差时使用的均值也是从样本中求平均得到的,这使得我们基于该均值得到的方差不够离散(因为使用了样本均值,所以自由度需要减一),也就是低估了总体方差
    • 怎么理解自由度?
      • 采样一个样本以后无法计算方差,此时方差为0,因为此时均值就等于样本本身,此时自由度为0
      • 采样两个样本以后得到的方差只根第二个样本到第一个样本的距离有关(样本均值与这两个样本强相关),此时自由度为1
      • 当采样的样本数非常多(假设为n)时,实际上单个样本与均值的关系很小了,此时自由度为n-1
  • 当已知总体均值 \(\mu\) 时(个人理解:这里的 \(\mu\) 可以是其他采样方式下获得的近似均值,只要不跟当前用于计算方差的样本相关即可),样本方差可以使用:
    $$
    \sigma^2 \approx S^2 = \frac{1}{n-1}\sum_i^n(X_i-\mu)^2
    $$
  • 样本方差经过 \(\frac{1}{n-1}\) 修正以后可以用来估计总体方差(修正以后是总体方差的无偏估计)
    • 这个修正叫做贝塞尔修正
  • 证明 from :Bilibili-样本方差为什么除以n-1?

  • 单样本均值和多样本均值的关系

    问题定义

    • 考虑以下采样方式
      • 集合X :每次采样 B个样本 得到的样本集合
      • 集合Y :每次采样 1个样本 得到的样本集合
    • 问:多次采样时,集合X和B的均值和方差关系是什么?
      • 即:如果我们重复多次进行这样的采样(每次采B个或1个),那么:这两种采样方式得到的样本均值的期望(即平均值的平均值)和样本均值的方差(即平均值的波动程度)之间有什么关系?

    假设与符号定义

    • 假设我们从一个总体中采样,总体的均值为 \(\mu\),方差为 \(\sigma^2\)
    • 集合X :
      • 每次采样 B个样本 :\(X_1, X_2, \dots, X_B\)
      • 计算这B个样本的均值:\(\bar{X}_A = \frac{1}{B}\sum_{i=1}^B X_i\)
    • 集合Y :
      • 每次采样 1个样本 :\(Y_1\)
      • 其“均值”就是它自己:\(\bar{X}_B = Y_1\)
    • 我们重复多次这样的采样过程,得到一系列的 \(\bar{X}_A\) 和 \(\bar{X}_B\)

    均值关系

    • 集合X 的样本均值的期望:
      $$
      E[\bar{X}_A] = E\left[\frac{1}{B}\sum_{i=1}^B X_i\right] = \frac{1}{B} \sum_{i=1}^B E[X_i] = \frac{1}{B} \cdot B \mu = \mu
      $$
    • 集合Y 的样本均值的期望:
      $$
      E[\bar{X}_B] = E[Y_1] = \mu
      $$
    • 结论:两种采样方式得到的样本均值的期望是相同的 ,都等于总体均值 \(\mu\)

    方差关系

    • 集合X 的样本均值的方差:
      $$
      \text{Var}(\bar{X}_A) = \text{Var}\left(\frac{1}{B}\sum_{i=1}^B X_i\right) = \frac{1}{B^2} \sum_{i=1}^B \text{Var}(X_i) = \frac{1}{B^2} \cdot B \sigma^2 = \frac{\sigma^2}{B}
      $$
    • 集合Y 的样本均值的方差:
      $$
      \text{Var}(\bar{X}_B) = \text{Var}(Y_1) = \sigma^2
      $$
    • 结论:集合X 的样本均值的方差是 \(\frac{\sigma^2}{B}\),集合Y 的样本均值的方差是 \(\sigma^2\)
      • 也就是说,集合X 的样本均值的方差更小,是集合Y 的 \(\frac{1}{B}\)
    • 直观理解
      • 均值方面:无论你是采1个还是采B个,平均来看,它们的中心位置(期望)都是一样的,都是总体的均值
      • 方差方面:采B个样本求平均,相当于把单个样本的“噪声”给“平均掉”了,因此波动更小,方差更小;而采1个样本,没有“平均”的过程,波动就更大,方差也就更大

    附录:Python 中计算标准差/方差的默认实现

    • 在进行数据归一化(如 Z-score 标准化)时,计算标准差的分母是 \(n\)(总体标准差)还是 \(n-1\)(样本标准差,即无偏估计),在不同的 Python 科学计算库中默认行为是不同的
    • 各 Python 库的默认行为总结:
      • 1)NumPy (np.std) :默认分母为 \(n\)(即 ddof=0)
        • 注:这里控制分母的参数通常称为 ddof(Delta Degrees of Freedom,自由度偏差),分母的计算公式为 \(N - ddof\)
      • 2)Pandas (pd.Series.std / pd.DataFrame.std) :默认分母为 \(n-1\)(即 ddof=1)
      • 3)PyTorch (torch.std) :默认分母为 \(n-1\)(即 unbiased=True 或 correction=1)
        • 注:修改 unbiased=False 即可得到分母为 \(n\) 的结果
      • 注:各个库的默认行为不同可能会导致一些意想不到的问题
    • 在机器学习中进行 Z-score 归一化(\(\frac{x - \mu}{\sigma}\))时,通常数据量 \(n\) 都比较大,此时 \(n\) 和 \(n-1\) 的差别微乎其微
      • 但为了保证训练集和测试集处理逻辑的绝对一致性,建议在代码中显式指定参数(例如统一写死 ddof=0 或 unbiased=False),避免因为在不同库之间切换数据格式(如从 Pandas 转换到 PyTorch Tensor)而引入隐蔽的计算差异

    测试代码

    • 以下是包含 NumPy、Pandas 和 PyTorch 计算 \(n\) 和 \(n-1\) 标准差的完整测试代码
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      import numpy as np
      import pandas as pd
      import torch

      def test_std_behaviors():
      # 准备相同的测试数据
      data_list = [1.0, 2.0, 3.0, 4.0, 5.0]

      print("-" * 40)
      print("NumPy 标准差测试")
      print("-" * 40)
      arr = np.array(data_list)
      # NumPy 默认 ddof=0,分母为 n
      np_std_n = np.std(arr)
      # NumPy 设置 ddof=1,分母为 n-1
      np_std_n_minus_1 = np.std(arr, ddof=1)
      print(f"NumPy 默认分母 (n) : {np_std_n:.4f}")
      print(f"NumPy 指定分母 (n-1) : {np_std_n_minus_1:.4f} (使用 ddof=1)")

      print("\n" + "-" * 40)
      print("Pandas 标准差测试")
      print("-" * 40)
      series = pd.Series(data_list)
      # Pandas 默认 ddof=1,分母为 n-1
      pd_std_n_minus_1 = series.std()
      # Pandas 设置 ddof=0,分母为 n
      pd_std_n = series.std(ddof=0)
      print(f"Pandas 默认分母 (n-1): {pd_std_n_minus_1:.4f}")
      print(f"Pandas 指定分母 (n) : {pd_std_n:.4f} (使用 ddof=0)")

      print("\n" + "-" * 40)
      print("PyTorch 标准差测试")
      print("-" * 40)
      tensor = torch.tensor(data_list)
      # PyTorch 默认无偏估计 (unbiased=True),分母为 n-1
      # 注:在较新版本的 PyTorch 中,也可以使用 correction=1
      pt_std_n_minus_1 = torch.std(tensor)
      # PyTorch 设置有偏估计 (unbiased=False),分母为 n
      # 注:在较新版本的 PyTorch 中,也可以使用 correction=0
      pt_std_n = torch.std(tensor, unbiased=False)
      print(f"PyTorch 默认分母 (n-1): {pt_std_n_minus_1:.4f}")
      print(f"PyTorch 指定分母 (n) : {pt_std_n:.4f} (使用 unbiased=False)")

      if __name__ == "__main__":
      test_std_behaviors()


      # ----------------------------------------
      # NumPy 标准差测试
      # ----------------------------------------
      # NumPy 默认分母 (n) : 1.4142
      # NumPy 指定分母 (n-1) : 1.5811 (使用 ddof=1)
      #
      # ----------------------------------------
      # Pandas 标准差测试
      # ----------------------------------------
      # Pandas 默认分母 (n-1): 1.5811
      # Pandas 指定分母 (n) : 1.4142 (使用 ddof=0)
      #
      # ----------------------------------------
      # PyTorch 标准差测试
      # ----------------------------------------
      # PyTorch 默认分母 (n-1): 1.5811
      # PyTorch 指定分母 (n) : 1.4142 (使用 unbiased=False)

    Math——概率密度函数的理解

    本文介绍概率密度函数的理解


    概率密度函数的定义

    • 概率密度函数(Probability Density Function, PDF)是概率论和统计学中用来描述连续型随机变量的概率分布的一种函数。对于一个连续型随机变量 \(X\),其概率密度函数 \(f(x)\) 具有以下性质:

      • 非负性 :对于所有的实数 \(x\),有 \(f(x) \geq 0\)
      • 归一化 :在整个可能值域内, \(f(x)\) 的积分等于1,即 \(\int_{-\infty}^{\infty} f(x) , dx = 1\)
      • 概率计算 :如果 \(a < b\),那么随机变量 \(X\) 落在区间 \([a, b]\) 内的概率可以通过 \(f(x)\) 在该区间上的积分来计算,即 \(P(a \leq X \leq b) = \int_{a}^{b} f(x) , dx\)
    • 需要注意的是,概率密度函数 \(f(x)\) 在某一点的值并不直接表示该点的概率,因为对于连续型随机变量来说,取任何一个具体值的概率实际上是0。相反, \(f(x)\) 更多地用于描述随机变量落在某个区间的概率大小。通过观察 \(f(x)\) 的形状,可以了解随机变量取值的集中趋势和分散程度等特征


    概率密度函数在某点的值 \( f(x_0) = \frac{1}{2} \) 的意义

    • 当我们说概率密度函数 \( f(x) \) 在某点 \( x_0 \) 的值等于 \( \frac{1}{2} \),即 \( f(x_0) = \frac{1}{2} \),其意义如下:

    概率密度函数的值

    • 概率密度函数 \( f(x) \) 在某点 \( x_0 \) 的值 \( f(x_0) \) 并不直接表示在 \( x_0 \) 点取得某个具体值的概率。对于连续型随机变量,在某个具体点取值的概率实际上是零,即:
      $$ P(X = x_0) = 0 $$

    概率密度的意义

    • 概率密度函数 \( f(x) \) 在点 \( x_0 \) 的值 \( f(x_0) \) 表示在 \( x_0 \) 附近的值的相对可能性。更具体地说,它表示在 \( x_0 \) 附近的一个小区间的长度和该区间内的概率的比值。比如,对于一个非常小的区间 \( [x_0 - \epsilon, x_0 + \epsilon] \),其概率可以近似表示为:
      $$ P(x_0 - \epsilon \leq X \leq x_0 + \epsilon) \approx f(x_0) \cdot 2\epsilon $$

    例子

    • 假设一个随机变量 \( X \) 的概率密度函数在某点 \( x_0 \) 处为 \( \frac{1}{2} \),即 \( f(x_0) = \frac{1}{2} \) 。这意味着在 \( x_0 \) 附近的一个小区间内的概率可以近似计算。例如,对于一个非常小的区间 \( [x_0 - 0.01, x_0 + 0.01] \),其概率可以近似为:
      $$ P(x_0 - 0.01 \leq X \leq x_0 + 0.01) \approx \frac{1}{2} \cdot 0.02 = 0.01 $$

    总结

    • 概率密度函数 \( f(x) \) 在某点 \( x_0 \) 的值 \( f(x_0) = \frac{1}{2} \) 并不表示在 \( x_0 \) 处取值的概率,而是表示在 \( x_0 \) 附近的值的相对可能性
    • 对于连续型随机变量,在某个具体点取值的概率是零
    • 概率密度函数的值可以用于近似计算在某个小区间内的概率

    Math——调和级数的和

    调和级数的和是发散的,并不收敛,但是这又是一个非常常用的级数,本文总结了调和级数的和的求法


    一个事实

    • 调和级数的和与 n 的自然对数的差值收敛到欧拉-马歇罗尼常数
      $$
      \begin{align}
      lim_{n \to \infty}(\sum_{i=1}^{n}\frac{1}{i} - ln(n)) = \gamma
      \end{align}
      $$
      • \(\gamma\) 为欧拉-马歇罗尼常数
        • (欧拉常数又称欧拉-马斯克若尼常数,近似值为γ≈0.57721 56649 01532 86060 65120 90082 40243 10421 59335)

    证明

    • 事实上,调和级数的和为
      $$
      \begin{align}
      \sum_{i=1}^{n}\frac{1}{i} = ln(n) + \gamma + \epsilon_{n}
      \end{align}
      $$
      • \(\gamma\) 为欧拉-马歇罗尼常数
      • \(\epsilon_{n}\) 约等于 \(\frac{1}{2n}\),随着n的不断增大, \(\epsilon_{n}\) 趋于0

    补充

    • 两个不同的调和数之间的差值永远不是整数
    • 除了n=1时以外,没有任何一个调和数是整数

    Math——马尔可夫链及其平稳分布


    核心定义

    • 一句话定义:平稳分布在马尔可夫链长期演化后系统达到的稳态概率分布
    • 对于一个离散时间马尔可夫链(Markov Chain) ,若存在一个概率分布 \(\pi\) 满足以下方程:
      $$
      \pi = \pi P
      $$
      • \(P\) 是转移概率矩阵(\(P_{ij}\) 表示从状态 \(i\) 转移到状态 \(j\) 的概率)
      • \(\pi\) 是行向量,表示每个状态的概率
    • 则称 \(\pi\) 为该马尔可夫链的平稳分布(Stationary Distribution)。直观上,这意味着系统达到 \(\pi\) 后,状态分布不再随时间改变

    关键性质

    • 存在性与唯一性 :

      • 若马尔可夫链是不可约马尔可夫链(Irreducible Markov Chain)(不可约马尔可夫链的所有状态互通),且满足正常返(Positive Recurrent)特性(即每个状态会被无限次访问),则平稳分布存在且唯一
      • 对于有限状态的不可约链,平稳分布一定存在
    • 长期行为 :

      • 无论初始分布如何,若链满足一定条件(如非周期性),长期后的状态分布会收敛到平稳分布:
        $$
        \lim_{n \to \infty} \mu P^n = \pi
        $$
        其中 \(\mu\) 是初始分布
    • 细致平衡条件(Detailed Balance):

      • 若分布 \(\pi\) 满足 \(\pi_i P_{ij} = \pi_j P_{ji}\)(对所有 \(i,j\)),则 \(\pi\) 是平稳分布。满足此条件的链称为可逆马尔可夫链

    计算方法

    • 解线性方程组 :
      • 通过 \(\pi = \pi P\) 和 \(\sum_i \pi_i = 1\) 联立求解
      • 例如,对两状态链:
        $$
        \begin{cases}
        \pi_1 = \pi_1 P_{11} + \pi_2 P_{21} \\
        \pi_2 = \pi_1 P_{12} + \pi_2 P_{22} \\
        \pi_1 + \pi_2 = 1
        \end{cases}
        $$
    • 其他求解方法:特征向量法

    例子

    • 假设天气模型(晴/雨)的转移矩阵,描述了晴雨天转换的概率:
      $$
      P = \begin{bmatrix}
      0.9 & 0.1 \\
      0.5 & 0.5
      \end{bmatrix}
      $$
    • 解 \(\pi P = \pi\) 得 \(\pi = [\frac{5}{6}, \frac{1}{6}]\),即长期下有5/6概率为晴天,1/6为雨天

    Math——辛普森悖论

    本文介绍辛普森悖论


    辛普森悖论

    • 辛普森悖论指的是在分组比较中占优的一方,在合并数据后反而处于劣势的现象

    药物效果示例

    • 场景场景 :比较两种药物(A 和 B)对轻症和重症患者的治愈率

    • 分组数据 :

      • 轻症患者组 :
        • 药 A:治疗 10 人 ,治愈 9 人 -> 治愈率 90%
        • 药 B:治疗 100 人 ,治愈 80 人 -> 治愈率 80%
      • 重症患者组 :
        • 药 A:治疗 100 人 ,治愈 30 人 -> 治愈率 30%
        • 药 B:治疗 10 人 ,治愈 2 人 -> 治愈率 20%
    • 分组结论 :

      • 轻症组:药 A 的治愈率(90%)> 药 B(80%)
      • 重症组:药 A 的治愈率(30%)> 药 B(20%)
    • 合并数据 :

      • 药 A:总治愈 39 人(9 + 30),总治疗 110 人 -> 治愈率 35.5%
      • 药 B:总治愈 82 人(80 + 2),总治疗 110 人 -> 治愈率 74.5%
    • 悖论出现 :

    • 尽管药 A 在每个分组的治愈率都更高,但合并后药 B 的总治愈率却显著优于药 A。这是因为药 B 主要用于治愈率高的轻症患者(样本量 100 vs. 10),而药 A 更多用于治愈率低的重症患者(样本量 100 vs. 10),导致整体结果反转

    核心原因 :

    • 数据分组中存在混杂变量(此处为病情严重程度),且各组样本量差异巨大,合并时权重不同引发悖论

    什么药是真正优秀的?

    • 药 A才是真正疗效更好的,因为在任何场景下(不论轻症还是重症下),都是药 A 效果更好,之所以合并到一起统计出现悖论,是因为医生开药时存在刻意倾向导致的,给轻症患者更多的开了药 B,这相当于强行提高了药 B 的治愈率
    • 其他类似问题也出现在不同学院男女录取率上

    数据存储——Parquet文件格式简单介绍


    Parquet 整体说明

    • Parquet(Apache Parquet)是一种列式存储的二进制文件格式,专为大数据处理场景设计,具有高效压缩和编码特性
    • Parquet 尤其适合分析型工作负载,能显著提升查询速度并降低存储成本

    Parquet 文件结构

    • Parquet文件由多个行组(Row Groups)组成,每个行组包含:
    • 列块(Column Chunks) :存储实际列数据
    • 元数据 :记录统计信息(如min/max),用于加速查询

    Parquet 文件读取示例

    • Spark :df.write.parquet("path") / spark.read.parquet("path")
    • Pandas :pd.read_parquet("file.parquet", engine="pyarrow")
    • Hive :CREATE TABLE ... STORED AS PARQUET

    附录:文件读取和分析示例

    • 使用 Python 代码读取并解析文件格式
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      import pandas as pd

      def read_and_inspect_parquet(file_path):
      try:
      # 读取Parquet文件
      df = pd.read_parquet(file_path)

      print("成功读取Parquet文件!")
      print("\n===== 数据基本信息 =====")
      df.info() # 显示数据框的基本信息,包括列名、数据类型、非空值数量等

      for col in df.columns:
      print("col:", col)
      print(df[col][0])

      print("\n===== 前5行数据 =====")
      print(df.head()) # 显示前5行数据,查看数据格式

      print("\n===== 数据统计信息 =====")
      print(df.describe()) # 显示数值型列的统计信息

      return df

      except FileNotFoundError:
      print(f"错误: 找不到文件 '{file_path}'")
      except Exception as e:
      print(f"读取Parquet文件时发生错误: {str(e)}")
      return None

      if __name__ == "__main__":
      parquet_file_path = "./gsm8k/test.parquet"

      # 读取并查看Parquet文件
      dataframe = read_and_inspect_parquet(parquet_file_path)

    附录:列式存储 vs 行式存储

    • 行式存储(如CSV、JSON):按行存储数据,适合整行读取的场景(如单条记录查询)
    • 列式存储(如Parquet):按列存储数据,适合只读取部分列或聚合分析的场景(如计算某列的平均值)
    1…525354…66
    Joe Zhou

    Joe Zhou

    Stay Hungry. Stay Foolish.

    659 posts
    53 tags
    GitHub E-Mail
    © 2026 Joe Zhou
    Powered by Hexo
    |
    Theme — NexT.Gemini v5.1.4