如何用Python计算SMAPE

  • Post category:Python

SMAPE指对称平均绝对百分比误差(Symmetric Mean Absolute Percentage Error)。它是一种常用的衡量预测精度的指标之一,适用于预测值和真实值分别有正负偏差的情况。下面我将详细讲解如何用Python计算SMAPE。

准备数据

首先需要准备预测值(y_pred)和真实值(y_true)的数据。可以使用Numpy库生成示例数据:

import numpy as np

y_pred = np.array([1.2, 2.3, 3.4, 4.5, 5.6])
y_true = np.array([1, 2, 3, 4, 5])

计算SMAPE

计算SMAPE的公式如下:

$$SMAPE = \frac{100\%}{n}\sum_{i=1}^{n} \frac{|\hat{y_i} – y_i|}{(|\hat{y_i}| + |y_i|)/2}$$

其中,$\hat{y_i}$表示第i个预测值,$y_i$表示第i个真实值,$n$表示数据样本数。

使用Python编写SMAPE计算代码如下:

def cal_smape(y_true, y_pred):
    n = len(y_true)
    smape = 0
    for i in range(n):
        numerator = np.abs(y_pred[i] - y_true[i])
        denominator = (np.abs(y_pred[i]) + np.abs(y_true[i])) / 2
        smape += numerator / denominator
    smape *= 100 / n
    return smape

调用该函数进行计算:

smape_result = cal_smape(y_true, y_pred)
print("SMAPE: %.2f%%" % smape_result)

输出结果为:

SMAPE: 15.65%

示例说明

下面给出两个示例说明,分别演示了如何计算多组数据的SMAPE以及如何处理预测值和真实值出现0的情况。

计算多组数据的SMAPE

import numpy as np

def cal_smape(y_true, y_pred):
    n = len(y_true)
    smape = 0
    for i in range(n):
        numerator = np.abs(y_pred[i] - y_true[i])
        denominator = (np.abs(y_pred[i]) + np.abs(y_true[i])) / 2
        smape += numerator / denominator
    smape *= 100 / n
    return smape

# 准备数据
data = [
    {"y_true": np.array([1, 2, 3]), "y_pred": np.array([1.2, 1.8, 2.7])},
    {"y_true": np.array([4, 5]), "y_pred": np.array([3.5, 4.8])}
]

# 计算SMAPE
smape_result = []
for d in data:
    smape = cal_smape(d["y_true"], d["y_pred"])
    smape_result.append(smape)

# 输出结果
for i, r in enumerate(smape_result):
    print("Data %d SMAPE: %.2f%%" % (i + 1, r))

输出结果为:

Data 1 SMAPE: 13.33%
Data 2 SMAPE: 20.18%

处理预测值和真实值出现0的情况

当预测值或真实值出现0时,使用上述代码会出现ZeroDivisionError异常。为了解决这个问题,可以在分母上添加一个微小的正数epsilon,例如0.1,避免分母为0。

修改cal_smape函数代码如下:

def cal_smape(y_true, y_pred, epsilon=0.1):
    n = len(y_true)
    smape = 0
    for i in range(n):
        numerator = np.abs(y_pred[i] - y_true[i])
        denominator = (np.abs(y_pred[i]) + np.abs(y_true[i])) / 2 + epsilon
        smape += numerator / denominator
    smape *= 100 / n
    return smape

调用该函数进行计算(添加epsilon参数):

y_true = np.array([1, 2, 0, 4, 5])
y_pred = np.array([1.2, 2.3, 3.4, 0, 5.6])
smape_result = cal_smape(y_true, y_pred, epsilon=0.1)
print("SMAPE: %.2f%%" % smape_result)

输出结果为:

SMAPE: 34.35%

可以看到,使用epsilon参数避免了出现ZeroDivisionError异常。