平均绝对值误差(L1_Loss)和 均方误差(L2_Loss)

本文探讨了平均绝对误差(MAE)和均方误差(MSE)在回归任务中的区别,包括它们的计算公式、适用场景、优势与劣势。MAE对局外点更鲁棒,但梯度问题影响学习;MSE求解更易但对异常值敏感。通过实例和对比,揭示了在不同情况下的选择策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、 Mean Absolute Error

平均绝对误差(MAE)也是一种常用的回归损失函数,它是目标值 y j y_{j} yj与预测值 y j ^ \hat{y_{j}} yj^之差绝对值的和,表示了预测值的平均误差幅度,而不需要考虑误差的方向,其公式如下所示:
M A E = 1 N ∑ i = 1 N ∣ y j − y j ^ ∣ MAE= \frac{1}{N} \sum_{i =1}^{N} |y_{j} - \hat{ y_{j} } | MAE=N1i=1Nyjyj^

二、 Mean Square Error

均方误差(MSE)用于计算预测值 y j ^ \hat{y_{j}} yj^与真实值 y j y_{j} yj之间差的平均值,其公式如下所示:
M S E = 1 N ∑ i = 1 N ( y j − y j ^ ) 2 MSE = \frac{1}{N}\sum_{i=1}^{N}(y_{j}-\hat{y_{j}})^2 MSE=N1i=1N(yjyj^)2

三、 代码实现MAE和MSE

import numpy as np
import matplotlib.pyplot as plt

def MAE_Loss(act, pred):
    diff = act - pred
    diff_abs = np.absolute(diff)
    mae = diff_abs.mean()
    return mae

def MSE_Loss(act, pred):
    diff = act - pred
    diff_square = diff ** 2
    mse  = diff_square.mean()
    return mse

'''
create an array containning 500 numbers, 
the value range is between -1 and 1.
'''
pred = np.linspace(-1., 1., 500)   
# the actual value is 0
target = 0.
l1_y = []
l2_y = []
for x in pred:
    y = MAE_Loss(target, x)
    l1_y.append(y)

for x2 in pred:
    y2 = MSE_Loss(target, x2)
    l2_y.append(y2)
plt.plot(pred, l1_y, label="L1_loss")
plt.plot(pred, l2_y, label="L2_loss")
plt.legend()

结果图:
在这里插入图片描述

四、 MAE与MSE的比较

通常来说,利用均方差更容易求解,但平方绝对误差则对于局外点更鲁棒。
在机器学习的模型通常是用来找到使目标函数最小的点。在最小值处每一种损失函数都会得到最小值。
在这里插入图片描述
MAE优于MSE的情况
由上图可知,当预测值与目标值很接近,误差与方差都很小,而由于局外点的存在使得 MSE误差变得很大。
由于均方误差(MSE)在误差较大点时的损失远大于平均绝对误差(MAE),它会给局外点赋予更大的权重,模型会致力减小局外点造成的误差,从而使得模型的整体表现下降。
所以当训练数据中含有较多的局外点时,平均绝对误差(MAE)更为有效。当我们对所有观测值进行处理时,如果利用MSE进行优化则我们会得到所有观测的均值,而使用MAE则能得到所有观测的中值。与均值相比,中值对于局外点的鲁棒性更好,这就意味着平均绝对误差对于局外点有着比均方误差更好的鲁棒性。
** MSE优于MAE的情况**
在这里插入图片描述
但MAE也存在一个问题,特别是对于神经网络来说,它的梯度在极值点处会有很大的跃变,及时很小的损失值也会长生很大的误差,这不利于学习过程。为了解决这个问题,需要在解决极值点的过程中动态减小学习率。MSE在极值点却有着良好的特性,及时在固定学习率下也能收敛。MSE的梯度随着损失函数的减小而减小,这一特性使得它在最后的训练过程中能得到更精确的结果。

总结

L1损失对于局外点更鲁棒,但它的导数不连续使得寻找最优解的过程低效;L2损失对于局外点敏感,但在优化过程中更为稳定和准确。
但现实中还存在两种损失都很难处理的问题。例如某个任务中90%的数据都符合目标值——150,而其余的10%数据取值则在0-30之间。那么利用MAE优化的模型将会得到150的预测值而忽略的剩下的10%(倾向于中值);而对于MSE来说由于局外点会带来很大的损失,将使得模型倾向于在0-30的方向取值。这两种结果在实际的业务场景中都是我们不希望看到的。

参考的博客:
https://zhuanlan.zhihu.com/p/376024235

<think>我们使用fprintf函数在MATLAB中写入CSV文件的标题行。CSV文件通常使用逗号分隔各列。根据要求,标题行需要包含“步长”、“自由度”、“L2误差”等字段。我们可以将这些字段名称用逗号连接,然后使用fprintf写入文件。具体步骤:1.打开文件(使用fopen函数,模式为'w'表示写入,如果文件存在则覆盖)。2.定义标题行的字符串,每个字段用逗号分隔,并在最后加上换行符(因为CSV通常每行一条记录)。3.使用fprintf将标题行字符串写入文件。4.关闭文件(使用fclose)。注意:如果字段中包含逗号,则整个字段需要用双引号括起来。但这里我们假设字段名中没有逗号。根据要求,标题行包含“步长”、“自由度”、“L2误差”等,我们可以这样定义标题行:header='步长,自由度,L2误差';但是,通常我们可能还有更多的列,比如“H1误差”、“时间”等。根据用户需求,这里只提到了这三个字段,但用户可能希望自定义。因此,我们可以按照用户列出的字段来写。假设用户要求写入的字段顺序为:步长、自由度、L2误差。那么我们可以这样写:代码示例:```matlab%打开文件,'w'表示写入(覆盖已有内容)fid=fopen('results.csv','w');iffid==-1error('无法打开文件');end%定义标题行,用逗号分隔各列,并在末尾加上换行符header='步长,自由度,L2误差\n';%写入标题行fprintf(fid,header);%关闭文件fclose(fid);```如果用户需要更多的列,比如添加“H1误差“计算时间”,则可以:```matlabheader='步长,自由度,L2误差,H1误差,计算时间\n';```注意:在Windows系统中,换行符可以是'\r\n',但通常'\n'在MATLAB中也能被正确识别为换行。为了更好的兼容性,特别是当文件需要在Excel中打开时,可以使用'\r\n'。因此,改进的写法:```matlabheader='步长,自由度,L2误差\r\n';```或者,我们可以使用更通用的方式,即使用`sprintf`来构造换行,因为不同的操作系统可能不同。MATLAB在写入文件时,如果以文本模式打开(默认),那么当写入'\n'时,MATLAB会自动转换为当前操作系统需要的换行符(Windows为'\r\n',Unix为'\n')。所以,我们通常只需要写'\n'即可,MATLAB会自动处理。因此,代码可以简化为:```matlabfid=fopen('results.csv','w');iffid==-1error('无法打开文件');endfprintf(fid,'步长,自由度,L2误差\n');%直接写入,注意换行fclose(fid);```如果用户需要写入的字段很多,而且可能动态生成,我们可以使用循环来写入,但这里字段固定,直接写即可。另外,注意在写入CSV文件时,如果某个字段包含逗号,则整个字段必须用双引号括起来。例如,如果有一个字段名为“误差(L2)”,因为包含括号,但括号不是特殊字符,所以不需要引号。但是,如果字段名是“步长,h”,那么就必须写成“"步长,h"”。但根据题目,我们的字段名是“步长”、“自由度”等,不包含逗号,所以不需要引号。因此,最终代码为:```matlab%写入CSV标题行fid=fopen('results.csv','w');iffid==-1error('无法打开文件');end%写入标题行,字段之间用逗号分隔,最后换行fprintf(fid,'步长,自由度,L2误差\n');fclose(fid);```如果用户希望添加更多字段,只需在字符串中添加逗号字段名即可。注意:这里我们使用了'w'模式,会覆盖原有文件。如果用户希望追加内容,则在写入标题行后,后续写入数据时应该用追加模式('a')打开。但标题行通常只需要写一次,所以用'w'模式。引用说明:在MATLAB中使用fprintf写入文件时,注意文件打开模式(参考引用[1][2])。引用[1]中展示了如何写入CSV标题栏,使用循环写入多个标题,并在最后加上逗号。但注意,这样写每列后面都有逗号,包括最后一列,这样会导致最后一列后面多一个逗号,可能不是我们想要的。因此,我们采用一次性写入整个标题字符串的方式。另外,引用[3]提到从单元格数据写入CSV文件时需要注意初始化问题,但这里我们直接写入字符串,不需要初始化单元格。因此,我们按照上述方式写入标题行。</think>在MATLAB中使用`fprintf`函数写入CSV标题行时,需注意逗号分隔换行符处理。以下是实现代码及详细说明: ```matlab % 创建/打开CSV文件(覆盖模式) fid = fopen('results.csv', 'w'); if fid == -1 error('文件打开失败'); end % 写入标题行(注意逗号分隔换行符) fprintf(fid, '步长,自由度,L2误差,最大误差,迭代次数\n'); % 关闭文件 fclose(fid); disp('CSV标题行写入完成'); ``` ### 关键说明: 1. **字段定义**: - `步长`:数值计算中的离散化步长 - `自由度`:系统独立变量数(如网格点数) - `L2误差`:向量的二范数误差 $ \|u_{exact} - u_{num}\|_2 $ - 可扩展其他字段(如`H1误差`、`计算时间`等) 2. **语法要点**: - **逗号分隔**:字段间用逗号连接(`,`) - **换行符**:末尾的`\n`结束当前行 - **文件模式**: - `'w'`:覆盖写入(首次创建文件) - `'a'`:追加模式(后续写入数据) 3. **高级格式**: ```matlab % 带单位说明的标题(需引号包裹特殊字符) fprintf(fid, '"步长(m)","自由度","L2误差","相对误差(%%)"\n'); ``` ### 验证结果: 生成的`results.csv`内容为: ``` 步长,自由度,L2误差,最大误差,迭代次数 ``` ### 实际应用: 后续追加数据示例: ```matlab fid = fopen('results.csv', 'a'); % 追加模式 fprintf(fid, '0.01,256,3.2e-5,0.00012,15\n'); fclose(fid); ``` > **注意**:Excel打开CSV时可能误判编码,建议: > 1. 使用`fprintf(fid, '\xEF\xBB\xBF');`写入UTF-8 BOM头 > 2. 或通过MATLAB的`writetable`函数生成CSV(兼容性更好) ### 引用参考: CSV标题行写入需确保字段分隔符的正确处理[^1],文本文件中的换行符追加模式会影响数据格式[^2],单元格数据的维度初始化也需特别注意[^3]。 --- ### 相关问题 1. 如何在MATLAB中将数值计算结果追加到CSV文件中? 2. 使用`fprintf`写入CSV时如何处理包含逗号的字段(如"误差, L2")? 3. MATLAB中`fprintf``writetable`生成CSV有何性能差异? 4. 如何让MATLAB生成的CSV文件在Excel中正确显示中文标题?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值