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异常。