【问题标题】:Identifying Outliers with Quantile Regression and Python使用分位数回归和 Python 识别异常值
【发布时间】:2018-08-10 17:57:25
【问题描述】:

我正在尝试使用回归线的第 5 个和第 95 个百分位来识别数据集中的异常值,因此我在 Python 中使用 statsmodel、matplotlib 和 pandas 的分位数回归。基于来自 bokeley 的this answer,我可以创建我的数据的散点图并显示最佳拟合线以及基于分位数回归的第 5 和第 95 个百分位数的线。但是我如何识别那些位于这些线之上和之下的点,然后将它们保存到 pandas 数据框?

我的数据是这样的(总共有 95 个值):

    Month   Year    LST     NDVI
0   June    1984    310.550975  0.344335
1   June    1985    310.495331  0.320504
2   June    1986    306.820900  0.369494
3   June    1987    308.945602  0.369946
4   June    1988    308.694022  0.31863

2

到目前为止我的脚本是这样的:

import pandas as pd
excel = my_excel
df = pd.read_excel(excel)
df.head()

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import statsmodels.formula.api as smf

model = smf.quantreg('NDVI ~ LST',df)
quantiles = [0.05,0.95]
fits = [model.fit(q=q) for q in quantiles]
figure,axes = plt.subplots()
x = df['LST']
y = df['NDVI']
axes.scatter(x,df['NDVI'],c='green',alpha=0.3,label='data point')
fit = np.polyfit(x, y, deg=1)
axes.plot(x, fit[0] * x + fit[1], color='grey',label='best fit')
_x = np.linspace(x.min(),x.max())
for index, quantile in enumerate(quantiles):
    _y = fits[index].params['LST'] * _x + fits[index].params['Intercept']
    axes.plot(_x, _y, label=quantile)

title = 'LST/NDVI Jun-Aug'
plt.title(title)
axes.legend()
axes.set_xticks(np.arange(298,320,4))
axes.set_yticks(np.arange(0.25,0.5,.05))
axes.set_xlabel('LST')
axes.set_ylabel('NDVI');

我从中得到的图表是这样的:

所以我绝对可以看到我将分类为异常值的第 95 行以上和第 5 行以下的数据点,但我想在我的原始数据框中识别这些数据点,并可能将它们绘制在购物车上或以某种方式突出显示它们以将它们显示为“异常值”。

我正在寻找一种方法,但结果是空的,需要一些帮助。

【问题讨论】:

    标签: python pandas matplotlib statsmodels quantile-regression


    【解决方案1】:

    您需要确定某个点是高于 95% 分位线还是低于 5% 分位线。您可以使用叉积来做到这一点,请参阅this answer 以获得简单的实现。

    在您的示例中,您可能需要组合分位数线上方和下方的点,可能在掩码中。

    这是一个例子:

    import matplotlib.pyplot as plt
    import numpy as np
    import pandas as pd
    import statsmodels.formula.api as smf
    
    df = pd.DataFrame(np.random.normal(0, 1, (100, 2)))
    df.columns = ['LST', 'NDVI']
    
    model = smf.quantreg('NDVI ~ LST', df)
    quantiles = [0.05, 0.95]
    fits = [model.fit(q=q) for q in quantiles]
    figure, axes = plt.subplots()
    x = df['LST']
    y = df['NDVI']
    
    fit = np.polyfit(x, y, deg=1)
    _x = np.linspace(x.min(), x.max(), num=len(y))
    
    # fit lines
    _y_005 = fits[0].params['LST'] * _x + fits[0].params['Intercept']
    _y_095 = fits[1].params['LST'] * _x + fits[1].params['Intercept']
    
    # start and end coordinates of fit lines
    p = np.column_stack((x, y))
    a = np.array([_x[0], _y_005[0]]) #first point of 0.05 quantile fit line
    b = np.array([_x[-1], _y_005[-1]]) #last point of 0.05 quantile fit line
    
    a_ = np.array([_x[0], _y_095[0]])
    b_ = np.array([_x[-1], _y_095[-1]])
    
    #mask based on if coordinates are above 0.95 or below 0.05 quantile fitlines using cross product
    mask = lambda p, a, b, a_, b_: (np.cross(p-a, b-a) > 0) | (np.cross(p-a_, b_-a_) < 0)
    mask = mask(p, a, b, a_, b_)
    
    axes.scatter(x[mask], df['NDVI'][mask], facecolor='r', edgecolor='none', alpha=0.3, label='data point')
    axes.scatter(x[~mask], df['NDVI'][~mask], facecolor='g', edgecolor='none', alpha=0.3, label='data point')
    
    axes.plot(x, fit[0] * x + fit[1], label='best fit', c='lightgrey')
    axes.plot(_x, _y_095, label=quantiles[1], c='orange')
    axes.plot(_x, _y_005, label=quantiles[0], c='lightblue')
    
    axes.legend()
    axes.set_xlabel('LST')
    axes.set_ylabel('NDVI')
    
    plt.show()
    

    【讨论】:

      猜你喜欢
      • 2019-10-31
      • 1970-01-01
      • 2021-12-10
      • 2011-09-07
      • 2020-08-18
      • 1970-01-01
      • 2020-02-20
      • 2020-08-26
      • 2018-12-18
      相关资源
      最近更新 更多