2015-12-21 3 views
0

Я работаю над утилитой python для получения данных из каталога звезд Tycho. Одна из функций, которые я работаю над запросами каталога и возвращает всю информацию для данного идентификатора звезды (или набора звездных идентификаторов).создать многоуровневый структурированный массив из списка строк

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

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

Например, говорят, что запись, которую я хочу, чтобы это:

record = '0002 00038 1| | 3.64121230| 1.08701186| 14.1| -23.0| 69| 82| 1.8| 1.9|1968.56|1957.30| 3|1.0|3.0|0.9|3.0|12.444|0.213|11.907|0.189|999| |   | 3.64117944| 1.08706861|1.83|1.73| 81.0|104.7| | 0.0' 

Теперь я пытаюсь разобрать это в Numpy структурированный массив с DTYPE:

 dform = [('starid', [('TYC1', int), ('TYC2', int), ('TYC3', int)]), 
      ('pflag', str), 
      ('starBearing', [('rightAscension', float), ('declination', float)]), 
      ('properMotion', [('rightAscension', float), ('declination', float)]), 
      ('uncertainty', [('rightAscension', int), ('declination', int), ('pmRA', float), ('pmDc', float)]), 
      ('meanEpoch', [('rightAscension', float), ('declination', float)]), 
      ('numPos', int), 
      ('fitGoodness', [('rightAscension', float), ('declination', float), ('pmRA', float), ('pmDc', float)]), 
      ('magnitude', [('BT', [('mag', float), ('err', float)]), ('VT', [('mag', float), ('err', float)])]), 
      ('starProximity', int), 
      ('tycho1flag', str), 
      ('hipparcosNumber', str), 
      ('observedPos', [('rightAscension', float), ('declination', float)]), 
      ('observedEpoch', [('rightAscension', float), ('declination', float)]), 
      ('observedError', [('rightAscension', float), ('declination', float)]), 
      ('solutionType', str), 
      ('correlation', float)] 

Это кажется, что должна быть довольно простая вещь, чтобы сделать, но все, что я стараюсь брейки ...

Я пробовал:

np.genfromtxt(BytesIO(record.encode()),dtype=dform,delimiter=(' ','|')) 
np.genfromtxt(BytesIO(record.encode()),dtype=dform,delimiter=(' ','|'),missing_values=' ',filling_values=None) 

оба из которых дает мне

{TypeError}cannot perform accumulate with flexible type 

, который не имеет никакого смысла, так как не следует делать какие-либо накопления.

Я также попытался

np.array(re.split('\|| ',record),dtype=dform) 

, который жалуется на

{TypeError}a bytes-like object is required, not 'str' 

и другой вариант

np.array([x.encode() for x in re.split('\|| ',record)],dtype=dform) 

который не выбрасывает ошибку, но и, конечно, не возвращает правильные результаты:

[ ((842018864, 0, 0), '', (0.0, 0.0), (0.0, 0.0), (0, 0, 0.0, 0.0), (0.0, 0.0), 0, (0.0, 0.0, 0.0, 0.0), ((0.0, 0.0), (0.0, 0.0)), 0, '', '', (0.0, 0.0), (0.0, 0.0), (0.0, 0.0), '', 0.0)... 

Так как я могу это сделать? Я думаю, что вариант genfromtxt - это путь (особенно потому, что иногда могут отсутствовать данные), но я не понимаю, почему он не работает. Это что-то, что мне просто нужно будет написать парсер самостоятельно?

+0

Хмм ... ваша 'запись' имеет 32 поля, но' dform', похоже, имеет '17'. Как так? Я мог представить, что это работает иначе: np.genfromtxt (BytesIO (record.encode()), dtype = dform, delimiter = '|') ', но в любом случае теперь кажется двусмысленным. –

+0

, так как для меня не достаточно, чтобы воссоздать проблему, попробуйте переключить свою 'str' на' np.str_' – TriHard8

ответ

3

Извините, этот ответ длинный и бессвязный, но это то, что нужно, чтобы выяснить, что происходит. Сложность dtype в частности была скрыта по его длине.


Я получаю ошибку TypeError: cannot perform accumulate with flexible type когда я пытаюсь список для delimiter. Подробности показывают, что ошибка возникает в LineSplitter. Не вдаваясь в подробности, разделитель должен быть одним символом (или по умолчанию «пробелом»).

Из genfromtxt документов:

разделителя: ул, Int, или последовательность, необязательно Строки, используемую для разделения значений. По умолчанию любые разделительные пробелы действуют как разделитель. Целое число или последовательность целых чисел также могут быть представлены как ширина (ширины) каждого поля.

genfromtxt сплиттер является немного более мощным, чем строка .split что loadtxt использует, но не так вообще как re сплиттер.

Что касается {TypeError}a bytes-like object is required, not 'str', вы указываете для нескольких полей, dtype 'str'. Это байтовая строка, где ваш record является строкой unicode (в Py3). Но вы уже поняли, что с BytesIO(record.encode()).

Я хотел бы проверить genfromtxt случаи с:

record = b'....' 
np.genfromtxt([record], ....) 

Или еще лучше

records = b"""one line 
tow line 
three line 
""" 
np.genfromtxt(records.splitlines(), ....) 

Если я позволяю genfromtxt типы выводят поля, и использовать только один разделитель, я получаю 32 полей:

In [19]: A=np.genfromtxt([record],dtype=None,delimiter='|') 
In [20]: len(A.dtype) 
Out[20]: 32 
In [21]: A 
Out[21]: 
array((b'0002 00038 1', False, 3.6412123, 1.08701186, 14.1, -23.0, 69, 82, 1.8, 1.9, 1968.56, 1957.3, 3, 1.0, 3.0, 0.9, 3.0, 12.444, 0.213, 11.907, 0.189, 999, False, False, 3.64117944, 1.08706861, 1.83, 1.73, 81.0, 104.7, False, 0.0), 
     dtype=[('f0', 'S12'), ('f1', '?'), ('f2', '<f8'), ('f3', '<f8'), ('f4', '<f8'), ... ('f26', '<f8'), ('f27', '<f8'), ('f28', '<f8'), ('f29', '<f8'), ('f30', '?'), ('f31', '<f8')]) 

Когда мы получим проблемы с байтом и разделителем d out

np.array([x for x in re.split(b'\|| ',record)],dtype=dform) 

бежит. Теперь я вижу, что ваша дробь сложна, с вложенными составными полями.

Но для определения структурированного массива вы должны дать ему список записей, например.

np.array([(record1...), (record2...), ....], dtype([(field1),(field2),...])) 

Здесь вы пытаетесь создать одну запись. Я мог бы обернуть ваш список в кортеж, но затем я получаю несоответствие между этой длиной и длиной dform, 66 v 17. Если вы считаете, что все подполя dform может принимать 66 значений, но мы не можем просто сделать это с одним кортежем.

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

In [41]: np.zeros((1,),dform) 
Out[41]: 
array([ ((0, 0, 0), '', (0.0, 0.0), (0.0, 0.0), (0, 0, 0.0, 0.0), (0.0, 0.0), 0, (0.0, 0.0, 0.0, 0.0), ((0.0, 0.0), (0.0, 0.0)), 0, '', '', (0.0, 0.0), (0.0, 0.0), (0.0, 0.0), '', 0.0)], 
     dtype=[('starid', [('TYC1', '<i4'), ('TYC2', '<i4'), ('TYC3', '<i4')]), ('pflag', '<U'), ('starBearing', [('rightAscension', '<f8'), ('declination', '<f8')]), ('properMotion', [('rightAscension', '<f8'), ('declination', '<f8')]), ('uncertainty', [('rightAscension', '<i4'), ('declination', '<i4'), ('pmRA', '<f8'), ('pmDc', '<f8')]), ('meanEpoch', ....('solutionType', '<U'), ('correlation', '<f8')]) 

In [64]: for name in A.dtype.names: 
    print(A[name].dtype) 
    ....:  
[('TYC1', '<i4'), ('TYC2', '<i4'), ('TYC3', '<i4')] 
<U1 
[('rightAscension', '<f8'), ('declination', '<f8')] 
[('rightAscension', '<f8'), ('declination', '<f8')] 
[('rightAscension', '<i4'), ('declination', '<i4'), ('pmRA', '<f8'), ('pmDc', '<f8')] 
[('rightAscension', '<f8'), ('declination', '<f8')] 
int32 
[('rightAscension', '<f8'), ('declination', '<f8'), ('pmRA', '<f8'), ('pmDc', '<f8')] 
[('BT', [('mag', '<f8'), ('err', '<f8')]), ('VT', [('mag', '<f8'), ('err', '<f8')])] 
int32 
<U1 
<U1 
[('rightAscension', '<f8'), ('declination', '<f8')] 
[('rightAscension', '<f8'), ('declination', '<f8')] 
[('rightAscension', '<f8'), ('declination', '<f8')] 
<U1 
float64 

Я считаю 34 примитивных полей типа dtype. Большинство из них являются «скалярными», некоторые 2-4 термины, у одного есть еще один уровень гнездования.

Если я заменяю первые 2 сплит-пространства |, record.split(b'|') дает мне 34 строки.

Давайте попробуем, что в genfromtxt:

In [79]: np.genfromtxt([record],delimiter='|',dtype=dform) 
Out[79]: 
array(((2, 38, 1), '', (3.6412123, 1.08701186), (14.1, -23.0), 
    (69, 82, 1.8, 1.9), (1968.56, 1957.3), 3, (1.0, 3.0, 0.9, 3.0), 
    ((12.444, 0.213), (11.907, 0.189)), 999, '', '', 
    (3.64117944, 1.08706861), (1.83, 1.73), (81.0, 104.7), '', 0.0), 
     dtype=[('starid', [('TYC1', '<i4'), ('TYC2', '<i4'), ('TYC3', '<i4')]), 
('pflag', '<U'), 
('starBearing', [('rightAscension', '<f8'), ('declination', '<f8')]), 
('properMotion', [('rightAscension', '<f8'), ('declination', '<f8')]), 
('uncertainty', [('rightAscension', '<i4'), ('declination', '<i4'), ('pmRA', '<f8'), ('pmDc', '<f8')]), 
('meanEpoch', [('rightAscension', '<f8'), ('declination', '<f8')]), 
('numPos', '<i4'), 
('fitGoodness', [('rightAscension', '<f8'), ('declination', '<f8'), ('pmRA', '<f8'), ('pmDc', '<f8')]), 
('magnitude', [('BT', [('mag', '<f8'), ('err', '<f8')]), ('VT', [('mag', '<f8'), ('err', '<f8')])]), 
('starProximity', '<i4'), ('tycho1flag', '<U'), ('hipparcosNumber', '<U'), 
('observedPos', [('rightAscension', '<f8'), ('declination', '<f8')]), 
('observedEpoch', [('rightAscension', '<f8'), ('declination', '<f8')]), 
('observedError', [('rightAscension', '<f8'), ('declination', '<f8')]), ('solutionType', '<U'), ('correlation', '<f8')]) 

Это почти выглядит разумным. genfromtxt может фактически разбить значения среди составных полей. Это более того, что я хотел бы попробовать с np.array().

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

+0

Спасибо, что написали это время. Это было действительно полезно. Проблема заключалась (как вы заявили), что genfromtxt может обрабатывать только один разделитель. Сейчас, похоже, в основном работают сейчас, за исключением другого вопроса, который я задам в другом вопросе. – Andrew

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