В рамках более крупного проекта я генерирую кучу разных списков координат разного размера и обнаружил странное поведение при попытке использовать эти списки координат в качестве индексов массивов. Эти списки координат генерируются в программе, поэтому я не знаю, насколько длинными они будут. См. пример ниже:
t = np.zeros((5,5))
coord = [[2,3], [1,2]]
t[coord] = 30
print(t)
Выход:
[[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 30. 0. 0. 0.]
[ 0. 0. 30. 0. 0.]
[ 0. 0. 0. 0. 0.]]
Но тогда, если в списке всего одна точка:
t = np.zeros((5,5))
coord = [[2,3]]
t[coord] = 30
print(t)
Выход:
[[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[30. 30. 30. 30. 30.]
[30. 30. 30. 30. 30.]
[ 0. 0. 0. 0. 0.]]
Затем, если я конвертирую список в массив numpy, он еще больше разбивается:
t = np.zeros((5,5))
coord = np.array([[2,3], [1,2]])
t[coord] = 30
print(t)
Выход:
[[ 0. 0. 0. 0. 0.]
[30. 30. 30. 30. 30.]
[30. 30. 30. 30. 30.]
[30. 30. 30. 30. 30.]
[ 0. 0. 0. 0. 0.]]
Как мне справиться с этим, чтобы я всегда получал первый вывод, даже если есть только один элемент, и это пустой массив?
Спасибо!
Обновлено:
Что в настоящее время происходит в моем коде, так это то, что программа возвращает массив точек:
array([[ 9, 5, 0],
[ 4, 2, 2],
[11, 4, 2],
[ 5, 7, 2],
[11, 12, 2],
[12, 9, 0],
[ 5, 4, 7],
[ 3, 2, 1],
...
Затем я хочу использовать это, чтобы изменить эти точки координат в большей матрице 14 * 14 * 9. big_matrix[координата] = 0
EDIT2: на основе комментария @hpaulj
Вот пример полномасштабной проблемы:
coord = np.array([[ 4, 7, 0],
[ 9, 6, 1],
[ 8, 2, 0],
[ 8, 7, 6],
[ 3, 10, 4],
[ 6, 4, 3],
[10, 10, 3],
[ 3, 2, 1]], dtype='int32')
matrix[coord]
возвращает:
array([[[[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]],
Возможный дубликат Индексирование массива numpy со списком кортежей
Я пытался объяснить, что происходит в ваших различных случаях, но мне пришло в голову, что я не уверен, чего вы хотите. Возможно, вам потребуется продемонстрировать желаемый результат, будь то присвоение значений определенным точкам или определенным строкам.
@hpaulj я отредактировал, чтобы ответить на ваш вопрос.
Ваши примеры были 2x2, которые в массиве 2d можно интерпретировать в любом случае. Новый пример с массивом (8,3) для трехмерного случая работает только в одном направлении, как набор из 8 точек.
Вышеприведенный случай является упрощенной версией. В полномасштабном проекте я видел поведение «выбор строки», когда список имел длину 1. Чтобы предотвратить это поведение, попытка запустить tuple(coord)
исправляет случай с одной точкой, но затем выполняет поведение «выбор строки» в случае с несколькими точками. numpy
не интерпретирует это как набор точек.
Индексированное присваивание может скрывать некоторые детали, которые, как мне кажется, более понятны с эквивалентом getitem
.
In [88]: arr = np.arange(25).reshape(5,5)
In [89]: arr
Out[89]:
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, 24]])
In [90]: coord = [[2,3],[1,2]]
In [91]: arr[coord]
FutureWarning: Using a non-tuple sequence for multidimensional indexing
is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the
future this will be interpreted as an array index, `arr[np.array(seq)]`,
which will result either in an error or a different result.
Out[91]: array([11, 17])
Правильная индексация пары точек, применяя [2,3] для 1-й оси, [1,2] для 2-й:
In [92]: coord = ([2,3],[1,2])
In [93]: arr[coord]
Out[93]: array([11, 17])
In [94]: arr[[2,3], [1,2]]
Out[94]: array([11, 17])
Исторически numpy
был немного неаккуратным и интерпретировал список списков как кортеж списков (при определенных обстоятельствах). Более новые версии пытаются устранить это несоответствие.
In [95]: coord = [[2,3]]
In [96]: arr[coord]
FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.
Out[96]:
array([[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
In [97]: coord = ([2,3],) # clearer - pick 2 rows, e.g. arr[[2,3],:]
In [98]: arr[coord]
Out[98]:
array([[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])
In [99]: arr[2,3] # pick one point
Out[99]: 13
In [100]: coord = (2,3)
In [101]: arr[coord]
Out[101]: 13
С массивом нет ни одного из этих запутанных списков для кортежей:
In [102]: coord = np.array([[2,3], [1,2]])
In [103]: arr[coord]
Out[103]:
array([[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]],
[[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]]])
Это выбирает (2,2) блок строк. Ваш arr[coord]=30
скрыл этот шаблон, так как в выборе строк были дубликаты (и назначение буферизуется). (для небуферизованного назначения проверьте np.add.at(t,coord,30)
).
Если мы явно укажем, что coord
применяется к 1-му измерению, мы будем использовать тот же стиль индексации массива:
In [111]: coord = [[2,3],[1,2]]
In [112]: arr[coord,:]
Out[112]:
array([[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]],
[[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]]])
Обратите внимание на разницу в форме, если я использую этот последний [coord,]
со списком из 1 элемента:
In [117]: coord = [[2,3]]
In [118]: arr[coord,]
Out[118]:
array([[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]]])
In [119]: _.shape
Out[119]: (1, 2, 5)
Так что сделайте coord
кортеж, а не список, если вы хотите, чтобы каждый элемент применялся к другому измерению. Или используйте массив, если вы хотите, чтобы он применялся только к одному измерению, или явно используйте нотацию [coord,:]
like.
Если вы возьмете этот массив, транспонируете его и разделите на кортеж, вы получите индексные массивы для двух измерений:
In [120]: coord = np.array([[2,3],[1,2]])
In [121]: coord
Out[121]:
array([[2, 3],
[1, 2]])
In [123]: tuple(coord.T)
Out[123]: (array([2, 1]), array([3, 2]))
In [124]: arr[tuple(coord.T)]
Out[124]: array([13, 7])
и с 4 баллами:
In [125]: coord = np.array([[2,3],[1,2],[0,0],[3,4]])
In [126]: arr[tuple(coord.T)]
Out[126]: array([13, 7, 0, 19])
Не знаю, поможет это или нет, но np.where
часто используется для выбора точек в массиве:
Условие - кратное 4:
In [135]: arr%4==0
Out[135]:
array([[ True, False, False, False, True],
[False, False, False, True, False],
[False, False, True, False, False],
[False, True, False, False, False],
[ True, False, False, False, True]])
Индексы этих точек — кортеж с массивом для каждого измерения. Это можно использовать непосредственно в качестве индекса:
In [136]: np.where(arr%4==0)
Out[136]: (array([0, 0, 1, 2, 3, 4, 4]), array([0, 4, 3, 2, 1, 0, 4]))
In [137]: arr[_]
Out[137]: array([ 0, 4, 8, 12, 16, 20, 24])
argwhere
применяет np.transpose
к этому кортежу, создавая массив (n,2):
In [138]: np.argwhere(arr%4==0)
Out[138]:
array([[0, 0],
[0, 4],
[1, 3],
[2, 2],
[3, 1],
[4, 0],
[4, 4]])
Это координаты отдельных элементов, но их нельзя использовать напрямую в качестве индексов, кроме как итеративно:
In [144]: [arr[i,j] for i,j in np.argwhere(arr%4==0)]
Out[144]: [0, 4, 8, 12, 16, 20, 24]
Я думаю, что вы генерируете координаты в этом стиле argwhere
, но они вам действительно нужны в стиле where
— как кортеж массивов.
Большое спасибо за этот подробный ответ. Основываясь на вашем ответе, я поигрался и немного смущен тем, что происходит, когда я делаю следующее: coord = tuple(np.array([[11, 6], [ 8, 5]]))
. Буферизируется ли выбор строки, потому что кортеж имеет элементы массива numpy?
Что именно вы пытаетесь сделать с этим последним случаем? Присвоить значения строкам 11,6,8 и 5, или точкам (11,6) и (8,5), или точкам (11,8) и (6,5)? Или что-то другое?
Я хочу присвоить значения отдельным точкам в этих координатах "x, y".
Спасибо, эта операция транспонирования решила мой вопрос.
Вы можете рассмотреть возможность использования Обозначение среза Numpy, который должен дать вам то, что вы ищете.