Gnuplot拟合时如何自动忽略异常值?
Gnuplot拟合时自动剔除异常值的实用方案
针对你拟合二次函数时遇到的异常点(比如y2列的(4,50))干扰拟合结果的问题,以下是几种可直接落地的解决方案:
方案1:基于残差迭代过滤异常值
核心思路是先完成一次初始拟合,计算每个数据点的残差(实际值与拟合值的差值),以3倍标准差作为阈值剔除残差超标的点,再用清洗后的数据集重新拟合,确保拟合结果不受异常点干扰。
适配你的gnuplottex环境的修改后代码:
\begin{gnuplot}[terminal=tikz, terminaloptions={color size 7cm,5cm}] reset session $Data <<EOD #data x y1 y2 y3 y4 1 1 6 4 2 2 4 10 1 1 3 9 15 0 0.5 4 16 50 1 2 5 25 31 4 5 6 36 42 9 12 7 49 55 30 23 EOD set print 'parameters.dat' # 图例设置 set key top left Left samplen 2 spacing 1.2 font ",8" noautotitle # 定义拟合函数 f(x,a,b,c) = a*(x-b)**2 + c colMin = 2 colMax = 5 set fit quiet nolog array A[colMax] array B[colMax] array C[colMax] array residuals[7] # 存储7个数据点的残差 do for [col=colMin:colMax] { a=1; b=1; c=4 # 第一次初始拟合 fit f(x,a,b,c) $Data u 1:col via a,b,c # 计算残差并统计标准差 stats $Data u (residuals[$0+1] = abs(column(col) - f(column(1),a,b,c))) nooutput threshold = 3 * STATS_stddev # 以3倍标准差作为异常值阈值 # 创建清洗后的临时数据集 $CleanData <<EOD EOD do for [i=1:7] { if (residuals[i] <= threshold) { stats $Data u 1:col every ::i-1::i-1 nooutput print sprintf("%d %.4f", STATS_x, STATS_y) >> $CleanData } } # 用清洗后的数据集重新拟合 fit f(x,a,b,c) $CleanData u 1:2 via a,b,c A[col] = a; B[col] = b; C[col] = c print sprintf ('%d %.4f %.4f %.4f',col-1,A[col],B[col],C[col]) } plot for [col=colMin:colMax] $Data u 1:col ls col, \ for [col=colMin:colMax] f(x,A[col],B[col],C[col]) ls col, \ for [col=colMin:colMax] keyentry w lp ls col \ title sprintf("$y%d$",col-1) \end{gnuplot}
方案2:加权拟合削弱异常值影响
如果不想完全剔除点,可以通过加权方式降低异常点的影响力:给残差小的点设置高权重,残差大的点设置低权重,让拟合过程更偏向正常数据。
修改拟合逻辑的代码片段:
do for [col=colMin:colMax] { a=1; b=1; c=4 # 初始拟合获取残差基准 fit f(x,a,b,c) $Data u 1:col via a,b,c # 定义权重规则:残差越小权重越高,加0.1避免除以0 weight(x,y) = 1/(abs(y - f(x,a,b,c)) + 0.1) # 执行加权拟合 fit f(x,a,b,c) $Data u 1:col:(weight($1,$col)) via a,b,c A[col] = a; B[col] = b; C[col] = c print sprintf ('%d %.4f %.4f %.4f',col-1,A[col],B[col],C[col]) }
方案3:手动指定排除规则(适合已知异常特征)
如果你明确知道某些点是异常(比如y2列x=4的点),可以直接在拟合时针对性排除,适合场景简单的情况:
修改拟合行的代码片段:
do for [col=colMin:colMax] { a=1; b=1; c=4 # 针对y2列(col=3)排除x=4的点,其他列正常拟合 if (col == 3) { fit f(x,a,b,c) $Data u 1:col not (column(1) == 4) via a,b,c } else { fit f(x,a,b,c) $Data u 1:col via a,b,c } A[col] = a; B[col] = b; C[col] = c print sprintf ('%d %.4f %.4f %.4f',col-1,A[col],B[col],C[col]) }
内容的提问来源于stack exchange,提问作者Konstantin Weigmann
相关产品推荐
相关产品推荐

