You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中去除异常值以实现更优曲线拟合?

如何处理图像曲线拟合中的异常值干扰?

我正尝试使用从图像中获取的数据进行曲线拟合,但有时图像中存在对应曲线之外的额外点,导致拟合结果不准确。例如右侧的数据点使拟合曲线出现偏离(见附图)。我当前使用的代码如下:

# CURVE
trend = np.polyfit(x_list,y_list,2)
trendpoly = np.poly1d(trend) 

new_x = np.linspace(min(x_list), max(x_list))
new_y = trendpoly(new_x)
plt.plot(x_list, y_list, 'o', new_x, new_y,'*')

补充说明:处理的是相机采集的图像,经处理后获取曲线数据,理想状态为特定曲线(见理想场景图),期望得到对应的拟合效果(见预期拟合图)。但采集的图像出现偏差时,会有干扰点破坏拟合效果,且由于未知图形形态,无法确定更高次多项式的次数。请问是否有方法检测此类异常值并实现更优拟合?


解决方案

1. 用稳健拟合替代普通最小二乘拟合

普通np.polyfit基于最小二乘法,对异常值极度敏感。改用稳健拟合算法,通过鲁棒损失函数降低异常值的权重,能直接得到更可靠的拟合结果,无需手动剔除点。

示例代码:

import numpy as np
from scipy.optimize import least_squares
import matplotlib.pyplot as plt

# 定义多项式残差计算函数
def poly_residuals(params, x, y):
    return y - np.polyval(params, x)

# 初始参数猜测(以二次多项式为例)
initial_guess = np.array([1, 0, 0])

# 使用Huber损失做稳健拟合,大残差点会被降权
result = least_squares(poly_residuals, initial_guess, args=(x_list, y_list), loss='huber')

# 生成拟合多项式
trendpoly_robust = np.poly1d(result.x)

# 对比绘图
new_x = np.linspace(min(x_list), max(x_list), 100)
plt.plot(x_list, y_list, 'o', label='原始数据')
plt.plot(new_x, np.polyval(trend, new_x), '*', label='普通拟合')
plt.plot(new_x, trendpoly_robust(new_x), 'r-', label='稳健拟合')
plt.legend()
plt.show()

2. 先检测剔除异常值再拟合

如果希望先明确移除异常点,可通过以下两种方法实现:

  • 残差阈值法:先做初步拟合,计算每个点的残差,将残差超过3倍标准差的点标记为异常值剔除;
  • 聚类法:用DBSCAN聚类,远离主数据簇的点直接判定为异常值。

示例:残差阈值法

import numpy as np
import matplotlib.pyplot as plt

# 初步拟合
trend_initial = np.polyfit(x_list, y_list, 2)
trendpoly_initial = np.poly1d(trend_initial)
y_pred_initial = trendpoly_initial(x_list)

# 计算残差与标准差
residuals = y_list - y_pred_initial
std_residual = np.std(residuals)

# 筛选正常点(阈值可根据实际场景调整)
mask = np.abs(residuals) < 3 * std_residual
x_clean = x_list[mask]
y_clean = y_list[mask]

# 用清洗后的数据重新拟合
trend_clean = np.polyfit(x_clean, y_clean, 2)
trendpoly_clean = np.poly1d(trend_clean)

# 绘图展示
new_x = np.linspace(min(x_list), max(x_list), 100)
plt.plot(x_list, y_list, 'o', label='原始数据')
plt.plot(new_x, trendpoly_initial(new_x), '*', label='初步拟合')
plt.plot(new_x, trendpoly_clean(new_x), 'r-', label='清洗后拟合')
plt.scatter(x_list[~mask], y_list[~mask], c='red', s=50, label='异常值')
plt.legend()
plt.show()

3. 非参数拟合(无需预设多项式次数)

如果不确定曲线的具体形态,可使用**LOESS(局部加权散点平滑)**这类非参数方法,它不需要预设多项式次数,且对局部异常值的鲁棒性更强。

示例代码:

import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm

# LOESS要求x有序,先排序数据
sorted_indices = np.argsort(x_list)
x_sorted = x_list[sorted_indices]
y_sorted = y_list[sorted_indices]

# 执行LOESS拟合,frac控制平滑程度(0-1,值越大拟合越平滑)
lowess_result = sm.nonparametric.lowess(y_sorted, x_sorted, frac=0.3)

# 提取拟合结果
x_fit = lowess_result[:, 0]
y_fit = lowess_result[:, 1]

# 绘图
plt.plot(x_list, y_list, 'o', label='原始数据')
plt.plot(x_fit, y_fit, 'r-', label='LOESS拟合')
plt.legend()
plt.show()

内容的提问来源于stack exchange,提问作者Javier Piña Camacho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 04:15:37