当numpy recarray中存在一个数组列时,如何更改其dtype?

5
之前的帖子中,我看到更改 recarray dtype 可以使用 astype 进行。但是,我无法在一个列中具有数组的 recarray 上执行此操作。
我的 recarray 来自FITS文件记录:
> f = fits.open('myfile.fits')   
> tbdata = f[1].data
> tbdata
# FITS_rec([ (0.27591679999999996, array([570, 576, 566, ..., 571, 571, 569], dtype=int16)),
#   (0.55175680000000005, array([575, 563, 565, ..., 572, 577, 582], dtype=int16)),
#   ...,
#   (2999.2083967999997, array([574, 570, 575, ..., 560, 551, 555], dtype=int16)),
#   (2999.4842367999995, array([575, 583, 578, ..., 559, 565, 568], dtype=int16)], 
#   dtype=[('TIME', '>f8'), ('AC', '>i4', (2,))])

我需要将AC列从int转换为float,因此我尝试了以下代码:

> tbdata = tbdata.astype([('TIME', '>f8'), ('AC', '>f4', (2,))])

虽然看起来 dtype 已经改变,但是...

> tbdata.dtype
# dtype([('TIME', '>f8'), ('AC', '>f4', (2,))])

查看AC中的数据,发现它们仍然是整数值。例如,对于一个sum计算,达到了int16变量的极限(所有AC列的值都是正数):

> tbdata['AC'][0:55].sum()
# _VLF(array([31112, 31128, 31164, ..., 31203, 31232, 31262], dtype=int16), dtype=object)
> tbdata['AC'][0:65].sum()
# _VLF(array([-28766, -28759, -28702, ..., -28659, -28638, -28583], dtype=int16), dtype=object)

有没有有效的方法可以更改数组数据类型?


不是回答,只是好奇:根据dtype,'AC'字段是一个形状为(2,)的数组。为什么注释输出显示此字段具有更多元素?例如array([570, 576, 566, ..., 571, 571, 569], dtype=int16) - Warren Weckesser
我无法重现这个问题,但我没有使用你的FITS库。提供一个自包含的示例,以便我们可以复制并运行将会很有帮助。不要使用FITS数据;只需手动创建一个简单的dtype和数组,以演示问题即可。 - Warren Weckesser
@WarrenWeckesser:对于第一个问题,我不确定,但我猜测这与“AC”字段是FITS可变长度数组有关... - mtc
2个回答

0

我可以使用来自fits文件的recarray重现此问题。 一种解决方法是将recarray作为fits表加载,然后将其转换为pandas数据框:

from astropy.table import Table
import pandas as pd

t = Table.read('file.fits')
df = pd.DataFrame.from_records(t, columns=t.columns) 
df.AC = df.AC.astype(float)

0
根据Warren的建议,如果我尝试使用手动创建的recarray,似乎一切都很顺利:
> ra = np.array([ ([30000,10000], 1), ([30000,20000],2),([30000,30000],3) ], dtype=[('x', 'int16',2), ('y', int)])
> ra
# array([([30000, 10000], 1), ([30000, 20000], 2), ([30000, 30000], 3)],
#       dtype=[('x', '<i2', (2,)), ('y', '<i8')])
> ra = ra.astype([('x', '<f4', (2,)), ('y', '<i8')])
> ra
# array([([30000.0, 10000.0], 1), ([30000.0, 20000.0], 2),
#        ([30000.0, 30000.0], 3)], dtype=[('x', '<f4', (2,)), ('y', '<i8')])

因此,int16数字会被转换为浮点数。

然而,在对我的tbdatarecarray进行astype调用之后,数字似乎根本没有改变(内部的dtype也没有):

> tbdata.dtype
# dtype([('TIME', '>f8'), ('AC', '>f4', (2,))])
> tbdata
# FITS_rec([ (0.27591679999999996, array([570, 576, 566, ..., 571, 571, 569], dtype=int16)),
#    (0.55175680000000005, array([575, 563, 565, ..., 572, 577, 582], dtype=int16)),
#   ...,
#   (2999.2083967999997, array([574, 570, 575, ..., 560, 551, 555], dtype=int16)),
#   (2999.4842367999995, array([575, 583, 578, ..., 559, 565, 568], dtype=int16))], 
#    dtype=[('TIME', '>f8'), ('ADC', '<f4', (2,))])

我的结论是,这可能与AstroPy接口到FITS文件有关的问题。此外,在sum()之后检索到的负数实际上与数据类型无关,而是存在于tbdata中的整数数组的中间,这是由于FITS存储大于32768的数字的方式,使用TZERO关键字作为无符号整数的偏移量。问题在于CFITSIO和普通的FITS查看器会以透明的方式重新转换这些数字,因此我不知道这些负数的存在。 非常感谢您的帮助和建议。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接