Python / NumPy: найти первый нулевой индекс, затем заменить все элементы на ноль после этого для каждой строки - PullRequest
0 голосов
/ 29 мая 2020

У меня есть массив numpy вроде этого:

a = np.array([[1, 0, 1, 1, 1],
              [1, 1, 1, 1, 0],
              [1, 0, 0, 1, 1],
              [1, 0, 1, 0, 1]])

Вопрос 1: Как показано в заголовке, я хочу заменить все элементы на ноль после появления первого нуля. Результат должен быть таким:

a = np.array([[1, 0, 0, 0, 0],
              [1, 1, 1, 1, 0],
              [1, 0, 0, 0, 0],
              [1, 0, 0, 0, 0]])

Вопрос 2: как разрезать разные столбцы для каждой строки, как в этом примере? Поскольку я имею дело с массивом большого размера. Если кто-нибудь может найти эффективный способ решить эту проблему, пожалуйста. Большое спасибо.

Ответы [ 4 ]

3 голосов
/ 29 мая 2020

Один из способов выполнить sh вопрос 1 - использовать numpy .cumprod

>>> np.cumprod(a, axis=1)
array([[1, 0, 0, 0, 0],
       [1, 1, 1, 1, 0],
       [1, 0, 0, 0, 0],
       [1, 0, 0, 0, 0]])
0 голосов
/ 29 мая 2020

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

indexer = tuple(np.s_[i:a.shape[1]] for i in (a==0).argmax(axis=1))
for i,j in enumerate(indexer):
    a[i,j]=0

indexer:

(slice(1, 5, None), slice(4, 5, None), slice(1, 5, None), slice(1, 5, None))

или:

indexer = (a==0).argmax(axis=1)
for i in range(a.shape[0]):
    a[i,indexer[i]:]=0

индексатор:

[1 4 1 1]

вывод:

[[1 0 0 0 0]
 [1 1 1 1 0]
 [1 0 0 0 0]
 [1 0 0 0 0]]
0 голосов
/ 29 мая 2020

Вопрос 1 : Эффективный способ сделать это:

import numpy as np

a = np.array([[1, 0, 1, 1, 1],
              [1, 1, 1, 1, 0],
              [1, 0, 0, 1, 1],
              [1, 0, 1, 0, 1]])

for row in a:
    zeros = np.where(row == 0)[0]
    if (len(zeros)):# Check if zero exists
        row[zeros[0]:] = 0

print(a)

Вывод:

[[1 0 0 0 0]
 [1 1 1 1 0]
 [1 0 0 0 0]
 [1 0 0 0 0]]

Вопрос 2 : Используя один и тот же массив для каждой строки rowIdx, вы можете получить массив столбцов colIdxs, из которого вы хотите извлечь.

rowIdx = 2
colIdxs = [1, 3, 4]
print(a[rowIdx, colIdxs])

Вывод:

[0 1 1]
0 голосов
/ 29 мая 2020

Вопрос 1 : Вы можете перебирать массив следующим образом:

for i in range(a.shape[0]):
    j = 0
    row = a[i]
    while row[j]>0:
        j += 1
    row[j+1:] = 0

Это изменит массив на месте. Если вас интересует очень высокая производительность, ответы на этот вопрос могут быть полезны для более быстрого поиска первого нуля. np.where сканирует весь массив для этого и поэтому не является оптимальным для задачи. На самом деле, самое быстрое решение будет немного зависеть от распределения записей в вашем массиве: если там много чисел с плавающей запятой и редко бывает ноль, циклы while в приведенном выше коде будут прерываться в среднем поздно, требуя только записи " несколько "нулей". Если, однако, есть только две возможные записи, как в вашем массиве примеров, и они происходят с аналогичной вероятностью (т.е. ~ 50%), в a будет записано много нулей, и следующее будет быстрее:

b = np.zeros(a.shape)
for i in range(a.shape[0]):
    j = 0
    a_row = a[i]
    b_row = b[i]
    while a_row[j]>0:
        b_row[j] = a_row[j]
        j += 1

Вопрос 2 : Если вы хотите разрезать каждую строку индивидуально по аналогичному критерию, имеющему дело с первым вхождением какого-либо вида, вы можете просто адаптировать этот шаблон итерации. Если критерий более глобальный (например, поиск максимума строки), существуют встроенные методы, такие как np.where, которые будут более эффективными, но, вероятно, это будет немного зависеть от самого критерия, какой выбор лучше.

...