2016-02-05 2 views
2

Я пытаюсь прочитать данные из файлов с помощью numpy.genfromtxt. Я установить параметр имен в список разделенных запятыми строк, таких, какNumpy.genfromtxt удаляет квадратные скобки в dtype.names

names = ['a', '[b]', 'c'] 

Однако, когда массив возвращается, значение dtype.names возвращает ('a', 'b', 'c')

Параметр deletechars либо не установлен или вынужден быть None. Я проверил, что создание numpy.ndarray с dtype с именованным столбцом с квадратными скобками сохраняет квадратные скобки, поэтому должно быть, что genfromtxt удаляет квадратные скобки. Есть ли способ отключить эту неожиданную функцию?

Обратите внимание, что это также происходит, если для параметра names установлено значение True. Я тестировал это в numpy версии 1.6.1 и 1.9.9

ответ

2

Я жаловался на это поведение для изменения имени поля до numpy issue tracker и списка рассылки. Он также вырос в severalpreviousquestions на SO.

В самом деле, по умолчанию np.genfromtxt будет изменять имена полей, даже если указать их непосредственно, передавая список строк в качестве names= параметра:

import numpy as np 
from io import BytesIO 

s = '[5],name with spaces,(x-1)!\n1,2,3\n4,5,6' 

x = np.genfromtxt(BytesIO(s), delimiter=',', names=True) 
print(repr(x)) 
# array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)], 
#  dtype=[('5', '<f4'), ('name_with_spaces', '<f4'), ('x1\n1', '<f4')]) 

names = s.split(',')[:3] 
x = np.genfromtxt(BytesIO(s), delimiter=',', skip_header=1, names=names) 
print(repr(x)) 
# array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)], 
#  dtype=[('5', '<f4'), ('name_with_spaces', '<f4'), ('x1\n1', '<f4')]) 

Это происходит, несмотря на то, что имена полей, содержащих не алфавитно-цифровой персонажи совершенно законны:

x2 = np.empty(2, dtype=dtype) 
x2[:] = [(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)] 
print(repr(x2)) 
# array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)], 
#  dtype=[('[5]', '<f4'), ('name with spaces', '<f4'), ('(x-1)!\n1', '<f4')]) 

Логика этого поведения ускользает от меня.


Как вы уже видели, проходя None как deletechars= аргумент не достаточно, чтобы не допустить этого, так как этот аргумент инициализируется внутренне набор символов по умолчанию в numpy._iotools.NameValidator.

Однако, вы можете передать пустую последовательность вместо:

x = np.genfromtxt(BytesIO(s), delimiter=',', names=True, deletechars='') 
print(repr(x)) 
# array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)], 
#  dtype=[('[5]', '<f8'), ('name_with_spaces', '<f8'), ('(x-1)!', '<f8')]) 

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

+0

Спасибо, ali_m. Я видел это решение в трекере ошибок [здесь] (https://github.com/numpy/numpy/issues/2509). @unutbu, рассматривал исправление после факта, но пустой параметр намного проще. Будет тест, а затем принять ответ. – krosbonz

+0

Эти символы могут выглядеть в формате dtype с структурированным массивом, но не как имена атрибутов для повторной проверки. Я вижу такое же напряжение в 'argparse' - вы даете пользователю достаточно веревки, чтобы повесить себя? – hpaulj

+0

@hpaulj Nope - они также легальны для повторных вычислений (хотя, конечно, вы не можете использовать синтаксис '.attribute' для доступа к ним). Независимо от того, должны ли они быть * законными, это еще один вопрос, но я считаю, что 'np.genfromtxt' не должен произвольно испортить имена юридических полей. –

2

В String formatting issue (parantheses vs underline) я обнаружил, что dtype=None требуется в дополнение к deletechars параметра:

https://stackoverflow.com/a/32540939/901925

In [168]: np.genfromtxt([b'1,2,3'],names=['a','[b]','xcx'],delimiter=',',deletechars='',dtype=None) 
Out[168]: 
array((1, 2, 3), 
     dtype=[('a', '<i4'), ('[b]', '<i4'), ('xcx', '<i4')]) 

С умолчанию dtype (поплавком) в, deletechars используется, но имена проходят через второй валидатор, easy_dtype, который не получает этот параметр.

In [170]: np.genfromtxt([b'1,2,3'],names=['a','[b]','xcx'],delimiter=',',deletechars='x') 
Out[170]: 
array((1.0, 2.0, 3.0), 
     dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')]) 

https://github.com/numpy/numpy/pull/4649


имена полей могут быть изменены после загрузки:

In [205]: data=np.genfromtxt([b'1 2 3 txt'],names=['a','b','c','d'],dtype=[int,float,int,'S4']) 

In [206]: data.dtype.names 
Out[206]: ('a', 'b', 'c', 'd') 

In [207]: data.dtype.names=['a','[b]','*c*','d'] 

In [208]: data 
Out[208]: 
array((1, 2.0, 3, 'txt'), 
     dtype=[('a', '<i4'), ('[b]', '<f8'), ('*c*', '<i4'), ('d', 'S4')]) 

Это работает для имен, взятых из самого файла:

In [212]: data=np.genfromtxt([b'a [b] *c* d','1 2 3 txt'],dtype=[int,float,int,'S4'],names=True) 
+0

действительно, без 'dtype = None', ответ @ali_m не работает. к сожалению, я не могу указать 'dtype = None', потому что я не хочу, чтобы все данные были прочитаны как строки и не были автоматически добавлены к чему-то другому genfromtxt. Я вместо этого оставил, чтобы написать свою собственную программу чтения файлов. – krosbonz

+1

Почему бы не использовать простые имена полей во время загрузки и впоследствии заменить их на смешные символы? См. Мое редактирование. – hpaulj

+0

Несмотря на то, что после изменения факта можно изменить «dtype.names» массива, для этого все еще требуется модификация кода, поскольку я не знаю _a priori_, какая строка во входных файлах содержит информацию заголовка. Существует несколько различных форматов входных файлов, и в некоторых случаях я использую встроенные функции 'genfromtxt', чтобы определить, какая строка содержит имена столбцов. Поскольку теперь мне нужно написать код, который читает в файлах, чтобы определить параметр «names», я мог бы просто написать код для чтения в самих данных. – krosbonz

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