从不规则间隔的向量中选择近似规则的样本

时间:2018-09-26 06:57:56

标签: python numpy

这是我的问题,假设我有一个像这样的向量:

import numpy as np
idxx = np.array([0.        , 0.07665982, 0.24366872, 0.49555099, 0.74743326,
       1.07871321, 1.58247775, 2.24503765, 2.58179329, 3.16221766,
       3.74811773, 4.1615332 , 4.58042437, 5.33059548])

我感兴趣的是仅过滤掉0.250.51.0大约倍数的那些值。让我们从0.25开始,说明我正在寻找要返回的过滤器:

np.array([0.24366872, 0.49555099, 0.74743326,
       1.07871321, 1.58247775, 2.24503765, 2.58179329,
       3.74811773, 4.58042437, 5.33059548])

这里仅保留大约0.25倍数的值。实际上,我还需要保留第一个条目0.0,但在此演示中已将其删除。

如果我正在使用0.5,则结果将如下所示:

np.array([0.49555099, 1.07871321, 1.58247775, 2.58179329, 4.58042437])

我最初的尝试是:

import math
for i in idxx:
    g = 0.25
    k = i % g
    if math.isclose(k, g, rel_tol=0.5):
        print('This is reasonably close: ', i, '\n\t for modulus k == ', k, '\n')

仍然需要我做很多调优(而且我仍然无法过滤掉我想要的东西),所以我想知道是否有人有更好的方法来正确地做到这一点?

从本质上讲,我想选择那些不规则点(例如0.24366872)到“规则”间隔的网格(例如0.25间距)上,但是规则间隔的网格上的每个点都具有一定的容差,例如。 +/- 0.05,以适应实际数据中的不规则性。因此,我可以找到那些在此公差范围内的规则间隔的点。

2 个答案:

答案 0 :(得分:1)

您可能会稍微向后退。与其试图找到一个可行的公差(1.07871321确实会丢掉东西,不是吗),而是找到最靠近网格点的点。

这是一种非循环方法,会浪费内存,因为它会创建完整的idxx.sizen数组,其中n是网格的大小:

def grid_filter(idxx, spacing):
    # use idxx[0] instead of idxx.min() if idxx is sorted
    g0 = np.floor(idxx.min() / spacing) * spacing
    # use idxx[-1] instead of idxx.max() if idxx is sorted
    g1 = np.ceil(idxx.max() / spacing) * spacing
    # turn the grid into a column vector for broadcasting
    n = np.round((g1 - g0) / spacing) + 1
    grid = np.linspace(g0, g1, n).reshape(-1, 1)

    # compute the absolute distance to each point and
    # get the index of the point nearest each grid point:
    # rows are grid points, columns data points
    indices = np.abs(grid - idxx).argmin(axis=1)
    # post-process to ensure that a data point only matches one grid point
    indices = np.unique(indices)

    # apply the result
    return idxx[indices]

浪费的数组是grid - idxx。这可能不会成为问题。 grid_filter(idxx, 0.25)的结果是:

[ 0. 0.24366872 0.49555099 0.74743326 1.07871321 1.58247775 2.24503765 2.58179329 3.16221766 3.74811773 4.1615332 4.58042437 5.33059548]

如果您不满意3.164.16并使其成为结果,则可以使容差为spacing的1/3或类似的值,然后使用:

def tolerance_filter(idxx, spacing, tolerance):
    deltas = (idxx % spacing)
    deltas = np.minimum(deltas, spacing - deltas)
    candidates = deltas <  tolerance * spacing
    return idxx[candidates]

此解决方案实际上可以满足您的要求,并且已完全矢量化。 tolerance_filter(idxx, 0.25, 0.33)返回

[ 0. 0.07665982 0.24366872 0.49555099 0.74743326 1.07871321 1.58247775 2.24503765 2.58179329 3.74811773 4.58042437 5.33059548]

要进一步摆脱0.07665982,我建议结合以下方法:首先过滤以获取最接近每个网格点的元素,然后过滤绝对公差:

tolerance_filter(grid_filter(idxx, 0.25), 0.25, 0.33)

这时您可以做得更好:首先将每个数组元素附加到最近的网格点,如第一部分所示。然后做一些自适应的事情。例如,获取残差的标准偏差,并丢弃高于标称值3σ的任何内容:

def sigma_filter(idxx, spacing, nsigma):
    deltas = (idxx % spacing)
    deltas[deltas > 0.5 * spacing] -= spacing
    sigma = np.std(deltas)
    candidates = (np.abs(deltas) <= nsigma * sigma)
    return idxx[candidates]

答案 1 :(得分:0)

您需要正确管理+/-。一种简单的方法:

error=minimum(-idxx%.25,idxx%.25)
res= idxx[error<.05]
# [ 0.,  0.24366872,  0.49555099,  0.74743326,  2.24503765, 3.74811773]