Конвертировать 1D массив с координатами в 2D массив в NumPy - PullRequest
2 голосов
/ 05 июня 2019

У меня есть массив значений arr с формой (N,) и массив координат coords с формой (N, 2).Я хочу представить это в (M, M) массиве grid, так что grid принимает значение 0 в координатах, которых нет в coords, и для включенных координат оно должно хранить сумму всех значенийв arr, которые имеют эту координату.Поэтому, если M = 3, arr = np.arange(4)+1 и coords = np.array([[0,0,1,2],[0,0,2,2]]), тогда grid должно быть:

array([[3., 0., 0.],
       [0., 0., 3.],
       [0., 0., 4.]])

Причина, по которой это нетривиально, заключается в том, что мне нужно иметь возможность повторять этот шаг много раз, изначения в arr меняются каждый раз, как и координаты.В идеале я ищу векторизованное решение.Я подозреваю, что я мог бы каким-то образом использовать np.where, но не сразу понятно, как.

Время решения

Я рассчитал время решения, представленные в настоящее времяи кажется, что метод накопления немного быстрее, чем метод разреженной матрицы, причем второй метод накопления является самым медленным по причинам, объясненным в комментариях:

%timeit for x in range(100): accumulate_arr(np.random.randint(100,size=(2,10000)),np.random.normal(0,1,10000))
%timeit for x in range(100): accumulate_arr_v2(np.random.randint(100,size=(2,10000)),np.random.normal(0,1,10000))
%timeit for x in range(100): sparse.coo_matrix((np.random.normal(0,1,10000),np.random.randint(100,size=(2,10000))),(100,100)).A
47.3 ms ± 1.79 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
103 ms ± 255 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
48.2 ms ± 36 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Ответы [ 2 ]

3 голосов
/ 05 июня 2019

Один из способов - создать sparse.coo_matrix и преобразовать его в плотный:

from scipy import sparse
sparse.coo_matrix((arr,coords),(M,M)).A
# array([[3, 0, 0],
#        [0, 0, 3],
#        [0, 0, 4]])
2 голосов
/ 05 июня 2019

С np.bincount -

def accumulate_arr(coords, arr):
    # Get output array shape
    m,n = coords.max(1)+1

    # Get linear indices to be used as IDs with bincount
    lidx = np.ravel_multi_index(coords, (m,n))
    # Or lidx = coords[0]*(coords[1].max()+1) + coords[1]

    # Accumulate arr with IDs from lidx
    return np.bincount(lidx,arr,minlength=m*n).reshape(m,n)

Пробный прогон -

In [58]: arr
Out[58]: array([1, 2, 3, 4])

In [59]: coords
Out[59]: 
array([[0, 0, 1, 2],
       [0, 0, 2, 2]])

In [60]: accumulate_arr(coords, arr)
Out[60]: 
array([[3., 0., 0.],
       [0., 0., 3.],
       [0., 0., 4.]])

Еще один с np.add.at на похожих строках, и за ним может быть проще следовать -

def accumulate_arr_v2(coords, arr):
    m,n = coords.max(1)+1
    out = np.zeros((m,n), dtype=arr.dtype)
    np.add.at(out, tuple(coords), arr)
    return out
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...