从字符串列表创建一个numpy结构化数组

2024-04-19 03:27:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在开发一个python实用程序来从tycho2star目录中获取数据。我正在处理的一个函数查询目录并返回给定星体id(或一组星体id)的所有信息。在

我目前的做法是循环遍历目录文件的行,然后尝试将该行解析为numpy结构的数组(如果有查询的话)。(请注意,如果有更好的方法,您可以让我知道,即使这不是这个问题的主题——我这样做是因为目录太大,无法一次将其全部加载到内存中)

不管怎样,一旦我确定了我想保留的记录,我就遇到了一个问题。。。我不知道如何将其解析为结构化数组。在

例如,假设我要保留的记录是:

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'

现在,我正试图将其解析为一个具有dtype的numpy结构化数组:

^{pr2}$

这看起来应该是一件很简单的事情,但是我尝试的每件事都会中断。。。在

我试过:

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选项是最好的选择(尤其是偶尔会丢失数据),但我不明白为什么它不起作用。这是不是我要自己编写一个解析器?在


Tags: numpy目录idnp记录数组recordencode
1条回答
网友
1楼 · 发布于 2024-04-19 03:27:16

抱歉,这个答案又长又乱,但这就是为什么要弄清楚到底发生了什么。尤其是数据类型的复杂性被其长度所掩盖。在


当我为delimiter尝试你的列表时,我得到了TypeError: cannot perform accumulate with flexible type错误。详细信息显示错误发生在LineSplitter。不必详细说明,分隔符应该是一个字符(或默认的“空白”)。在

来自genfromtxt文档:

delimiter : str, int, or sequence, optional The string used to separate values. By default, any consecutive whitespaces act as delimiter. An integer or sequence of integers can also be provided as width(s) of each field.

genfromtxt拆分器比loadtxt使用的字符串.split稍微强大一些,但没有{}拆分器一般。在

至于{TypeError}a bytes-like object is required, not 'str',您可以为几个字段指定dtype'str'。这是字节字符串,其中record是unicode字符串(在Py3中)。但是你已经意识到了BytesIO(record.encode())。在

我喜欢测试genfromtxt病例:

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

或者更好

^{pr2}$

如果我让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')])

当我们解决了整个字节和分隔符的问题时

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

确实跑了。我现在看到你的数据表单很复杂,有嵌套的复合字段。在

但是要定义一个结构化数组,需要给它一个记录列表,例如

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

您正在尝试创建一个记录。我可以把你的列表包装成一个元组,但是我得到了这个长度和dform长度,66v17不匹配。如果计算所有的子字段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个原始数据类型字段。大多数是“标量”,一些是2-4个术语,其中一个有更高层次的嵌套。在

如果我用|替换前两个拆分空格,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()来尝试的。在

因此,如果您确定了分隔符和byte/unicode,那么genfromtxt就可以处理这种混乱。在

相关问题 更多 >