【问题标题】:Filtering Outliers - how to make median-based Hampel Function faster?过滤异常值 - 如何使基于中值的 Hampel 函数更快?
【发布时间】:2018-03-30 20:43:54
【问题描述】:

我需要对我的数据使用 Hampel 过滤器,去除异常值。

我无法在 Python 中找到现有的;仅在 Matlab 和 R 中。

[Matlab函数说明][1]

[Matlab Hampel函数的Stats Exchange讨论][2]

[R pracma 包小插曲;包含hampel函数][3]

我编写了以下函数,对 R pracma 包中的函数进行了建模;但是,它比 Matlab 版本慢得多。这并不理想;希望能提供有关如何加快速度的意见。

功能如下图-

def hampel(x,k, t0=3):
    '''adapted from hampel function in R package pracma
    x= 1-d numpy array of numbers to be filtered
    k= number of items in window/2 (# forward and backward wanted to capture in median filter)
    t0= number of standard deviations to use; 3 is default
    '''
    n = len(x)
    y = x #y is the corrected series
    L = 1.4826
    for i in range((k + 1),(n - k)):
        if np.isnan(x[(i - k):(i + k+1)]).all():
            continue
        x0 = np.nanmedian(x[(i - k):(i + k+1)])
        S0 = L * np.nanmedian(np.abs(x[(i - k):(i + k+1)] - x0))
        if (np.abs(x[i] - x0) > t0 * S0):
            y[i] = x0
    return(y)

“pracma”包中的 R 实现,我将其用作模型:

function (x, k, t0 = 3) 
{
    n <- length(x)
    y <- x
    ind <- c()
    L <- 1.4826
    for (i in (k + 1):(n - k)) {
        x0 <- median(x[(i - k):(i + k)])
        S0 <- L * median(abs(x[(i - k):(i + k)] - x0))
        if (abs(x[i] - x0) > t0 * S0) {
            y[i] <- x0
            ind <- c(ind, i)
        }
    }
    list(y = y, ind = ind)
}

任何有助于提高函数效率的帮助,或指向现有 Python 模块中现有实现的指针将不胜感激。下面的示例数据; Jupyter 中的 %%timeit 单元魔法表明当前需要 15 秒才能运行:

vals=np.random.randn(250000)
vals[3000]=100
vals[200]=-9000
vals[-300]=8922273
%%timeit
hampel(vals, k=6)

[1]:https://www.mathworks.com/help/signal/ref/hampel.html [2]:https://dsp.stackexchange.com/questions/26552/what-is-a-hampel-filter-and-how-does-it-work [3]:https://cran.r-project.org/web/packages/pracma/pracma.pdf

【问题讨论】:

  • 感谢@EHB 的实施。我已经使用过它,在大多数情况下它确实对我有用。但是我发现如果它们位于时间序列的末尾,它就无法找到峰值。有什么办法可以修改过滤器以找到尖峰,如果它们在最后?
  • @ Lufy,如果不是严格需要的话,也许只是删除你系列中的最后几个测量值?如果您找到一个好的答案,请在此处添加:)

标签: python function pandas filter


【解决方案1】:

上面@EHB 的解决方案很有帮助,但不正确。具体来说,median_abs_deviation中计算的滚动中位数是有difference的,其本身就是每个数据点与rolling_median中计算的滚动中位数的差值,但它应该是滚动窗口中数据与窗口中位数之间差异的中位数。我把上面的代码修改了一下:

def hampel(vals_orig, k=7, t0=3):
    '''
    vals: pandas series of values from which to remove outliers
    k: size of window (including the sample; 7 is equal to 3 on either side of value)
    '''
    
    #Make copy so original not edited
    vals = vals_orig.copy()
    
    #Hampel Filter
    L = 1.4826
    rolling_median = vals.rolling(window=k, center=True).median()
    MAD = lambda x: np.median(np.abs(x - np.median(x)))
    rolling_MAD = vals.rolling(window=k, center=True).apply(MAD)
    threshold = t0 * L * rolling_MAD
    difference = np.abs(vals - rolling_median)
    
    '''
    Perhaps a condition should be added here in the case that the threshold value
    is 0.0; maybe do not mark as outlier. MAD may be 0.0 without the original values
    being equal. See differences between MAD vs SDV.
    '''
    
    outlier_idx = difference > threshold
    vals[outlier_idx] = rolling_median[outlier_idx] 
    return(vals)

【讨论】:

  • @RachelCyr,在这种情况下,L 代表高斯分布的比例因子。
【解决方案2】:

Pandas 解决方案的速度要快几个数量级:

def hampel(vals_orig, k=7, t0=3):
    '''
    vals: pandas series of values from which to remove outliers
    k: size of window (including the sample; 7 is equal to 3 on either side of value)
    '''
    #Make copy so original not edited
    vals=vals_orig.copy()    
    #Hampel Filter
    L= 1.4826
    rolling_median=vals.rolling(k).median()
    difference=np.abs(rolling_median-vals)
    median_abs_deviation=difference.rolling(k).median()
    threshold= t0 *L * median_abs_deviation
    outlier_idx=difference>threshold
    vals[outlier_idx]=np.nan
    return(vals)

这个时间是 11 毫秒 vs 15 秒;巨大的进步。

我在this post.找到了类似过滤器的解决方案

【讨论】:

  • 我同意@EduardoOsorio 这个实现也不正确。您应该在解决方案中编辑 median_abs_deviation 的计算。
  • 乍一看,我认为 Eduardo 的解决方案和你的解决方案是等价的,但实际上这有一个细微的错误。最好手动做一个小例子来验证。
猜你喜欢
  • 2018-12-05
  • 2016-04-09
  • 1970-01-01
  • 1970-01-01
  • 2018-11-19
  • 2018-04-08
  • 1970-01-01
  • 2021-10-19
  • 2018-11-19
相关资源
最近更新 更多