#python #numpy #numpy-ndarray #numpy-slicing
#python #numpy #numpy-ndarray #numpy-нарезка
Вопрос:
a = np.array([2,3,1,4])
b = np.array([2,3,7,1])
c = np.zeros((4, 10))
Я хочу присвоить значение 1
некоторым элементам в c
. a
и b
определите позиции таких элементов. a
являются ли индексы начальных столбцов значениями 1
в каждой строке. И b
представляет, сколько последовательных 1
есть в строке. Результат, который я ожидаю, это:
array([[ 0., 0., 1., 1., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 1., 1., 1., 0., 0., 0., 0.],
[ 0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
[ 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]])
Я могу использовать простой цикл for, как показано ниже:
for i in range(c.shape[0]):
for k in range(a[i], a[i] b[i]):
c[i,k]=1
Но это было бы медленно для больших массивов, есть ли более быстрая индексация numpy для этого? Спасибо.
Комментарии:
1.
c[i, a[i]:a[i] b[i]] = 1
должно работать вместоk
цикла.2. да, моя главная проблема — это самый внешний цикл for .
3. Вы не можете справиться с внешним циклом, не имея сначала дело с внутренним.
4. Какова типичная форма c в вашем реальном варианте использования?
Ответ №1:
Я реализовал следующее решение без каких-либо циклов Python, просто чистый код NumPy. Возможно, это не так просто, как решение с циклом python, но определенно будет намного быстрее, особенно для больших данных.
import numpy as np
def set_val_2d(a, val, starts, lens):
begs = starts np.arange(a.shape[0]) * a.shape[1]
ends = begs lens
clens = lens.cumsum()
ix = np.ones((clens[-1],), dtype = np.int64)
ix[0] = begs[0]
ix[clens[:-1]] = begs[1:] - ends[:-1] 1
ix = ix.cumsum()
a.ravel()[ix] = val
a = np.array([2,3,1,4])
b = np.array([2,3,7,1])
c = np.zeros((4, 10))
set_val_2d(c, 1, a, b)
print(c)
Вывод:
[[0. 0. 1. 1. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 1. 1. 1. 0. 0. 0. 0.]
[0. 1. 1. 1. 1. 1. 1. 1. 0. 0.]
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]]
Ответ №2:
Вы можете преобразовать его в одномерную задачу
def convert_inds(a,b,array_shape):
nrows,ncols = array_shape
to_take = np.zeros(sum(b))
count = 0
for ind,item in enumerate(b):
start_ind = ind*ncols a[ind]
to_take[count:count item] = np.arange(start_ind,start_ind item)
count = item
return to_take.astype(np.int)
to_take = convert_inds(a,b,c.shape)
c.ravel()[to_take] = 1
В приведенном выше коде convert_inds
будет преобразовано a
и b
в
array([ 2, 3, 13, 14, 15, 21, 22, 23, 24, 25, 26, 27, 34])
какие индексы 1
s в сглаженном c
. Делая это, вам нужно только выполнить итерацию b
в функции convert_inds
.
Ответ №3:
Если вы выберете причудливый подход, основанный на индексации, самой сложной частью будет поиск индексов оси 1. Это очень похоже на:
>>> np.repeat(a, b)
array([2, 2, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 4])
за исключением того, что каждая группа индексов должна увеличиваться. Это исправление можно выполнить с помощью этой функции:
def accumulative_count(counts, initial):
counter = np.ones(np.sum(counts), dtype=int)
marker_idx = np.r_[0, np.cumsum(counts)[:-1]]
subtract_vals = np.r_[1, counts[:-1]]
initial_vals = np.r_[initial[0], np.diff(initial)]
counter[marker_idx] = counter[marker_idx] - subtract_vals initial_vals
return np.cumsum(counter)
>>> accumulative_count(counts, initial)
array([2, 3, 3, 4, 5, 1, 2, 3, 4, 5, 6, 7, 4], dtype=int32)
В конце концов, вы способны его завершить:
c[np.repeat(np.arange(len(c)), b), accumulative_count(b, a)] = 1
c:
array([[0., 0., 1., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 1., 1., 0., 0., 0., 0.],
[0., 1., 1., 1., 1., 1., 1., 1., 0., 0.],
[0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]])