Отбор приблизительно регулярных выборок из нерегулярно разнесенного вектора - PullRequest
0 голосов
/ 26 сентября 2018

Это моя проблема, предположим, у меня есть такой вектор:

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.25, 0.5 и 1.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 голосов
/ 26 сентября 2018

Возможно, вы идете немного назад.Вместо того, чтобы пытаться найти допустимое отклонение (которое 1.07871321 действительно отбрасывает вещи, не так ли), просто найдите точку, которая ближе всего к вашим точкам сетки.

Вот нецикличный подходэто бесполезно расходует память, поскольку создает полный массив idxx.size -by- n, где 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.16 и 4.16 делают это результатом, вы можете сделать допуск 1/3 spacing или что-то подобноеи работайте с этим:

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]
0 голосов
/ 26 сентября 2018

Вам необходимо правильно управлять +/-.Простой способ сделать это:

error=minimum(-idxx%.25,idxx%.25)
res= idxx[error<.05]
# [ 0.,  0.24366872,  0.49555099,  0.74743326,  2.24503765, 3.74811773]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...