np.squeeze для заданий - PullRequest
       2

np.squeeze для заданий

1 голос
/ 20 июня 2019

У меня есть t.shape=(M, N), и теперь я хотел бы присвоить новые значения v части массива, которая проиндексирована с переменными m и n.m - это массив, а n либо int, либо массив.Я делаю m=m.reshape(-1, 1) в случае, если n является массивом.Это хорошо работает для доступа, например

t[m, n]

. Затем я могу использовать

np.squeeze(t[m, n])

, чтобы удалить дополнительное измерение, которое было добавлено ранее (если n равно int).

Однако, если я сделаю

t[m, n] = v

, это не сработает, потому что если n равно int, v.shape=(m.size,), то есть v имеет только одно измерение.Я мог бы проверить, является ли n целым числом, и соответственно изменить логику (либо не добавляя измерение к m, либо добавляя также к v).

Есть ли более элегантное решение для этого (np.squeeze(t[m, n]) = v было бы неплохо, но, очевидно, это не так)?

Редактировать:

Конкретный пример:

def change_data(data, slices, channels, values):
    data[slices.reshape(-1, 1), channels] = values

data = np.random.randint(low=0, high=10, size=(10, 4))
slices = np.arange(4)
channels = [2]
values = np.squeeze(np.random.randint(low=0, high=10, size=(slices.size, len(channels)))) # The values come as a list
try:
    change_data(data, slices, channels, values) # Does not work
    print("Single channel does work")
except:
    print("Single channel does not work")
channels = [1, 2]
values = np.squeeze(np.random.randint(low=0, high=10, size=(slices.size, len(channels))))
try:
    change_data(data, slices, channels, values) # Works
    print("Multi channel does work")
except:
    print("Multi channel does not work")

В этом простом примере это выглядит немного нелепо, поскольку у меня есть дополнительная операция np.squeezeздесь, но в зависимости от того, сколько измерений имеет массив, это может быть немного громоздким, поэтому, если бы я мог просто «сжать» выбор индекса, проблема была бы решена.Надеюсь, теперь стало понятнее ...

1 Ответ

1 голос
/ 20 июня 2019
In [44]: data = np.arange(40).reshape(10,4)                                               

Делая первую индексную (4,1) форму, мы можем индексировать с различными размерами вторых массивов:

In [46]: data[np.arange(4)[:,None],[2]]                                                   
Out[46]: 
array([[ 2],
       [ 6],
       [10],
       [14]])
In [47]: data[np.arange(4)[:,None],[1,2]]                                                 
Out[47]: 
array([[ 1,  2],
       [ 5,  6],
       [ 9, 10],
       [13, 14]])

Первый результат (4,1), второй (4,2).

С squeeze мы получаем (4,), эквивалентный индексации:

In [48]: data[np.arange(4),2]                                                             
Out[48]: array([ 2,  6, 10, 14])

np.ix_ генерирует аналогичные наборы индексов, например, (4,1) и (1,2)

In [49]: np.ix_(np.arange(4),[1,2])                                                       
Out[49]: 
(array([[0],
        [1],
        [2],
        [3]]), array([[1, 2]]))

и (4,1) с (1,1):

In [50]: np.ix_(np.arange(4),[2])                                                         
Out[50]: 
(array([[0],
        [1],
        [2],
        [3]]), array([[2]]))

(m, 1) передает с (1, n), чтобы получить (m, n) результат. (n,) работает так же, как (1, n) - опять же правила вещания.

С изменением вы хотите присвоить значение этому (m, n) блоку. В этом случае работает (4,2), как и (4,1). Но вы хотели бы назначить (4,). Но путем трансляции (4,) можно транслировать на (1,4), а не на (4,1). Можно добавить начальное измерение, но не конечное.

In [51]: data[np.arange(4)[:,None],[2]]=np.ones(4)                                        
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-51-9245de6331ce> in <module>
----> 1 data[np.arange(4)[:,None],[2]]=np.ones(4)

ValueError: shape mismatch: value array of shape (4,) could not be 
    broadcast to indexing result of shape (4,1)
In [52]: data[np.arange(4)[:,None],[2]] = np.ones((4,1))    # (4,1) into (4,1)
# (4,1) also goes into a (4,2)
In [53]: data[np.arange(4),[2]] = np.ones(4)   # (4,) into (4,)
In [55]: data[np.arange(4)[:,None],[1,2]] = np.zeros(2)  # (2,) into (4,2) 

flat может использоваться для присвоения значений 1d способом, но здесь это не работает, потому что data[np.arange(4)[:,None],[1,2]] является копией, если она используется каким-либо образом, кроме как непосредственно в случае __setitem__, data[...] = ... .

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