Вы хотите устойчивая линейная регрессия , игнорируя выбросы.Такая вещь уже реализована в модуле sklearn , но поскольку ее нет в тегах, вот простое решение SciPy.
Идея состоит в том, чтобы минимизировать сумму абсолютных значений отклонений (функцию потерь L1) вместо суммы квадратов.(Сравните с: медиана против среднего.)
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt
x = np.linspace(0.7, 7, 10)
y = 0.8*x + 1.2
y[5] = 2.5 # outlier
l1_loss = lambda c: np.sum(np.abs(c[0]*x + c[1] - y))
c = minimize(l1_loss, (0, 0)).x
plt.plot(x, y, 'b*')
plt.plot(x, c[0]*x+c[1], 'r')
plt.show()
good = np.abs(c[0]*x + c[1] - y) < 0.1 # arbitrary threshold to separate good from bad
print('good data: x = {}, y = {}'.format(x[good], y[good]))
Вывод: "хорошие данные: x = [0.7 1.4 2.1 2.8 3.5 4.9 5.6 6.3 7. ]
, y = [1.76 2.32 2.88 3.44 4. 5.12 5.68 6.24 6.8 ]
".
Линия вообще не возмущена выбросом.
Возможно, вы захотите заменить good = np.abs(c[0]*x + c[1] - y) < 0.1
итеративным подходом, когда точка данных с наибольшим значением отклонения, т. Е.
outlier_idx = np.argmax(np.abs(c[0]*x + c[1] - y))
идентифицируется и удаляется из массивов x и y.(np.delete
), затем процесс повторяется до тех пор, пока корреляция не станет хорошей.