2D-массив numpy не дает ошибки при индексировании со строками, содержащими цифры

Когда я создаю одномерный массив в numpy и использую строку (содержащую цифры) для ее индексации, я получаю ошибку, как ожидалось:

>>> import numpy as np
>>> a = np.arange(15)
>>> a['10']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: field named 10 not found.

Однако, когда я создаю двухмерный массив и использую две строки для индексирования, он не дает ошибки и возвращает элемент, как если бы строки сначала конвертировались в целые числа.

>>> b = np.arange(15).reshape(3,5)
>>> b
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
>>> b[1, 2]
7
>>> b['1', '2']
7

Что происходит? Почему бы мне не получить ошибку в двухмерном случае?

Ответ 1

отказ от ответственности - этот ответ обязательно будет неполным

Я думаю, что то, что вы видите, является следствием индексации последовательности имен. Поскольку строки являются фактически последовательностями, вы получаете значения строки по одному символу за раз и преобразуете их в объекты "intp" (которые предположительно используют только функцию python int), которая затем дает вам ваш массив индекс.

Это также объясняет случай 1D:

class Foo(object):
    def __getitem__(self,idx):
        print idx

a = Foo()
a[12]
a[12,12]

Обратите внимание, что во втором случае передается a tuple, тогда как в первом случае передается целое число.


Часть этого, что я до сих пор не понимаю, демонстрируется этим тестом:

import numpy as np
a = np.arange(156).reshape(13,12)
print a[12,3] == a['12',3]   #True -- I would have thought False for this one...
print a['12',3] == a[('1','2'),3]  #False -- I would have guessed True for this..
assert( a[tuple('12'),3] == a[(1,2),3] )  #This passes, as expected

Не стесняйтесь пытаться объяснить это мне в комментариях.:) Несоответствие может заключаться в том, что numpy намеренно оставляет строки в одиночку при преобразовании в последовательность объектов intp, чтобы более плавно обрабатывать массивы записей...

Ответ 2

Просто добавьте, обратите внимание, что первый случай (одна строка), вероятно, связан с поддержкой повторений, которые используют строки как имена полей.

Пожалуйста, не полагайтесь на второй случай. Numpy чрезвычайно свободен в отношении индексирования с помощью не-массивов, поскольку, если он не является массивом (а не срезом, а не None), он просто попытается преобразовать его в целочисленный массив, который хорошо определен для этих строк. Однако это не по дизайну, потому что слишком много программного обеспечения полагается на это поведение (по крайней мере частично), чтобы фактически изменить его и, честно говоря, в то время как это несколько имеет смысл для поплавков, которые забываются, для строк.


Некоторые подробности для @mgilson. учитывая, что все это исключает использование ярлыков, оно действительно сводится к деталям реализации. Например, одна строка в настоящее время имеет специальную оболочку для повторных вычислений, даже если она не является повторением, но кортеж строк является только специальным для ретрансляций.

Теперь список строк, несколько особенный, поскольку они не являются кортежами, но действуют как один раз в большую часть времени. Это может быть небольшая ошибка... Поскольку она находит последовательность внутри нее, она запускает фантастическую индексацию, но "забывает" преобразовать ее в массив. Хотя я бы обычно использовал кортежи для обозначения нескольких осей.