Чтобы ответить на вопрос, почему ограничения не работают, давайте рассмотрим одно из них, например (подставив значение d[0]
, поскольку список d
на самом деле не помогает нам ни в решении проблемы, ни в упрощение кода):
a[r-1, c] > 0 and r >= 0
Короткое замыкание and
можно использовать, чтобы убедиться, что значение не проверяется, да. Но короткое замыкание работает наоборот. В этом примере a[d[0], c] > 0
проверяется безоговорочно, а затем r >= 0
проверяется только в том случае, если первое, что привело к истинному значению. Но первая часть вызывает ошибку, поэтому вторая уже слишком поздно, чтобы предотвратить ошибку. Вы хотели r >= 0 and a[r-1, c] > 0
. (Заменяя r-1
на d[0]
, становится понятнее: мы проверяем значение r
, а , затем пробуем индексирование, использующее r
.)
Но мы можем добиться большего, если воспользуемся преимуществами операций Numpy. Numpy в значительной степени специально разработан, чтобы упростить кодирование таких проблем и сделать их более производительными.
Первое, что мы хотим сделать, это увидеть места, где есть ненулевые значения в данных :
>>> a = np.array([
... [0, 16, 12, 21, 0, 0, 0],
... [16, 0, 0, 17, 20, 0, 0],
... [12, 0, 0, 28, 0, 31, 0],
... [21, 17, 28, 0, 18, 19, 23],
... [0, 20, 0, 18, 0, 0, 11],
... [0, 0, 31, 19, 0, 0, 27],
... [0, 0, 0, 23, 11, 27, 0]
... ], dtype = np.uint8)
>>> a
array([[ 0, 16, 12, 21, 0, 0, 0],
[16, 0, 0, 17, 20, 0, 0],
[12, 0, 0, 28, 0, 31, 0],
[21, 17, 28, 0, 18, 19, 23],
[ 0, 20, 0, 18, 0, 0, 11],
[ 0, 0, 31, 19, 0, 0, 27],
[ 0, 0, 0, 23, 11, 27, 0]], dtype=uint8)
>>> a != 0 # Yes, it's really *this* easy
array([[False, True, True, True, False, False, False],
[ True, False, False, True, True, False, False],
[ True, False, False, True, False, True, False],
[ True, True, True, False, True, True, True],
[False, True, False, True, False, False, True],
[False, False, True, True, False, False, True],
[False, False, False, True, True, True, False]])
И давайте получим индексы этих позиций:
>>> np.where(a != 0)
(array([0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6,
6, 6], dtype=int64), array([1, 2, 3, 0, 3, 4, 0, 3, 5, 0, 1, 2, 4, 5, 6, 1, 3, 6, 2, 3, 6, 3,
4, 5], dtype=int64))
Этот результат немного сложно понять; мы получаем кортеж из двух одномерных массивов, представляющих все x-координаты и y-координаты ненулевых значений (они также сохраняются с использованием собственного целочисленного типа вашей системы, поскольку они являются индексами; как вы можете видеть , Я на 64-битной машине). К счастью, Numpy также легко объединить их в пары:
>>> np.transpose(np.where(a != 0))
# long output omitted
Это все хорошо, но как теперь искать соседей? Я рассмотрю случай соседей выше текущей позиции, а остальное оставлю в качестве упражнения.
Мы сделаем это, построив массив, значения которого представляют те, которые находятся над исходной позицией массива ( заполнение нулями верхнего ряда). Мы делаем это, разрезая массив, а затем добавляя строку. Нам нужны все строки, кроме last , а затем мы заполняем нулями top . Но более простой способ сделать это - начать с двумерного массива нулей равного размера и поместить соответствующие строки в нижнюю . Итак:
>>> above = np.zeros(a.shape, dtype=np.uint8)
>>> above[1:, :] = a[:-1, :]
>>> above
array([[ 0, 0, 0, 0, 0, 0, 0],
[ 0, 16, 12, 21, 0, 0, 0],
[16, 0, 0, 17, 20, 0, 0],
[12, 0, 0, 28, 0, 31, 0],
[21, 17, 28, 0, 18, 19, 23],
[ 0, 20, 0, 18, 0, 0, 11],
[ 0, 0, 31, 19, 0, 0, 27]], dtype=uint8)
Обратите внимание на пары значений, используемые для нарезки: каждая соответствует отдельному измерению массива. Таким образом, [1:, :]
выполняет срезы начиная со строки 1 и далее, сохраняя все столбцы в качестве места назначения; [:-1, :]
нарезает каждую строку, кроме последней, в качестве наших исходных данных.
Теперь мы можем проверить ненулевые места, а также ненулевые соседние элементы выше:
>>> (a != 0) & (above != 0)
array([[False, False, False, False, False, False, False],
[False, False, False, True, False, False, False],
[ True, False, False, True, False, False, False],
[ True, False, False, False, False, True, False],
[False, True, False, False, False, False, True],
[False, False, False, True, False, False, True],
[False, False, False, True, False, False, False]])
(Скобки здесь необходимы; объяснение немного сложно.)
Наконец, мы можем посмотреть эти координаты и для каждой из них записать ссылку на график обычным способом:
>>> for r, c in np.transpose(np.where((a != 0) & (above != 0))):
... print('there is a link from ({r}, {c}) to ({r - 1}, {c})')