【问题标题】:Replacing abnormally large values with nan in a numpy array在numpy数组中用nan替换异常大的值
【发布时间】:2018-07-12 10:58:13
【问题描述】:

我正在尝试绘制的数据文件中有以下列。

[   2.21    2.34    2.56    2.78  180.      3.32    4.57    2.89  286.
    2.46    3.76    4.89   10.13]

因此,在我的数据集中,有时我的值会急剧增加,例如 (2.78 180 3.32) 和 (2.89 286 2.46)。我想用 np.nan 替换这个异常值。我正在尝试输入这样的条件 [if x(i)>5(x(i-1)+x(i+1)), then x(i)=np.nan] 这意味着每当第 i 个x 的值(x 是列值)比它的前一个值和下一个值大得多,python 将用 np.nan 替换该值,因此它不会被绘制或考虑。 但是我无法将其转换为编码格式。任何帮助都会非常有帮助。

import numpy as np
data=np.loadtxt('/Users/Hrihaan/Desktop/Data.txt')
x=data[:,1]
print(x)

【问题讨论】:

  • 边界条件是什么?

标签: python arrays numpy replace nan


【解决方案1】:

条件x(i)>5(x(i-1)+x(i+1)) 可以测试i = 1,...,n-1,其中nx 的最大允许索引。 为所有is 测试此条件的矢量化版本将是:

mask = (x[1:-1] > 5*(x[2:]+x[:-2]))

然后您可以使用以下方法将np.nan 分配给mask 为True 的位置:

x[1:-1][mask] = np.nan

注意x[1:-1]slice of x——这很重要,因为切片(与通过所谓的"advanced indexing" 获得的数组相反)是原始数组x 的视图。因此修改视图x[1:-1] 会影响原始数组x。因此,分配给x[1:-1][mask] 不仅会影响切片x[1:-1],还会影响x 本身。

使用布尔掩码进行索引调用高级索引,该索引返回一个新数组(不是视图)。所以相比之下,赋值x[mask][1:-1] = np.nan 将不起作用,因为修改x[mask] 不会影响x 本身。 (由于更普通的原因,它也不起作用——mask 的长度不正确。)


让我们试一试:

import numpy as np
x = np.array([ 2.21, 2.34, 2.56, 2.78, 180., 3.32, 4.57, 2.89, 286., 2.46, 3.76, 4.89, 10.13])
mask = (x[1:-1] > 5*(x[2:]+x[:-2]))
# array([False, False, False,  True, False, False, False,  True, False,
#        False, False], dtype=bool)
x[1:-1][mask] = np.nan

print(x)
# array([  2.21,   2.34,   2.56,   2.78,    nan,   3.32,   4.57,   2.89,
#         nan,   2.46,   3.76,   4.89,  10.13])

为了更好地理解(x[1:-1] > 5*(x[2:]+x[:-2])),看一个简化的例子会有所帮助:

In [57]: x = np.arange(8); x
Out[57]: array([0, 1, 2, 3, 4, 5, 6, 7])

x[2:]x 中切掉前两项:

In [58]: x[2:]
Out[58]: array([2, 3, 4, 5, 6, 7])

x[:-2]x 中切掉最后两项:

In [59]: x[:-2]
Out[59]: array([0, 1, 2, 3, 4, 5])

x[1:-1]x 中第一个和最后一个项目的切片:

In [60]: x[1:-1]
Out[60]: array([1, 2, 3, 4, 5, 6])

NumPy 算术以元素方式执行。所以(x[2:]+x[:-2])i=1,...,n-1 计算x(i-1)+x(i+1)

In [61]: (x[2:]+x[:-2])
Out[61]: array([ 2,  4,  6,  8, 10, 12])

所以我们有这种情况:

|   i | x(i-1) | x(i+1) | x(i)   |
|-----+--------+--------+--------|
|   1 | x(0)   | x(2)   | x(1)   |
|   2 | x(1)   | x(3)   | x(2)   |
|   3 | x(2)   | x(4)   | x(3)   |
| ... |        |        |        |
| n-1 | x(n-1) | x(n)   | x(n-1) |
|-----+--------+--------+--------|
        ^        ^        ^
        |        |        |
        |        |        o--- This column is the array x[1:-1]
        |        |
        |        o------------ This column is the array x[2:]
        |
        o--------------------- This column is the array x[:-2]

另一种看待它的方式是:一旦你知道条件是i=1,...,n-1,那么x(i) 显然会变成x[1:-1],因为它从索引 1 开始并在最后一个可能的索引之前结束 1 索引。 接下来,x(i-1)x(i+1) 可以被认为是x(i) 左右的元素。所以我们正在处理x[1:-1] 向左移动一个索引,向右移动一个索引。 因此,将x[1:-1] 向右移动一个索引会产生x[2:],将x[1:-1] 向左移动一个索引会产生x[:-2]


顺便说一句,beautiful properties 之一 Python 的半开切片语法是 x[a:b](b-a) 元素。所以 x[1:-1](相当于x[1:n-1])具有n-2 元素。注意到 有 2 个缺失的元素可以很容易地猜出相邻的数组 x[1:-1]x[2:]x[:-2]

【讨论】:

  • @Hrihaan:我在上面添加了一些内容,希望能解释这些索引的来源。
  • 非常感谢,所以我想知道我是否只想将条件应用于下一个值或上一个值,例如 x(i)>5(x(i+1)) 或 x( i)>5(x(i-1)),我尝试使用 mask = (x[1:-1] > 5*(x[2:]) 然后 x[1:-1][mask] = np.nan,但它给了我无效的语法错误。
  • @Hrihaan: mask = (x[1:-1] > 5*(x[2:]) 最后需要一个右括号。 (提示:使用具有brace matching 和一些组合键的文本编辑器会有所帮助,让您可以在右括号和大括号之间跳转光标。)
  • 所以,我尝试了这个数组 [12. 2. 3. 1. 22. 4. 5. 8. 10. 11.],其中第一个值 12 > 5*(下一个值是 2),也是第五个值 22 > 5*(下一个值是 4),所以 12 和 22 应该被替换为 nan,我使用 mask = (x[1:-1] > 2*( x[2:])) 然后是x[1:-1][mask1] = np.nan,但是没用,12和22没有被替换。
【解决方案2】:

如果异常值的出现很少见(根据定义,异常 == 罕见),那么使用整数索引而不是 @unutbu 的答案中使用的布尔索引会显着提高效率,尤其是在大型数组中:

import numpy as np
x = np.array([ 2.21, 2.34, 2.56, 2.78, 180., 3.32, 4.57, 2.89, 286., 2.46, 3.76, 4.89, 10.13])
xp = np.pad(x, 1, 'reflect') # to deal with boundaries
idx = np.where(x > 5*(xp[2:]+xp[:-2]))
x[idx] = np.nan

【讨论】:

    猜你喜欢
    • 2022-10-31
    • 2016-06-25
    • 2018-07-02
    • 2020-05-02
    • 2012-03-21
    • 1970-01-01
    • 2013-09-12
    • 2022-10-05
    • 1970-01-01
    相关资源
    最近更新 更多