RANSAC(随机抽样一致性算法)是一种用于估计数学模型参数的迭代方法,尤其适用于包含大量异常值的数据。使用 RANSAC,我们可以找到一个最优的线性拟合,同时最大限度地减少对异常值的影响。接下来,我将给出一个使用 RANSAC 进行线性回归的 Python 示例,并绘制散点、回归线及回归线的置信区间。
前置安装
首先,需要安装 scikit-learn
和 matplotlib
库,如果还没有安装,可以通过以下命令安装:
pip install scikit-learn matplotlib
代码示例
以下代码展示如何使用 RANSAC 进行线性回归:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import RANSACRegressor, LinearRegression
from sklearn.utils import resample
# 生成数据:带有异常值的线性数据
np.random.seed(42)
x = np.linspace(0, 10, 100)
y = 2 * x + 1 + np.random.normal(0, 1, x.shape)
# 添加一些异常值
x[::10] = np.random.uniform(0, 10, size=(10,))
y[::10] = np.random.uniform(-10, 30, size=(10,))
# Reshape x for sklearn
x = x.reshape(-1, 1)
# 创建RANSAC模型
model = RANSACRegressor(estimator=LinearRegression(), random_state=42)
model.fit(x, y)
# 预测值
x_pred = np.linspace(0, 10, 100).reshape(-1, 1)
y_pred = model.predict(x_pred)
# 获取内点和外点
inlier_mask = model.inlier_mask_
outlier_mask = np.logical_not(inlier_mask)
# 使用 Bootstrap 方法计算置信区间
n_bootstraps = 200
y_pred_bootstrap = []
for _ in range(n_bootstraps):
# 随机采样数据集(仅内点)
x_sample, y_sample = resample(x[inlier_mask], y[inlier_mask])
ransac_bootstrap = RANSACRegressor(estimator=LinearRegression(), random_state=42)
ransac_bootstrap.fit(x_sample, y_sample)
# 预测
y_pred_sample = ransac_bootstrap.predict(x_pred)
y_pred_bootstrap.append(y_pred_sample)
# 转换为数组并计算 95% 置信区间
y_pred_bootstrap = np.array(y_pred_bootstrap)
lower_bound = np.percentile(y_pred_bootstrap, 2.5, axis=0)
upper_bound = np.percentile(y_pred_bootstrap, 97.5, axis=0)
# 绘制散点图、RANSAC回归线和置信区间
plt.figure(figsize=(10, 6))
plt.scatter(x[inlier_mask], y[inlier_mask], color='blue', label='Inliers', alpha=0.6)
plt.scatter(x[outlier_mask], y[outlier_mask], color='red', label='Outliers', alpha=0.6)
plt.plot(x_pred, y_pred, color='green', label='RANSAC Linear Fit', linewidth=2)
plt.fill_between(x_pred.ravel(), lower_bound, upper_bound, color='lightgreen', alpha=0.5, label='95% Confidence Interval')
plt.xlabel('x')
plt.ylabel('y')
plt.title('RANSAC Linear Regression with Confidence Interval')
plt.legend()
plt.grid()
plt.show()
代码说明
-
数据生成:
- 使用
numpy
生成带有噪声的线性数据。 - 随机插入一些异常值,以模拟实际情况中的离群点。
- 使用
-
模型创建:
- 创建
RANSACRegressor
模型,并使用LinearRegression
作为基本估计器。 - 拟合模型以找到最佳的线性回归线。
- 创建
-
内点和外点:
- 使用
inlier_mask
获取模型中的内点(符合模型的点)和外点(异常点)。
- 使用
-
置信区间计算:
- 使用 Bootstrap 方法从内点中随机采样 200 次,每次拟合 RANSAC 模型并预测。
- 计算 95% 的置信区间。
-
绘图:
- 绘制散点图,分别标记内点和外点。
- 绘制 RANSAC 拟合的回归线和 95% 置信区间。
输出图形
运行代码后会得到以下输出:
- 蓝色点:代表符合模型的内点。
- 红色点:代表被识别为异常值的外点。
- 绿色线:代表 RANSAC 模型的线性回归拟合线。
- 淡绿色区域:代表回归线的 95% 置信区间。
这个示例展示了 RANSAC 如何有效地处理异常值,同时仍然能够提供稳定的线性回归模型。
如果是曲线
min_samples
用于指定在拟合时最少需要多少个样本点(可以是样本数的比例或绝对数)。
在我们的情况下,因为我们使用的是二次多项式的线性回归模型,所以我们可以简单地设置 min_samples
为 2(因为二次多项式需要至少 3 个点来进行拟合)。
下面是修正后的代码:
修正后的代码示例
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import RANSACRegressor, LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
from sklearn.utils import resample
# 生成数据:带有异常值的二次曲线数据
np.random.seed(42)
x = np.linspace(0, 10, 100)
y = 0.5 * (x ** 2) - x + 2 + np.random.normal(0, 2, x.shape)
# 添加一些异常值
x[::10] = np.random.uniform(0, 10, size=(10,))
y[::10] = np.random.uniform(-10, 30, size=(10,))
# Reshape x for sklearn
x = x.reshape(-1, 1)
# 创建二次多项式回归的 RANSAC 模型
degree = 2
model = RANSACRegressor(
estimator=make_pipeline(PolynomialFeatures(degree), LinearRegression()),
min_samples=2, # 设置最少样本数
random_state=42
)
model.fit(x, y)
# 预测值
x_pred = np.linspace(0, 10, 100).reshape(-1, 1)
y_pred = model.predict(x_pred)
# 获取内点和外点
inlier_mask = model.inlier_mask_
outlier_mask = np.logical_not(inlier_mask)
# 使用 Bootstrap 方法计算置信区间
n_bootstraps = 200
y_pred_bootstrap = []
for _ in range(n_bootstraps):
# 随机采样数据集(仅内点)
x_sample, y_sample = resample(x[inlier_mask], y[inlier_mask])
model_bootstrap = RANSACRegressor(
estimator=make_pipeline(PolynomialFeatures(degree), LinearRegression()),
min_samples=2, # 设置最少样本数
random_state=42
)
model_bootstrap.fit(x_sample, y_sample)
# 预测
y_pred_sample = model_bootstrap.predict(x_pred)
y_pred_bootstrap.append(y_pred_sample)
# 转换为数组并计算 95% 置信区间
y_pred_bootstrap = np.array(y_pred_bootstrap)
lower_bound = np.percentile(y_pred_bootstrap, 2.5, axis=0)
upper_bound = np.percentile(y_pred_bootstrap, 97.5, axis=0)
# 绘制散点图、RANSAC回归二次曲线和置信区间
plt.figure(figsize=(10, 6))
plt.scatter(x[inlier_mask], y[inlier_mask], color='blue', label='Inliers', alpha=0.6)
plt.scatter(x[outlier_mask], y[outlier_mask], color='red', label='Outliers', alpha=0.6)
plt.plot(x_pred, y_pred, color='green', label='RANSAC Quadratic Fit', linewidth=2)
plt.fill_between(x_pred.ravel(), lower_bound, upper_bound, color='lightgreen', alpha=0.5, label='95% Confidence Interval')
plt.xlabel('x')
plt.ylabel('y')
plt.title('RANSAC Quadratic Regression with Confidence Interval')
plt.legend()
plt.grid()
plt.show()
代码修改说明
-
添加
min_samples
参数:在创建RANSACRegressor
实例时,明确指定min_samples=2
,这是因为拟合一个二次多项式需要至少 3 个样本点来确定二次方程的系数。 -
其余部分保持不变:保留了数据生成、模型拟合、置信区间计算和绘图的其余部分。
运行此修正后的代码,应该能够顺利生成 RANSAC 二次曲线拟合的散点图和置信区间。