Автоматическая длина строки в повторном массиве

Если я создаю повторный массив таким образом:

In [29]: np.rec.fromrecords([(1,'hello'),(2,'world')],names=['a','b'])

Результат выглядит отлично:

Out[29]: 
rec.array([(1, 'hello'), (2, 'world')], 
      dtype=[('a', '<i8'), ('b', '|S5')])

Но если я хочу указать типы данных:

In [32]: np.rec.fromrecords([(1,'hello'),(2,'world')],dtype=[('a',np.int8),('b',np.str)])

Строка имеет длину ноль:

Out[32]: 
rec.array([(1, ''), (2, '')], 
      dtype=[('a', '|i1'), ('b', '|S0')])

Мне нужно указать типы данных для всех числовых типов, так как я забочусь о int8/16/32 и т. Д., Но я бы хотел воспользоваться автоматическим определением длины строки, которое работает, если я не указываю типы данных. Я попытался заменить np.str на None, но не повезло. Я знаю, что могу указать, например, "|S5", но заранее не знаю, какую длину строки следует задать.

2 ответа

Если вам не нужно манипулировать строками как байтами, вы можете использовать объектный тип данных для их представления. Это по существу хранит указатель вместо фактических байтов:

In [38]: np.array(data, dtype=[('a', np.uint8), ('b', np.object)])
Out[38]: 
array([(1, 'hello'), (2, 'world')], 
      dtype=[('a', '|u1'), ('b', '|O8')])

В качестве альтернативы идея Алекса будет хорошо работать:

new_dt = []

# For each field of a given type and alignment, determine
# whether the field is an integer.  If so, represent it as a byte.

for f, (T, align) in dt.fields.iteritems():
    if np.issubdtype(T, int):
        new_dt.append((f, np.uint8))
    else:
        new_dt.append((f, T))

new_dt = np.dtype(new_dt)
np.array(data, dtype=new_dt)

который должен дать

array([(1, 'hello'), (2, 'world')], 
      dtype=[('f0', '|u1'), ('f1', '|S5')])

Я не знаю, как попросить numpy определить для вас некоторые аспекты dtype, но не другие, но вы не могли бы, например:

data = [(1,'hello'),(2,'world')]
dlen = max(len(s) for i, s in data)
st = '|S%d' % dlen
np.rec.fromrecords(data, dtype=[('a',np.int8), ('b',st)])
Другие вопросы по тегам