найти и заменить ближайшие значения в массиве numpy относительно второго массива - PullRequest
0 голосов
/ 19 ноября 2018

У меня большой 2D np.array (vec).Я хотел бы заменить каждое значение в vec ближайшим значением из более короткого массива vals.

Я пробовал следующее

replaced_vals=vals[np.argmin(np.abs(vec[:, np.newaxis] - vals), axis=0)]

, но оно не работает, потому чтоРазмеры vec и vals различны.

Пример ввода

vec = np.array([10.1,10.7,11.4,102,1100]
vals = np.array([10.0,11.0,100.0])

Желаемый вывод:

replaced_vals = [10.0,11.0,11.0,100.0,100.0]

Ответы [ 3 ]

0 голосов
/ 19 ноября 2018

Если ваш массив vals отсортирован, более эффективное использование памяти и, возможно, в целом более эффективное решение возможно через np.searchsorted:

def jpp(vec, vals):
    ss = np.searchsorted(vals, vec)
    a = vals[ss - 1]
    b = vals[np.minimum(len(vals) - 1, ss)]
    return np.where(np.fabs(vec - a) < np.fabs(vec - b), a, b)

vec = np.array([10.1,10.7,11.4,102,1100])
vals = np.array([10.0,11.0,100.0])

print(jpp(vec, vals))

[  10.   11.   11.  100.  100.]

Сравнительный анализ производительности

# Python 3.6.0, NumPy 1.11.3

n = 10**6
vec = np.array([10.1,10.7,11.4,102,1100]*n)
vals = np.array([10.0,11.0,100.0])

# @ThomasPinetz's solution, memory inefficient
def tho(vec, vals):
    return vals[np.argmin(np.abs(vec[:, np.newaxis] - vals), axis=1)]

def jpp(vec, vals):
    ss = np.searchsorted(vals, vec)
    a = vals[ss - 1]
    b = vals[np.minimum(len(vals) - 1, ss)]
    return np.where(np.fabs(vec - a) < np.fabs(vec - b), a, b)

# @Divakar's solution, adapted from first related Q&A link
def diva(A, B):
    L = B.size
    sorted_idx = np.searchsorted(B, A)
    sorted_idx[sorted_idx==L] = L-1
    mask = (sorted_idx > 0) & \
    ((np.abs(A - B[sorted_idx-1]) < np.abs(A - B[sorted_idx])) )
    return B[sorted_idx-mask]

assert np.array_equal(tho(vec, vals), jpp(vec, vals))
assert np.array_equal(tho(vec, vals), diva(vec, vals))

%timeit tho(vec, vals)   # 366 ms per loop
%timeit jpp(vec, vals)   # 295 ms per loop
%timeit diva(vec, vals)  # 334 ms per loop

Связанные вопросы и ответы

  1. Найти ближайшие индексы для одного массива относительно всех значений в другом массиве - Python / NumPy
  2. Найти ближайшее значение в массиве NumPy
0 голосов
/ 19 ноября 2018

, если vals отсортировано, x_k с vec должно быть округлено до y_i с vals, если:

                           (y_(i-1)+y_i)/2 <= x_k < (y_i+y_(i+1))/2.    

Итак, еще одно решение, использующее np.searchsorted, но минимизирующее количество операций и как минимум вдвое быстрее:

def bm(vec, vals):
    half = vals.copy() / 2
    half[:-1] += half[1:]
    half[-1] = np.inf
    ss = np.searchsorted(half,vec)
    return vals[ss]

%timeit bm(vec, vals)  # 84 ms per loop

Если vals также отсортирован, вы можете закончить работу с numba для другого пробела:

from numba import njit
@njit
def bmm(vec,vals):
    half=vals.copy()/2
    half[:-1] += half[1:]
    half[-1]=np.inf
    res=np.empty_like(vec)
    i=0
    for k in range(vec.size):
        while half[i]<vec[k]:
            i+=1
        res[k]=vals[i]
    return res

%timeit bmm(vec, vals)  # 31 ms per loop
0 голосов
/ 19 ноября 2018

Вы должны смотреть вдоль другой оси, чтобы получить желаемые значения, например:

replaced_vals=vals[np.argmin(np.abs(vec[:, np.newaxis] - vals), axis=1)]

Выход для вашей проблемы:

array([  10.,   11.,   11.,  100.,  100.])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...