I. *_*. A 7 python absolute-value norm least-squares loss-function
( RMSE和MAE都是测量两个向量之间距离的方法:预测向量和目标值向量。各种距离测量或范数都是可能的。一般来说,计算向量的大小或长度是通常直接需要或作为更广泛的向量或向量矩阵运算的一部分。
尽管RMSE通常是回归任务的首选性能度量,但在某些情况下您可能更喜欢使用其他函数。例如,如果数据集中有许多异常值实例,在这种情况下,我们可以考虑使用平均绝对误差(MAE)。
更正式地说,规范指数越高,它就越关注大值而忽视小值。这就是 RMSE 比 MAE 对异常值更敏感的原因。) 来源:使用 scikit learn 和 tensorflow 进行机器学习实践。
因此,理想情况下,在任何数据集中,如果我们有大量异常值,则损失函数或向量范数“代表预测与真实标签之间的绝对差异;类似于y_diff下面的代码”应该会增长,如果我们增加标准...换句话说,RMSE 应该大于 MAE。--> 如果有错请纠正<--
根据这个定义,我生成了一个随机数据集,并向其中添加了许多异常值,如下面的代码所示。我计算了残差或许多 k 值(范围从 1 到 5)的lk_normy_diff。但是,我发现 lk_norm 随着 k 值的增加而减小;然而,我期望 RMSE(又名范数 = 2)大于 MAE(又名范数 = 1)。
我很想了解当我们增加 K(又名阶数)时,LK 范数是如何减少的,这与上面的定义相反。
预先感谢您的任何帮助!
代码:
import numpy as np
import plotly.offline as pyo
import plotly.graph_objs as go
from plotly import tools
num_points = 1000
num_outliers = 50
x = np.linspace(0, 10, num_points)
# places where to add outliers:
outlier_locs = np.random.choice(len(x), size=num_outliers, replace=False)
outlier_vals = np.random.normal(loc=1, scale=5, size=num_outliers)
y_true = 2 * x
y_pred = 2 * x + np.random.normal(size=num_points)
y_pred[outlier_locs] += outlier_vals
y_diff = y_true - y_pred
losses_given_lk = []
norms = np.linspace(1, 5, 50)
for k in norms:
losses_given_lk.append(np.linalg.norm(y_diff, k))
trace_1 = go.Scatter(x=norms,
y=losses_given_lk,
mode="markers+lines",
name="lk_norm")
trace_2 = go.Scatter(x=x,
y=y_true,
mode="lines",
name="y_true")
trace_3 = go.Scatter(x=x,
y=y_pred,
mode="markers",
name="y_true + noise")
fig = tools.make_subplots(rows=1, cols=3, subplot_titles=("lk_norms", "y_true", "y_true + noise"))
fig.append_trace(trace_1, 1, 1)
fig.append_trace(trace_2, 1, 2)
fig.append_trace(trace_3, 1, 3)
pyo.plot(fig, filename="lk_norms.html")
Run Code Online (Sandbox Code Playgroud)
输出:
最后,我很想知道,在什么情况下使用 L3 或 L4 范数等......?
为了回答你的问题,我们首先必须再次看看 Lp 范数,它是如何定义的以及它在极限中的含义。
Lp范数的定义如下:
您正确地确定了是否p=1有绝对值之和以及p=2平方值之和。有两种特殊情况:p=0和p=infinity。对于p=0Lp-norm 本质上是计算向量中非零元素的数量x并p=infinity返回向量 的最大绝对值x。
这对于拟合模型(例如像您一样的简单线条)意味着什么?正如您正确指出的那样,越高p越强调异常值。L-无穷大损失将尝试最小化回归模型产生的最大绝对误差。这意味着即使是单个异常值也会完全影响拟合线的参数。相反,L0 损失将尝试最小化非零元素的数量,这意味着最优模型将尝试让尽可能多的点直接精确地位于拟合线上(即零误差)。下面是一个示例,您可以在其中在存在单个异常值的情况下拟合直线时看到不同 Lp 范数作为损失函数的效果:
现在建议您更大p意味着误差向量的范数y_diff会增加。仅当您在范数定义中省略 pth-root 时才会出现这种情况。我改编了您的代码并绘制了pLp 范数y_diff与 Lp 范数的 pth 幂之间的关系。
您可以看到,如果您省略范数中的 pth 根,您的直觉是正确的。但是,如果包含它,对于较大的 , if 将收敛到 L-无穷范数(这是最大绝对误差)p。由于 L-无穷大将忽略除最大错误之外的所有错误,这就是它减少的原因。
代码:
import numpy as np
np.random.seed(42)
num_points = 1000
num_outliers = 50
x = np.linspace(0, 10, num_points)
# places where to add outliers:
outlier_locs = np.random.choice(len(x), size=num_outliers, replace=False)
outlier_vals = np.random.normal(loc=1, scale=5, size=num_outliers)
y_true = 2 * x
y_pred = 2 * x + np.random.normal(size=num_points)
y_pred[outlier_locs] += outlier_vals
y_diff = y_true - y_pred
losses_given_lk, losses = [], []
norms = np.linspace(1, 5, 50)
for k in norms:
losses_given_lk.append(np.linalg.norm(y_diff, k))
losses.append(np.linalg.norm(y_diff,k)**k)
plt.figure(dpi=100)
plt.semilogy(norms, losses_given_lk, label=r"$||y_{diff}||_p$")
plt.semilogy(norms, losses,label=r"$||y_{diff}||_p^p$")
plt.grid('on')
plt.legend()
plt.xlabel('p')
Run Code Online (Sandbox Code Playgroud)
from scipy.optimize import minimize
points = np.array([[0,1.1],[0.75,1.8],[1,2.2],[1.75,2.8],[2,3.1],[1.5,1.25]])
plt.figure(dpi=100)
plt.scatter(points[:-1,0],points[:-1,1],label="inliers",marker='x')
plt.scatter(points[-1,0],points[-1,1],label="outlier",marker='x')
def lp_loss(p):
return lambda x: np.linalg.norm((x[0] + x[1]*points[:,0]) - points[:,1],p)
x = np.arange(0,3)
for p in [0, 1, 2, np.inf]:
x0 = (1.1,1.1)
res = minimize(lp_loss(p), x0, method="bfgs")
print(p, res.x)
y_pred = res.x[0] + res.x[1]*x
print((res.x[0] + points[:,0]*res.x[1]) - points[:,1])
plt.plot(x,y_pred,label=f"p={p}")
plt.title(r"True model: $y=x+1 + \epsilon$")
plt.legend()
plt.xlabel("x")
plt.ylabel("y")
Run Code Online (Sandbox Code Playgroud)
另一个 python 实现是np.linalg:
def my_norm(array, k):
return np.sum(np.abs(array) ** k)**(1/k)
Run Code Online (Sandbox Code Playgroud)
要测试我们的功能,请运行以下命令:
array = np.random.randn(10)
print(np.linalg.norm(array, 1), np.linalg.norm(array, 2), np.linalg.norm(array, 3), np.linalg.norm(array, 10))
# And
print(my_norm(array, 1), my_norm(array, 2), my_norm(array, 3), my_norm(array, 10))
Run Code Online (Sandbox Code Playgroud)
输出:
(9.561258110585216, 3.4545982749318846, 2.5946495606046547, 2.027258231324604)
(9.561258110585216, 3.454598274931884, 2.5946495606046547, 2.027258231324604)
Run Code Online (Sandbox Code Playgroud)
因此,我们可以看到数字正在减少,类似于我们在上面问题中发布的图中的输出。
然而,RMSE在python中的正确实现是:np.mean(np.abs(array) ** k)**(1/k)其中k等于2。因此,我将 替换sum为mean。
因此,如果我添加以下功能:
def my_norm_v2(array, k):
return np.mean(np.abs(array) ** k)**(1/k)
Run Code Online (Sandbox Code Playgroud)
并运行以下命令:
print(my_norm_v2(array, 1), my_norm_v2(array, 2), my_norm_v2(array, 3), my_norm_v2(array, 10))
Run Code Online (Sandbox Code Playgroud)
输出:
(0.9561258110585216, 1.092439894967332, 1.2043296427640868, 1.610308452218342)
Run Code Online (Sandbox Code Playgroud)
因此,数量正在增加。
在下面的代码中,我使用修改后的实现重新运行上面问题中发布的相同代码,得到以下结果:
import numpy as np
import plotly.offline as pyo
import plotly.graph_objs as go
from plotly import tools
num_points = 1000
num_outliers = 50
x = np.linspace(0, 10, num_points)
# places where to add outliers:
outlier_locs = np.random.choice(len(x), size=num_outliers, replace=False)
outlier_vals = np.random.normal(loc=1, scale=5, size=num_outliers)
y_true = 2 * x
y_pred = 2 * x + np.random.normal(size=num_points)
y_pred[outlier_locs] += outlier_vals
y_diff = y_true - y_pred
losses_given_lk = []
losses = []
norms = np.linspace(1, 5, 50)
for k in norms:
losses_given_lk.append(np.linalg.norm(y_diff, k))
losses.append(my_norm(y_diff, k))
trace_1 = go.Scatter(x=norms,
y=losses_given_lk,
mode="markers+lines",
name="lk_norm")
trace_2 = go.Scatter(x=norms,
y=losses,
mode="markers+lines",
name="my_lk_norm")
trace_3 = go.Scatter(x=x,
y=y_true,
mode="lines",
name="y_true")
trace_4 = go.Scatter(x=x,
y=y_pred,
mode="markers",
name="y_true + noise")
fig = tools.make_subplots(rows=1, cols=4, subplot_titles=("lk_norms", "my_lk_norms", "y_true", "y_true + noise"))
fig.append_trace(trace_1, 1, 1)
fig.append_trace(trace_2, 1, 2)
fig.append_trace(trace_3, 1, 3)
fig.append_trace(trace_4, 1, 4)
pyo.plot(fig, filename="lk_norms.html")
Run Code Online (Sandbox Code Playgroud)
输出:
这就解释了为什么损失随着 k 的增加而增加。
| 归档时间: |
|
| 查看次数: |
419 次 |
| 最近记录: |