Python中是否有用于均方根误差(RMSE)的库函数?

264

我知道我可以像这样实现一个均方根误差函数:

def rmse(predictions, targets):
    return np.sqrt(((predictions - targets) ** 2).mean())

如果这个RMSE函数已经在某个库中实现了,比如说scipy或者scikit-learn,我是希望能够找到它的。


7
你在那里写了这个函数。如果函数写起来很简单,很可能不会出现在库中。你最好创建一个名为“modules”的目录,将有用的函数放入其中,并将其添加到您的路径中。 - Ryan Saxe
27
我不同意@RyanSaxe的观点。与其自己重新实现一个函数,我更愿意调用库函数。比如说,我原本想用.mean(),但写成了.sum()。此外,我认为这个函数被使用得如此频繁,没有理由不将其作为库函数供人使用。 - siamii
3
我理解100%。我只是在推测为什么这种函数可能不在scipy中。如果有的话,我似乎找不到它。 - Ryan Saxe
1
对于那些尝试过但没有成功的人:如果predictionstargets的类型例如为int16,则平方可能会溢出(产生负数)。因此,在使用平方之前,您可能需要使用.astype('int').astype('double'),例如np.sqrt(((predictions - targets).astype('double') ** 2).mean()) - John
1
在sklearn中拥有这个的另一个优点是,sklearn的实现具有大量额外的样板代码,以确保数组具有相同的形状,并包括权重参数,还处理多维数组和不同的“类似数组”。做所有这些将使问题变得更加复杂。 - David Waterworth
显示剩余2条评论
14个回答

370

sklearn >= 0.22.0

sklearn.metrics有一个mean_squared_error函数,其中包含一个名为squared的参数(默认值为True)。将squared设置为False将返回RMSE。

from sklearn.metrics import mean_squared_error

rms = mean_squared_error(y_actual, y_predicted, squared=False)

sklearn < 0.22.0

sklearn.metrics有一个mean_squared_error函数。RMSE只是它返回值的平方根。

from sklearn.metrics import mean_squared_error
from math import sqrt

rms = sqrt(mean_squared_error(y_actual, y_predicted))

8
返回RMSE的'squared'参数似乎是一个误导性的名称,因为我们仍然在进行平方运算,只是加上了根号而已。在我看来,更准确的参数名称应该是'root'布尔值,这样你可以让函数知道是否要取根号。我错了吗? - THIS USER NEEDS HELP
这应该是被接受的答案,因为它正确地告诉了我们如何计算RMSE。我也同意@THISUSERNEEDSHELP关于参数名称的观点,它是具有误导性的。它应该有一个其他的参数名称。 - hp77
@THISUSERNEEDSHELP 不是这样的。RMSE和MSE之间的区别仅在于我们在RMSE中计算MSE的平方根,这意味着我们可以将MSE称为RMSE的平方,而这正是该参数所做的。 - DaniyalAhmadSE
1
@DaniyalAhmadSE 谢谢您。这很有道理。我明白其中的原因,但是不包含直观的"root"参数仍然让人困惑。 - THIS USER NEEDS HELP

171

什么是RMSE?也称为MSE、RMD或RMS。它解决了什么问题?

如果您理解RMSE(均方根误差)、MSE(均方误差)、RMD(均方根偏差)和RMS(均方根),那么要求一个库来为您计算这些是不必要的过度工程。所有这些都可以直观地写成一行代码。rmse、mse、rmd和rms是同一件事的不同名称。

RMSE回答了这个问题:“list1中的数字与list2中的数字平均相似吗?”这两个列表必须具有相同的大小。消除任何两个给定元素之间的噪声,消除收集的数据大小,并获得单个数字结果。

RMSE的直觉和ELI5。它解决了什么问题?

想象一下,您正在学习向飞镖靶投掷飞镖。每天你练习一个小时。你想弄清楚自己是变得更好还是变得更糟。所以每天你会投10次并测量靶心和你的飞镖命中位置之间的距离。

你需要制作一个数字列表list1,并使用在第一天与一个全零的list2之间距离的均方根误差来计算。在第二天和第n天进行相同的操作。你会得到一个单一的数字,希望随着时间的推移逐渐减少。当RMSE值为零时,你每次都命中靶心。如果RMSE值上升,则说明越来越糟糕。

在Python中计算均方根误差的示例:

import numpy as np
d = [0.000, 0.166, 0.333]   #ideal target distances, these can be all zeros.
p = [0.000, 0.254, 0.998]   #your performance goes here

print("d is: " + str(["%.8f" % elem for elem in d]))
print("p is: " + str(["%.8f" % elem for elem in p]))

def rmse(predictions, targets):
    return np.sqrt(((predictions - targets) ** 2).mean())

rmse_val = rmse(np.array(d), np.array(p))
print("rms error is: " + str(rmse_val))

这将打印:

d is: ['0.00000000', '0.16600000', '0.33300000']
p is: ['0.00000000', '0.25400000', '0.99800000']
rms error between lists d and p is: 0.387284994115

数学符号:

root mean squared deviation explained

符号图例:n是表示掷骰子的正整数,i表示列举总和的正整数计数器,d代表理想距离,即上面示例中包含所有零的list2p代表性能,即上面示例中的list1。上标2代表数字平方。 did的第i个索引。 pip的第i个索引。

RMSE分步解释:

def rmse(predictions, targets):

    differences = predictions - targets                       #the DIFFERENCEs.

    differences_squared = differences ** 2                    #the SQUAREs of ^

    mean_of_differences_squared = differences_squared.mean()  #the MEAN of ^

    rmse_val = np.sqrt(mean_of_differences_squared)           #ROOT of ^

    return rmse_val                                           #get the ^

RMSE的每个步骤是如何工作的:

从一个数字中减去另一个数字可以得到它们之间的距离。

8 - 5 = 3         #absolute distance between 8 and 5 is +3
-20 - 10 = -30    #absolute distance between -20 and 10 is +30

如果你将任何一个数乘以它本身,结果总是正数,因为负数乘以负数等于正数:

3*3     = 9   = positive
-30*-30 = 900 = positive

将它们全部加起来,但要等一下,那么一个元素众多的数组会比一个小数组具有更大的误差,因此按元素数量平均它们。
但我们之前把它们都平方了,以强制它们为正。用平方根撤销这种伤害。
这样您就得到了一个单一的数字,代表了list1中每个值与list2对应元素值之间的距离的平均值。
如果RMSE值随时间降低,我们会感到高兴,因为variance正在减小。在这里,“缩小方差”是一种原始的机器学习算法。

RMSE不是最精确的线拟合策略,总最小二乘法是:

均方根误差测量点和线之间的垂直距离,因此如果您的数据形状像香蕉,底部平坦而顶部陡峭,那么当事实上距离相等时,RMSE将报告高点的距离更远,但对低点的距离较短。这会导致线倾向于靠近高点而不是低点。
如果这是一个问题,总最小二乘法可以解决这个问题:https://mubaris.com/posts/linear-regression 可能会破坏此RMSE函数的注意事项:
如果输入列表中有null或无穷大,则输出的rmse值将没有意义。有三种策略来处理任一列表中的null /缺失值/无穷大:忽略该组件、将其清零或添加最佳猜测或均匀随机噪声到所有时间步长。每种方法都有其优缺点,具体取决于数据的含义。一般来说,忽略任何具有缺失值的组件更可取,但这会使RMSE偏向零,使您认为性能已经提高,而实际上并没有。如果有很多缺失值,则添加最佳猜测的随机噪声可能更可取。
为了保证RMSE输出的相对正确性,必须从输入中消除所有null /无限大。
RMSE对不属于异常数据点的异常数据点具有零容忍度。
均方根误差依赖于所有数据都是正确的且都被视为相等。这意味着一个偏离正常范围的点会完全破坏整个计算。为了处理异常值数据点并在达到一定阈值后忽略它们的巨大影响,请参见内置阈值以排除离群值的鲁棒估计器,因为这些极端罕见事件不需要它们的离奇结果来改变我们的行为。

8
是的,这是一个简单的函数。但如果你在日常使用中需要它,那么有一个正确的解决方案可以随时使用,这样你就不必每次都重新实现它。 😉 - logical x 2
@eric-leschinski,如果您能看一下这个链接,我会很感激:https://dev59.com/O6Pia4cB1Zd3GeqP0IpY - Desta Haileselassie Hagos
@logicalx2 重新实现一个只有两行代码的函数可能会很困难,因为它可以压缩成120个字符,并且只要你的编程语言工作正常,它就总是有效的。这必须与7 GB大小的黑匣子库的儿童保育维护成本相对比,这些库调用数百万行代码,会停止工作并破坏您的流程,现在您陷入了寻找源代码的泥潭,以弄清楚为什么它不像以前那样产生正确的均方根误差值。如果您不想重新实现它,则将该函数放在中央位置,并让每个人都调用它。 - Eric Leschinski
1
我在SO上看到的最好的答案之一! - DonCarleone
@DonCarleone 均方根误差在观测值和模型、模型和正确答案之间的表现,一直是机器学习中心的话题。我相信,人体通过使用糖、空间和时间,在几个世纪内进行渐进式改进演化,每次都能产生更优越的变异。RMSE 产生了一个斜率,其中的列表可以将模型朝着错误的方向进行改进。当你看到它时,这就是完美的解释。"误差"和"学习"是同一件事情。 - Eric Leschinski

43
在scikit-learn 0.22.0中,您可以向mean_squared_error()传递参数squared=False以返回RMSE。
from sklearn.metrics import mean_squared_error
mean_squared_error(y_actual, y_predicted, squared=False)

4
这是一个新功能,如果我们使用它会更好。 - Ravi

28

这也许更快?:

n = len(predictions)
rmse = np.linalg.norm(predictions - targets) / np.sqrt(n)

19

sklearn的mean_squared_error函数本身包含一个名为squared的参数,默认值为True。如果我们将其设置为False,同一个函数将返回RMSE而不是MSE。

from sklearn.metrics import mean_squared_error
rmse = mean_squared_error(y_true, y_pred , squared=False)

参考链接在这里:https://scikit-learn.org/stable/modules/generated/sklearn.metrics.mean_squared_error.html - Gabriel Patricio Bonilla

11

在Kaggle的内核中,有一个名为ml_metrics的库可供使用,无需预先安装,相当轻量级,并可通过pypi访问(可以使用pip install ml_metrics轻松快速地安装):

from ml_metrics import rmse
rmse(actual=[0, 1, 2], predicted=[1, 10, 5])
# 5.507570547286102

它还有其他一些有趣的指标,这些指标在sklearn中不可用,比如mapk

参考文献:


11

或者仅使用NumPy函数:

def rmse(y, y_pred):
    return np.sqrt(np.mean(np.square(y - y_pred)))

其中:

  • y是我的目标值
  • y_pred是我的预测值

请注意,由于平方函数,rmse(y, y_pred)==rmse(y_pred, y)


6

是的,这是由SKLearn提供的,我们只需要在参数中提到squared = False

from sklearn.metrics import mean_squared_error

mean_squared_error(y_true, y_pred, squared=False)

2
from sklearn import metrics              
import numpy as np
print(np.sqrt(metrics.mean_squared_error(y_test,y_predict)))

4
仅提供代码的回答如果附加解释会更有帮助。 - Arghya Sadhu

1
from sklearn.metrics import mean_squared_error
rmse = mean_squared_error(y_actual, y_predicted, squared=False)

or 

import math
from sklearn.metrics import mean_squared_error
rmse = math.sqrt(mean_squared_error(y_actual, y_predicted))

3
请问您能否对这段代码进行一些解释吗? - Ruli
1
你好,欢迎来到SO!你的回答与已有的高票答案重复。建议在没有添加新的有价值内容的情况下避免重复回答。即使在这种情况下,也可以通过评论提出一些小的变化建议给原有的答案。 - pkuderov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接