2013-10-01 2 views
16

Предположим, у меня естьНайти индекс, где элементы изменяют значение NumPy

>>> v 
array([1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 3, 4, 3, 4, 3, 4, 5, 5, 5]) 

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

>>> index_of_changed_values(v) 
[0, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16] 

Если это не возможно, с некоторыми Numpy рутина, что это быстрый способ сделать это в Python? Мне также было бы полезно обратиться к некоторым хорошим учебникам с numpy, так как я начинаю с нуля.

ответ

28

Вы можете получить эту функциональность в numpy путем сравнения каждого элемента со своим соседом;

v[:-1] != v[1:] 


array([False, False, False, False, True, False, False, True, True, 
    True, True, True, True, True, True, True, False, False], dtype=bool) 

, чтобы получить индексы вы используете «где» функция

np.where(v[:-1] != v[1:])[0] 

array([ 4, 7, 8, 9, 10, 11, 12, 13, 14, 15]) 

Здесь вы можете предварять первый элемент и добавить один, чтобы добраться до той же схеме индексации у вас есть в вашем вопросе.

+0

это работает совершенно спасибо. Отличное объяснение тоже. – liang

+3

@kith Так просто, так идеально, поэтому OMG! –

-1

Возможно, это потому, что Python 3.5, но приведенные выше коды не помогли мне.

Похоже, v[:-1] != v[1:] не возвращает iterable но один bool.

я придумал следующий список понимание с помощью zip и enumerate

[ i for i, (x, y) in enumerate(zip(v[:-1],v[1:])) if x!=y] 

Кто-то ищет решения в py3.5 может оказаться полезным!

+0

выше код использовал numpy – ash

+0

@ash: Я имел в виду, что 'v [: - 1]! = V [1:]' не возвращал * массив * (или, в более общем смысле, массив-подобную структуру *) 'bools', который в свою очередь, не работал с 'numpy.where' в * python 3.5 *. И ответ был нацелен на людей, которые пришли бы к этому вопросу и использовали python 3.5. И да, я знаю, что код выше, используется numpy, и это не так. – cipher

+1

, то есть bc, они должны быть массивами numpy, а не списками python. – ash

-1

Подобного @kith ответа, но требует меньше массирования результата:

np.where(np.roll(v,1)!=v)[0] 

Нет необходимости предварять 0 или добавить 1. Примера:

>>> v=np.array([1, 1, 1, 2, 2, 3, 3, 4, 4, 4]) 
>>> np.where(np.roll(v,1)!=v)[0] 
array([0, 3, 5, 7]) 

EDIT: как уже упоминалось @Praveen , это не выполняется, когда последний и первый элементы равны.

+0

Это не будет работать, если массив выглядит примерно как '[1, 1, 1, 2, 2, 2, 1, 1, 1]'. то есть первое и последнее значения одинаковы, поэтому вы не получите индекс «0», как вы ожидаете ... – Praveen

Смежные вопросы