【问题标题】:Python: Find outliers inside a listPython:查找列表中的异常值
【发布时间】:2020-10-29 07:01:59
【问题描述】:

我有一个包含随机数量的整数和/或浮点数的列表。我想要实现的是在我的数字中找到异常(希望用正确的词来解释这一点)。例如:

list = [1, 3, 2, 14, 108, 2, 1, 8, 97, 1, 4, 3, 5]
  • 90% 到 99% 的整数值在 1 到 20 之间
  • 有时会有更高的值,比如大约 100 或 1.000 甚至更多

我的问题是,这些值可能一直都不同。也许常规范围在 1.000 到 1.200 之间,例外情况在 50 万之间。

有过滤掉这些特殊数字的功能吗?

【问题讨论】:

  • 类似计算standard deviation?
  • 您正在寻找“异常值”。困难的部分是确定如何定义异常值。如果您的大多数数字都符合一个分布,例如正态分布,您可以将您的数据拟合到一个分布中,并找出在统计上不太可能来自该分布的点。
  • 这能回答你的问题吗? stackoverflow.com/questions/57161413/…
  • @James 谢谢!即使知道它们被称为“异常值”也确实有助于我的搜索。
  • @DeepSpace 很好的建议,谢谢!我要读这篇文章。

标签: python list range


【解决方案1】:

假设你的列表是l:

  • 如果您知道要过滤某个百分位数/分位数,您可以 使用:

    这会删除底部 10% 和顶部 90%。当然,您可以更改任何 它们达到您想要的截止值(例如,您可以移除底部过滤器,仅过滤示例中的前 90%):

    import numpy as np
    l = np.array(l)
    l = l[(l>np.quantile(l,0.1)) & (l<np.quantile(l,0.9))].tolist()
    

    输出:

    [ 3  2 14  2  8  4  3  5]
    
  • 如果您不确定百分位分界点并希望 去除异常值:

    您可以通过调整参数 m 来调整异常值的截止值 函数调用。它越大,去除的异常值越少。与其他异常值去除技术相比,此函数似乎对各种类型的异常值更稳健。

     import numpy as np 
     l = np.array(l) 
     def reject_outliers(data, m=6.):
        d = np.abs(data - np.median(data))
        mdev = np.median(d)
        s = d / (mdev if mdev else 1.)
        return data[s < m].tolist()
     print(reject_outliers(l))
    

    输出:

    [1, 3, 2, 14, 2, 1, 8, 1, 4, 3, 5]
    

【讨论】:

  • 完美运行!谢谢!
  • 您好!你能解释一下你的第二个功能的步骤吗?例如,你为什么要找到中位数两次(第一次是数据,然后是 d?“mdev if mdev else 1.”的目的是什么?最后,“s”代表什么以及为什么截断 s
【解决方案2】:

可以使用内置的filter()方法:

lst1 = [1, 3, 2, 14, 108, 2, 1, 8, 97, 1, 4, 3, 5]

lst2 = list(filter(lambda x: x > 5,lst1))

print(lst2)

输出:

[14, 108, 8, 97]

【讨论】:

  • 来自 OP:“我的问题是,这些值可能一直都不同。也许常规范围在 1.000 到 1.200 之间,例外情况在 50 万之间。”我认为这里的想法是没有 5 或任何其他硬编码的值
  • @DeepSpace regular range 是什么意思?
  • OP 表示可以接受的数字范围
【解决方案3】:

所以这里有一个方法来阻止这些偏差

import math
_list = [1, 3, 2, 14, 108, 2, 1, 8, 97, 1, 4, 3, 5]
def consts(_list):
    mu = 0
    for i in _list:
        mu += i
    mu = mu/len(_list)
    sigma = 0
    for i in _list:
        sigma += math.pow(i-mu,2)
    sigma = math.sqrt(sigma/len(_list))
    return sigma, mu

def frequence(x, sigma, mu):
    return (1/(sigma*math.sqrt(2*math.pi)))*math.exp(-(1/2)*math.pow(((x-mu)/sigma),2))

sigma, mu = consts(_list)

new_list = []
for i in range(len(_list)):
    if frequence(_list[i], sigma, mu) > 0.01:
        new_list.append(i)
print(new_list)

【讨论】:

  • 来自 OP:“我的问题是,这些值可能一直都不同。也许常规范围在 1.000 到 1.200 之间,例外情况在 50 万之间。”我认为这里的想法是没有 20 或任何其他硬编码值。此外,您在迭代时从列表中删除元素,这绝不是一个好主意(即使您发布的代码也会导致 @987654323 @)
  • 好吧,你不喜欢我创建一个函数来检测正常的分布,然后删除那些不被接受的,,...
  • @DeepSpace 你是对的!这个想法实际上是没有像本例中的 20 这样的硬编码值。
  • 是的,所以如果你创建一个正态分布并删除不太正态的分布,那么你会得到最大值和最小值(ouliers),然后你只需弹出它们。 :)
  • @mama 试过了,但不幸的是效果不佳。函数会弹出一些应该在可接受范围内的值。但无论如何,非常感谢您的帮助!
猜你喜欢
  • 2012-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-17
  • 2021-09-16
  • 2017-11-13
  • 2020-02-16
相关资源
最近更新 更多