将 masked astropy Table 中的元素转换为 np.nan

Convert elements in masked astropy Table to np.nan

考虑读取包含一些无效条目的数据文件的简单过程。这是我的 test.dat 文件:

16        1035.22  1041.09    24.54     0.30     1.39     0.30     1.80     0.30     2.26     0.30     1.14     0.30     0.28     0.30   0.2884
127        824.57  1105.52    25.02     0.29     0.87     0.29     1.30     0.29     2.12     0.29     0.66     0.29     0.10     0.29   0.2986
182       1015.83   904.93    INDEF     0.28     1.80     0.28     1.64     0.28     2.38     0.28     1.04     0.28     0.06     0.28   0.3271
185       1019.15  1155.09    24.31     0.28     1.40     0.28     1.78     0.28     2.10     0.28     0.87     0.28     0.35     0.28   0.3290
192       1024.80  1045.57    24.27     0.27     1.24     0.27     2.01     0.27     2.40     0.27     0.90     0.27     0.09     0.27   0.3328
197       1035.99   876.04    24.10     0.27     1.23     0.27     1.52     0.27     2.59     0.27     0.45     0.27     0.25     0.27   0.3357
198       1110.80  1087.97    24.53     0.27     1.49     0.27     1.71     0.27     2.33     0.27     0.22     0.27     0.00     0.27   0.3362
1103      1168.39  1065.97    24.35     0.27     1.28     0.27     1.29     0.27     2.68     0.27     0.43     0.27     0.26     0.27   0.3388

这是读取它的代码,并将 "bad" 值 (INDEF) 替换为浮点数 (99.999)

import numpy as np
from astropy.io import ascii

data = ascii.read("test.dat", fill_values=[('INDEF', '0')])
data = data.filled(99.999)

这很好用,但是如果我尝试用 np.nan 替换错误的值(即,我使用行 data = data.filled(np.nan)),我会得到:

ValueError: cannot convert float NaN to integer

为什么会这样,我该如何解决?

这在 numpy.ma.filled 中发生在 numpy 的深处。基本上,填充值必须是标量。

一个杂乱的解决方案,其中充满了 nan,但仍然 returns 一个 table 可能看起来像:

import numpy as np
from astropy.io import ascii
from astropy.table import Table

def fill_with_nan(t):
    arr = t.as_array()
    arr_list = arr.tolist()
    arr = np.array(arr_list)
    arr[np.equal(arr, None)] = np.nan
    arr = np.array(arr.tolist())
    return Table(arr)


data = ascii.read("test.dat", fill_values=[('INDEF', '0')])
data = fill_with_nan(data)

去掉中间商? fill_values=[('INDEF', np.nan)]) 似乎有效。

我不认为这主要是一个 numpy 问题,因为它适用于各个列:

>>> data['col4'].filled(np.nan)
<Column name='col4' dtype='float64' length=8>
24.54
25.02
  nan
24.31
24.27
24.1
24.53
24.35

但是你仍然不能从这个构造一个 Table -

Table([data[n].filled(np.nan) for n in data.colnames])

np.ma.core 中引发了同样的错误。 您可以显式设置

data['col4'] = data['col4'].filled(np.nan)

但这显然让 table 失去了它的 .filled() 方法...... 我不太熟悉掩码数组和 tables,但由于您已经在 Github 上提交了 related issue,您可能想添加这个问题。

如前所述,问题是 numpy MaskedArray.filled() 方法似乎在检查是否确实有任何东西要填充之前尝试将填充值转换为适当的类型。由于示例中的 table 有一个 int 列,这在 numpy 中失败(并且 astropy.Table 只是在每一列上调用 filled() 方法)。

这应该有效:

In [44]: def fill_cols(tbl, fill=np.nan, kind='f'):
    ...:     """
    ...:     In-place fill of ``tbl`` columns which have dtype ``kind``
    ...:     with ``fill`` value.
    ...:     """
    ...:     for col in tbl.itercols():
    ...:         if col.dtype.kind == kind:
    ...:             col[...] = col.filled(fill)
    ...: 

In [45]: t = simple_table(masked=True)

In [46]: t
Out[46]: 
<Table masked=True length=3>
  a      b     c  
int64 float64 str1
----- ------- ----
   --     1.0    c
    2     2.0   --
    3      --    e

In [47]: fill_cols(t)

In [48]: t
Out[48]: 
<Table masked=True length=3>
  a      b     c  
int64 float64 str1
----- ------- ----
   --     1.0    c
    2     2.0   --
    3     nan    e