当其中一列是数组时,如何更改 numpy recarray 的数据类型?
How to change the dtype of a numpy recarray when one of the columns is an array?
在 previous posts 中,我看到可以使用 astype
来更改 recarray
的 dtype
。但是我无法使用其中一列中有数组的 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)
有什么方法可以有效改变数组的数据类型吗?
听从 Warren 的建议,如果我尝试使用 recarray
创建的 "by hand",事情似乎进展顺利:
> 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 数字 被 转换为浮点数。
然而,在 astype
调用我的 tbdata recarray
之后,数字似乎根本没有改变(内部 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,))])
我的结论是,这可能是与 FITS 文件的 AstroPy 接口相关的问题。此外,我在sum()
之后检索到的负数实际上与数据类型无关,但它们存在于tbdata中整数数组的中间,由于FITS 存储大于 32768 的数字的方式,使用 TZERO 关键字作为无符号整数的偏移量。问题是 CFITSIO 和普通 FITS 查看器以对用户透明的方式重新转换这些数字,因此我不知道这些负数。
非常感谢您的帮助和建议。
我可以使用适合文件中的 recarray
重现此问题。
解决方法是将 recarray
加载为适合 table,然后将其转换为 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)
在 previous posts 中,我看到可以使用 astype
来更改 recarray
的 dtype
。但是我无法使用其中一列中有数组的 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)
有什么方法可以有效改变数组的数据类型吗?
听从 Warren 的建议,如果我尝试使用 recarray
创建的 "by hand",事情似乎进展顺利:
> 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 数字 被 转换为浮点数。
然而,在 astype
调用我的 tbdata recarray
之后,数字似乎根本没有改变(内部 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,))])
我的结论是,这可能是与 FITS 文件的 AstroPy 接口相关的问题。此外,我在sum()
之后检索到的负数实际上与数据类型无关,但它们存在于tbdata中整数数组的中间,由于FITS 存储大于 32768 的数字的方式,使用 TZERO 关键字作为无符号整数的偏移量。问题是 CFITSIO 和普通 FITS 查看器以对用户透明的方式重新转换这些数字,因此我不知道这些负数。
非常感谢您的帮助和建议。
我可以使用适合文件中的 recarray
重现此问题。
解决方法是将 recarray
加载为适合 table,然后将其转换为 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)