Найти cumsum subarrays, разбитый по индексам для массива numpy эффективно

Учитывая массив «массив» и набор индексов «индексы», как мне найти суммарную сумму суб-массивов, сформированных путем разбиения массива по этим индексам векторизованным образом? Чтобы уточнить, предположим, что у меня есть:

>>> array = np.arange(20) >>> array array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]) indices = np.arrray([3, 8, 14]) 

Операция должна выводиться:

  • Как найти все элементы в двумерном массиве numpy, который соответствует определенному списку?
  • Создайте массив numpy с несколькими настраиваемыми диапазонами индексов без явного цикла
  •  array([0, 1, 3, 3, 7, 12, 18, 25, 8, 17, 27, 38, 50, 63, 14, 29, 45, 62, 80, 99]) 

    Обратите внимание, что массив очень большой (100000 элементов), и поэтому мне нужен векторный ответ. Использование любых циклов значительно замедлит его. Кроме того, если бы у меня была такая же проблема, но для двумерного массива и соответствующих индексов, и мне нужно было сделать то же самое для каждой строки в массиве, как бы я это сделал?

    Для 2D-версии:

     >>>array = np.arange(12).reshape((3,4)) >>>array array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> indices = np.array([[2], [1, 3], [1, 2]]) 

    Результатом будет:

     array([[ 0, 1, 3, 3], [ 4, 9, 6, 13], [ 8, 17, 10, 11]]) 

    Чтобы уточнить: каждая строка будет разделена.

  • Панды: переформатирование данных
  • Векторизованный поиск
  • Производительность по разному методу векторизации в numpy
  • Вычисление числа конкретных последовательных равных значений в векторном виде в пандах
  • Векторизованный поиск значений в кадре данных Pandas
  • Получение подмассивов из массива numpy с заданным шагом / шагом
  • 2 Solutions collect form web for “Найти cumsum subarrays, разбитый по индексам для массива numpy эффективно”

    Вы можете ввести дифференциацию первоначально кумулятивно суммированного массива в позиции indices чтобы создать такой эффект в таких местах, чтобы при дифференцированном массиве кумулятивно суммировать, мы получаем обобщенный результат с суммированным индексом. Это может показаться немного надуманным с первого взгляда, но придерживаться его, попробовать с другими образцами и, надеюсь, будет иметь смысл! Идея очень похожа на ту, которая применяется в this other MATLAB solution. Итак, после такой философии здесь один подход, использующий numpy.diff наряду с cumulative summation

     # Get linear indices n = array.shape[1] lidx = np.hstack(([id*n+np.array(item) for id,item in enumerate(indices)])) # Get successive differentiations diffs = array.cumsum(1).ravel()[lidx] - array.ravel()[lidx] # Get previous group's offsetted summations for each row at all # indices positions across the entire 2D array _,idx = np.unique(lidx/n,return_index=True) offsetted_diffs = np.diff(np.append(0,diffs)) offsetted_diffs[idx] = diffs[idx] # Get a copy of input array and place previous group's offsetted summations # at indices. Then, do cumulative sum which will create a boundary like # effect with those offsets at indices positions. arrayc = array.copy() arrayc.ravel()[lidx] -= offsetted_diffs out = arrayc.cumsum(1) 

    Это должно быть почти векторизованное решение, почти потому, что даже если мы вычисляем линейные индексы в цикле, но поскольку это не вычислительно интенсивная часть здесь, так что влияние на общую продолжительность выполнения будет минимальным. Кроме того, вы можете заменить arrayc на array если вы не хотите разрушать вход для сохранения в памяти.

    Пример ввода, вывод –

     In [75]: array Out[75]: 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]]) In [76]: indices Out[76]: array([[3, 6], [4, 7], [5]], dtype=object) In [77]: out Out[77]: array([[ 0, 1, 3, 3, 7, 12, 6, 13], [ 8, 17, 27, 38, 12, 25, 39, 15], [16, 33, 51, 70, 90, 21, 43, 66]]) 

    Вы можете использовать np.split для разделения вашего массива по индексам, а затем используя встроенную map функций python, примените np.cumsum() к вашим вспомогательным массивам. И в конце, используя np.hstack преобразуйте результат в интегрированный массив:

     >>> np.hstack(map(np.cumsum,np.split(array,indices))) array([ 0, 1, 3, 3, 7, 12, 18, 25, 8, 17, 27, 38, 50, 63, 14, 29, 45, 62, 80, 99]) 

    Обратите внимание : поскольку map является встроенной функцией в python и реализован в C внутри интерпретатора Python, он будет работать лучше обычного цикла. 1

    Вот альтернатива для 2D-массивов:

     >>> def func(array,indices): ... return np.hstack(map(np.cumsum,np.split(array,indices))) ... >>> >>> array array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> >>> indices array([[2], [1, 3], [1, 2]], dtype=object) >>> np.array([func(arr,ind) for arr,ind in np.array((array,indices)).T]) array([[ 0, 1, 2, 5], [ 4, 5, 11, 7], [ 8, 9, 10, 21]]) 

    Обратите внимание, что ожидаемый результат не зависит от того, как работает np.split .

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

     >>> indices = np.array([[3], [2, 4], [2, 3]], dtype=object) >>> >>> np.array([func(arr,ind) for arr,ind in np.array((array,indices)).T]) array([[ 0., 1., 3., 3.], [ 4., 9., 6., 13.], [ 8., 17., 10., 11.]]) 

    Из-за комментария, в котором говорилось, что нет разницы в производительности между использованием выражения генератора и функцией map я провел тест, который демонстрирует результат лучше.

     # Use map ~$ python -m timeit --setup "import numpy as np;array = np.arange(20);indices = np.array([3, 8, 14])" "np.hstack(map(np.cumsum,np.split(array,indices)))" 10000 loops, best of 3: 72.1 usec per loop # Use generator expression ~$ python -m timeit --setup "import numpy as np;array = np.arange(20);indices = np.array([3, 8, 14])" "np.hstack(np.cumsum(a) for a in np.split(array,indices))" 10000 loops, best of 3: 81.2 usec per loop 

    Обратите внимание, что это не означает, что использование карты, которая выполняет на скорости C, делает этот код заготовкой на скорости C. Из-за этого код реализовал в python и вызвал функцию (первый аргумент) и применил ее к итерабельным элементам, потребовалось бы время.

    Python - лучший язык программирования в мире.