Numpy: поиск минимальных и максимальных значений из ассоциаций через биннинг

необходимое условие

Это вопрос, полученный из этого поста. Таким образом, некоторые из введения проблемы будут похожи на этот пост.

проблема

Скажем result это 2D массив и values является одномерным массивом values содержит некоторые значения, связанные с каждым элементом в result, Отображение элемента в values в result хранится в x_mapping а также y_mapping, Положение в result могут быть связаны с разными значениями. Теперь я должен найти минимум и максимум значений, сгруппированных по ассоциациям.

Пример для лучшего разъяснения.

min_result массив:

[[0, 0],
[0, 0],
[0, 0],
[0, 0]]

max_result массив:

[[0, 0],
[0, 0],
[0, 0],
[0, 0]]

values массив:

[ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.]

Примечание: здесь result массивы и values имеют одинаковое количество элементов. Но это может быть не так. Между размерами нет никакой связи.

x_mapping а также y_mapping есть отображения из 1D values в 2D result(как мин, так и макс). Размеры x_mapping, y_mapping а также values будет таким же.

x_mapping - [0, 1, 0, 0, 0, 0, 0, 0]

y_mapping - [0, 3, 2, 2, 0, 3, 2, 1]

Здесь 1-е значение (values[0]) и 5-е значение (values[4]) иметь х как 0 и у как 0(x_mapping[0] а также y_mappping[0]) и, следовательно, связано с result[0, 0], Если мы вычислим минимум и максимум из этой группы, мы получим 1 и 5 в качестве результатов соответственно. Так, min_result[0, 0] будет 1 и max_result[0, 0] будет 5.

Обратите внимание, что если нет никакой связи, то значение по умолчанию для result будет ноль.

Текущее рабочее решение

x_mapping = np.array([0, 1, 0, 0, 0, 0, 0, 0])
y_mapping = np.array([0, 3, 2, 2, 0, 3, 2, 1])
values = np.array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.], dtype=np.float32)
max_result = np.zeros([4, 2], dtype=np.float32)
min_result = np.zeros([4, 2], dtype=np.float32) 
min_result[-y_mapping, x_mapping] = values # randomly initialising from values
for i in range(values.size):
    x = x_mapping[i]
    y = y_mapping[i]
    # maximum
    if values[i] > max_result[-y, x]:
        max_result[-y, x] = values[i]
    # minimum
    if values[i] < min_result[-y, x]:
        min_result[-y, x] = values[i]

min_result,

[[1., 0.],
[6., 2.],
[3., 0.],
[8., 0.]]

max_result,

[[5., 0.],
[6., 2.],
[7., 0.],
[8., 0.]]

Неудачные решения

# 1

min_result = np.zeros([4, 2], dtype=np.float32)
np.minimum.reduceat(values, [-y_mapping, x_mapping], out=min_result)

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-17-126de899a90e> in <module>()
1 min_result = np.zeros([4, 2], dtype=np.float32)
----> 2 np.minimum.reduceat(values, [-y_mapping, x_mapping], out=min_result)

ValueError: object too deep for desired array

# 2

min_result = np.zeros([4, 2], dtype=np.float32)
np.minimum.reduceat(values, lidx, out= min_result)

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-24-07e8c75ccaa5> in <module>()
1 min_result = np.zeros([4, 2], dtype=np.float32)
----> 2 np.minimum.reduceat(values, lidx, out= min_result)

ValueError: operands could not be broadcast together with remapped shapes [original->remapped]: (4,2)->(4,) (8,)->() (8,)->(8,) 

# 3

lidx = ((-y_mapping) % 4) * 2 + x_mapping #from mentioned post
min_result = np.zeros([8], dtype=np.float32)
np.minimum.reduceat(values, lidx, out= min_result).reshape(4,2)

[[1., 4.],
[5., 5.],
[1., 3.],
[5., 7.]]

Вопрос

Как пользоваться np.minimum.reduceat а также np.maximum.reduceat для решения этой проблемы? Я ищу решение, оптимизированное для времени выполнения.

Примечание

Я использую Numpy версии 1.14.3 с Python 3.5.2

1 ответ

Решение

Подход № 1

Опять же, самые интуитивные были бы с numpy.ufunc.at, Теперь, поскольку эти сокращения будут выполняться по отношению к существующим значениям, нам нужно инициализировать вывод с максимальными значениями для минимальных сокращений и минимальными значениями для максимальных. Следовательно, реализация будет -

min_result[-y_mapping, x_mapping] = values.max()
max_result[-y_mapping, x_mapping] = values.min()

np.minimum.at(min_result, [-y_mapping, x_mapping], values)
np.maximum.at(max_result, [-y_mapping, x_mapping], values)

Подход № 2

Использовать np.ufunc.reduceat нам нужно отсортировать данные -

m,n = max_result.shape
out_dtype = max_result.dtype
lidx = ((-y_mapping)%m)*n + x_mapping

sidx = lidx.argsort()
idx = lidx[sidx]
val = values[sidx]

m_idx = np.flatnonzero(np.r_[True,idx[:-1] != idx[1:]])
unq_ids = idx[m_idx]

max_result_out.flat[unq_ids] = np.maximum.reduceat(val, m_idx)
min_result_out.flat[unq_ids] = np.minimum.reduceat(val, m_idx)
Другие вопросы по тегам