NumPy или Pandas: сохранение типа массива как целого с указанием значения NaN
Есть ли предпочтительный способ сохранить тип данных массива numpy
фиксированным как int
(или int64
или что-то еще), но все еще содержащий элемент внутри, указанный как numpy.NaN
?
В частности, я преобразовываю внутреннюю структуру данных в Pandas DataFrame. В нашей структуре у нас есть столбцы целочисленного типа, у которых все еще есть NaN (но dtype столбца - int). Кажется, он переделает все как float, если мы сделаем это DataFrame, но нам бы очень хотелось быть int
.
Мысли?
Проверенные вещи:
Я попытался использовать функцию from_records()
в pandas.DataFrame, с coerce_float=False
, и это не помогло. Я также пробовал использовать маскированные массивы NumPy с NaN fill_value, которые также не работали. Все это привело к тому, что тип данных столбца стал плавающим.
Ответы
Ответ 1
Эта возможность была добавлена в pandas (начиная с версии 0.24): https://pandas.pydata.org/pandas-docs/version/0.24/whatsnew/v0.24.0.html#optional-integer-na-support
На этом этапе требуется использование расширения dtype Int64 (с большой буквы), а не по умолчанию dtype int64 (строчные буквы).
Ответ 2
NaN
не может быть сохранен в целочисленном массиве. Это известное ограничение панд на данный момент; Я ждал прогресса в достижении значений NA в NumPy (аналогично NA в R), но пройдет не менее 6 месяцев в году, пока NumPy получит эти функции, кажется:
http://pandas.pydata.org/pandas-docs/stable/gotchas.html#support-for-integer-na
(Эта функция была добавлена начиная с версии 0.24 для панд, но учтите, что для нее требуется расширение dtype Int64 (с заглавной буквы), а не по умолчанию dtype int64 (строчные буквы): https://pandas.pydata.org/pandas- docs/version/0.24/whatsnew/v0.24.0.html # option-integer-na-support)
Ответ 3
Если производительность не является основной проблемой, вы можете сохранить строки вместо этого.
df.col = df.col.dropna().apply(lambda x: str(int(x)) )
Затем вы можете смешать с NaN
столько, сколько хотите. Если вы действительно хотите иметь целые числа, в зависимости от вашего приложения вы можете использовать -1
или 0
, или 1234567890
, или другое выделенное значение для представления NaN
.
Вы также можете временно дублировать столбцы: один, как у вас, с поплавками; другой - экспериментальный, с ints или строками. Затем вставляет asserts
в каждое разумное место, проверяя, что эти два синхронизированы. После достаточного тестирования вы можете отпустить поплавки.
Ответ 4
Это не решение для всех случаев, но мои (геномные координаты) я прибегал к использованию 0 в качестве NaN
a3['MapInfo'] = a3['MapInfo'].fillna(0).astype(int)
Это, по крайней мере, позволяет использовать собственный тип столбца "native", такие операции, как вычитание, сравнение и т.д. Работают так, как ожидалось
Ответ 5
Панды v0. 24+
Функциональность для поддержки NaN
в целочисленных рядах будет доступна в версии v0.24 и выше. Информация об этом содержится в разделе "Что нового" в v0.24, а также в разделе " Тип данных Nullable Integer".
Панды v0.23 и ранее
В общем случае, лучше всего работать с сериями с float
где это возможно, даже если ряд переходит с int
на float
из-за включения значений NaN
. Это позволяет векторизовать вычисления на основе NumPy, где в противном случае будут обрабатываться циклы уровня Python.
Документы предлагают: "Одна из возможностей - использовать вместо этого массивы dtype=object
". Например:
s = pd.Series([1, 2, 3, np.nan])
print(s.astype(object))
0 1
1 2
2 3
3 NaN
dtype: object
По косметическим причинам, например, вывод в файл, это может быть предпочтительным.
Панды v0.23 и более ранние: фон
NaN
считается float
. Документы в настоящее время (по состоянию на v0.23) указывают причину, по которой целочисленные ряды выгружаются для float
:
В отсутствие поддержки высокой производительности NA, встроенной в NumPy с нуля, основной жертвой является возможность представлять NA в целочисленных массивах.
Этот компромисс сделан в основном из-за памяти и производительности, а также из-за того, что полученный ряд продолжает оставаться "числовым".
Документы также предоставляют правила для апкастинга из-за включения NaN
:
Typeclass Promotion dtype for storing NAs
floating no change
object no change
integer cast to float64
boolean cast to object
Ответ 6
Теперь это возможно, поскольку pandas v 0.24.0
Замечания к выпуску pandas 0.24.x Цитата: "У Pandas появилась возможность хранить целочисленные dtypes с пропущенными значениями.
Ответ 7
Просто хочу добавить, что в случае, если вы пытаетесь преобразовать вектор с плавающей точкой (1.143) в целое число (1), в котором преобразование NA в новый тип Int64 Int64, даст вам ошибку. Чтобы решить эту проблему, вы должны округлить числа, а затем выполнить ".astype('Int64')"
s1 = pd.Series([1.434, 2.343, np.nan])
#without round() the next line returns an error
s1.astype('Int64')
#cannot safely cast non-equivalent float64 to int64
##with round() it works
s1.round().astype('Int64')
0 1
1 2
2 NaN
dtype: Int64
Мой вариант использования состоит в том, что у меня есть серия чисел с плавающей точкой, которую я хочу округлить до int, но когда вы делаете .round(), в конце числа остается "*.0", так что вы можете сбросить этот 0 с конца на преобразование в int.
Ответ 8
Округление с плавающей точкой до целых значений:
Представьте себе серию V панд со смесью положительных поплавков и NaN. Чтобы удалить весь десятичный мусор:
V.fillna(-1).astype(int).replace(-1, np.nan)