Как мне справиться со странным поведением индексации со ссылками на координаты массива numpy? - PullRequest
1 голос
/ 08 апреля 2019

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

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.]]

Как мне справиться с этим, чтобы я всегда получал первый вывод, даже если есть только один элемент, и это массив numpy?

Спасибо!

EDIT:

То, что в настоящее время происходит в моем коде, это программа возвращает массив значений:

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 [ordin] = 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.]],

1 Ответ

2 голосов
/ 09 апреля 2019

Индексированное назначение может скрыть некоторые детали, которые, я думаю, более понятны с эквивалентом 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,:].


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

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 стиль - как кортеж массивов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...