快速从 Python 中的列表中删除异常值?

Quickly remove outliers from list in Python?

我有很多时间和温度值的长列表,其结构如下:

list1 = [[1, 72], [2, 72], [3, 73], [4, 72], [5, 74], [6, 73], [7, 71], [8, 92], [9, 73]]

一些 time/temperature 对是数据中不正确的尖峰。例如,在时间 8 中,它飙升至 92 度。我想摆脱这些温度值的突然跳跃或骤降。

为此,我编写了以下代码(我删除了不需要的内容,只复制了删除 spikes/outliers 的部分):

outlierpercent = 3

for i in values:
    temperature = i[1]
    index = values.index(i)
    if index > 0:
        prevtemp = values[index-1][1]
        pctdiff = (temperature/prevtemp - 1) * 100
        if abs(pctdiff) > outlierpercent:
            outliers.append(i)

虽然这可行(我可以将它被视为尖峰所需的最小百分比差异设置为 outlierpercent),但它需要很长时间(每个列表 5-10 分钟)。我的列表非常长(每个大约 500 万个数据点),而且我有数百个列表。

我想知道是否有更快的方法?我主要关心的是时间。还有其他类似的问题,但是,对于这种结构的超长列表,它们似乎效率不高,所以我不确定该怎么做!谢谢!

outlierpercent = 3

for index in range(1, len(values)):
    temperature = values[index][1]
    prevtemp = values[index-1][1]

    pctdiff = (temperature/prevtemp - 1) * 100
    if abs(pctdiff) > outlierpercent:
        outliers.append(index)

随着时间的推移,这应该会做得更好

更新:

只有第一个异常值被移除的问题是因为在我们移除异常值之后,在下一次迭代中,我们正在比较移除的异常值(prevtemp = values[index-1][1])的温度。

我相信你可以通过更好地处理之前的温度来避免这种情况。像这样:

outlierpercent = 3
prevtemp = values[0][1]

for index in range(1, len(values)):
    temperature = values[index][1]

    pctdiff = (temperature/prevtemp - 1) * 100
    # outlier - add to list and don't update prev temp
    if abs(pctdiff) > outlierpercent:
        outliers.append(index)
    # valid temp, update prev temp
    else:
        prevtemp = values[index-1][1]

使用 Numpy 加速计算

values = [[1, 72], [2, 72], [3, 73], [4, 72], [5, 74], [6, 73], [7, 71], [8, 92], [9, 73]]

Numpy 代码

# Convert list to Numpy array
a = np.array(values)

# Calculate absolute percent difference of temperature
b = np.diff(a[:, 1])*100/a[:-1, 1]

# List of outliers
outlier_indices = np.where(np.abs(b) > outlierpercent)
if outlier_indices:
  print(a[outlier_indices[0]+1])  # add one since b is is one short due to 
                                  # computing difference
 # Output: List of outliers same as original code
[[ 8 92]
 [ 9 73]]

这应该生成两个列表,有效列表和离群值列表。

我试图将数学运算保持在最低限度以提高速度。

请原谅任何打字错误,这是键盘组成的,未经测试。

lolim=None
outliers=[]
outlierpercent=3.0
lower_mult=(100.0-outlierpercent)/100.0
upper_mult=(100.0+outlierpercent)/100.0
for index,temp in values
    if lolim is None:
         valids=[[index,temp]]            # start the valid list
         lolim,hilim=[lower_mult,upper_mult]*temp  # create initial range
    else:
         if lolim <= temp <= hilim:
             valids.append([index,temp])               # new valid entry
             lolim,hilim=[lower_mult,upper_mult]*temp  # update range
         else:
             outliers.append([index,temp])             # save outliers, keep old range