Конвертировать элементы в замаскированной таблице астропии в 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

И это код для чтения и замены "плохих" значений (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

почему это и как я могу обойти это?

4 ответа

Решение

Как отмечается, проблема в том, что NumPy MaskedArray.filled() Кажется, что метод пытается преобразовать значение заполнения в соответствующий тип, прежде чем проверять, есть ли на самом деле что-нибудь для заполнения. Поскольку таблица в примере имеет int столбец, это терпит неудачу в пределах NumPy (и Astropy. Таблица просто вызывает 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

Я не думаю, что это, в первую очередь, проблемная проблема, так как она работает с отдельными столбцами:

>>> 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)

но это, очевидно, позволяет столу потерять .filled() метод... Я не очень хорошо знаком с замаскированными массивами и таблицами, но, поскольку вы уже подали связанную проблему на Github, вы можете добавить эту проблему.

Это происходит довольно глубоко в numpy, в numpy.ma.filled. значения заполнения должны быть скалярами, в основном.

Грязное решение, которое заполняет nan и возвращает таблицу, может выглядеть так:

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)]) похоже на работу.

Другие вопросы по тегам