Учитывая ndarray x
и одномерный массив, содержащий длину смежных срезов измерения x
, я хочу вычислить новый массив, содержащий сумму всех срезов. Например, в двух измерениях суммируя по одномерно:сумма неровных сегментов массива в numpy
>>> lens = np.array([1, 3, 2])
array([1, 3, 2])
>>> x = np.arange(4 * lens.sum()).reshape((4, lens.sum())).astype(float)
array([[ 0., 1., 2., 3., 4., 5.],
[ 6., 7., 8., 9., 10., 11.],
[ 12., 13., 14., 15., 16., 17.],
[ 18., 19., 20., 21., 22., 23.]])
# I want to compute:
>>> result
array([[ 0., 6., 9.],
[ 6., 24., 21.],
[ 12., 42., 33.],
[ 18., 60., 45.]])
# 0 = 0
# 6 = 1 + 2 + 3
# ...
# 45 = 22 + 23
два способа, которые приходят на ум:
а) Используйте cumsum и фантазии индексацию:
def cumsum_method(x, lens):
xc = x.cumsum(1)
lc = lens.cumsum() - 1
res = xc[:, lc]
res[:, 1:] -= xc[:, lc[:-1]]
return res
б) Используйте bincount и разумно сгенерировать соответствующие бункеры:
def bincount_method(x, lens):
bins = np.arange(lens.size).repeat(lens) + \
np.arange(x.shape[0])[:, None] * lens.size
return np.bincount(bins.flat, weights=x.flat).reshape((-1, lens.size))
Сроки эти два на больших i nput имел метод cumsum, выполняющий несколько лучше:
>>> lens = np.random.randint(1, 100, 100)
>>> x = np.random.random((100000, lens.sum()))
>>> %timeit cumsum_method(x, lens)
1 loops, best of 3: 3 s per loop
>>> %timeit bincount_method(x, lens)
1 loops, best of 3: 3.9 s per loop
Есть ли более эффективный способ, которым я не хватает? Кажется, что нативный вызов c будет быстрее, потому что ему не потребуется выделять массив cumsum или bins. Функция numpy builtin, которая делает что-то близкое к этому, может быть лучше, чем (a) или (b). Я ничего не смог найти, выполнив поиск и просмотрев документацию.
Примечание: это похоже на this question, но интервалы суммирования не являются регулярными.
Это также имеет хорошую выгоду легко применять к любой размерности. – Erik