【问题标题】:How to change the dtype of a numpy recarray when one of the columns is an array?当其中一列是数组时,如何更改 numpy recarray 的 dtype?
【发布时间】:2016-03-24 02:46:31
【问题描述】:

previous posts 中,我看到可以使用astype 更改recarraydtype。但是,我无法使用 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)
  • 我无法重现此内容,但我没有使用您的 FITS 库。一个我们可以复制和运行的独立示例会很有帮助。不要使用 FITS 数据;只需“手动”创建一个简单的 dtype 和数组即可用于演示问题。
  • @WarrenWeckesser :对于第一个问题,我不确定,但我想这与“AC”字段是 FITS 可变长度数组这一事实有关......

标签: python arrays numpy fits


【解决方案1】:

我可以使用 fit 文件中的 recarray 重现此问题。 一种解决方法是将 recarray 加载为适合表,然后将其转换为 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)

【讨论】:

    【解决方案2】:

    按照 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 数字转换为浮点数。

    然而,在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() 之后检索到的负数实际上与数据类型无关,但由于 FITS 的存储方式,它们存在于 tbdata 的整数数组的中间大于 32768 的数字,使用 TZERO 关键字作为无符号整数的偏移量。问题是 CFITSIO 和普通 FITS 查看器以对用户透明的方式重新转换这些数字,因此我不知道这些负数。 非常感谢您的帮助和建议。

    【讨论】:

      猜你喜欢
      • 2012-04-14
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 2021-03-23
      • 1970-01-01
      • 2017-01-16
      • 1970-01-01
      • 2018-04-07
      相关资源
      最近更新 更多