Понимание странного логического поведения индексации 2d-массивов в numpy - PullRequest
17 голосов
/ 19 октября 2011

Почему это работает:

a=np.random.rand(10,20)
x_range=np.arange(10)
y_range=np.arange(20)

a_tmp=a[x_range<5,:]
b=a_tmp[:,np.in1d(y_range,[3,4,8])]

и это не так:

a=np.random.rand(10,20)
x_range=np.arange(10)
y_range=np.arange(20)    

b=a[x_range<5,np.in1d(y_range,[3,4,8])]

Ответы [ 2 ]

19 голосов
/ 19 октября 2011

Страница справочной документации Numpy по индексированию содержит ответы, но требует небольшого внимательного прочтения.

Ответ здесь заключается в том, что индексация с логическими значениями эквивалентна индексации с полученными целочисленными массивамисначала преобразовав логические массивы с np.nonzero.Следовательно, с логическими массивами m1, m2

a[m1, m2] == a[m1.nonzero(), m2.nonzero()]

, которые (когда это удается, т. Е. m1.nonzero().shape == m2.nonzero().shape) эквивалентны:

[a[i, i] for i in range(a.shape[0]) if m1[i] and m2[i]]

Я неконечно, почему он был разработан для такой работы - обычно это , а не , что вы хотели бы.

Чтобы получить более интуитивный результат, вы можете вместо этого сделать

a[np.ix_(m1, m2)]

, который дает результат, эквивалентный

[[a[i,j] for j in range(a.shape[1]) if m2[j]] for i in range(a.shape[0]) if m1[i]]
5 голосов
/ 19 октября 2011

Альтернативой np.ix_ является преобразование логических массивов в целочисленные массивы (с использованием np.nonzero()), а затем использование np.newaxis для создания массивов правильной формы для использования преимуществ вещания.

import numpy as np

a=np.random.rand(10,20)
x_range=np.arange(10)
y_range=np.arange(20)

a_tmp=a[x_range<5,:]
b_correct=a_tmp[:,np.in1d(y_range,[3,4,8])]

m1=(x_range<5).nonzero()[0]
m2=np.in1d(y_range,[3,4,8]).nonzero()
b=a[m1[:,np.newaxis], m2]
assert np.allclose(b,b_correct)

b2=a[np.ix_(x_range<5,np.in1d(y_range,[3,4,8]))]
assert np.allclose(b2,b_correct)

np.ix_ имеет тенденцию быть медленнее, чем двойное индексирование. Подробное решение выглядит немного быстрее:

длинный форма :

In [83]: %timeit a[(x_range<5).nonzero()[0][:,np.newaxis], (np.in1d(y_range,[3,4,8])).nonzero()[0]]
10000 loops, best of 3: 131 us per loop

двойное индексирование :

In [85]: %timeit a[x_range<5,:][:,np.in1d(y_range,[3,4,8])]
10000 loops, best of 3: 144 us per loop

с использованием np.ix_ :

In [84]: %timeit a[np.ix_(x_range<5,np.in1d(y_range,[3,4,8]))]
10000 loops, best of 3: 160 us per loop

Примечание. Было бы неплохо проверить эти временные параметры на вашем компьютере, поскольку рейтинги могут меняться в зависимости от вашей версии Python, numpy или аппаратного обеспечения.

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