NumPy или Pandas: сохранение типа массива целочисленным при наличии значения NaN

160

Есть ли предпочтительный способ сохранить тип данных numpyмассива фиксированным как int( int64или что-то еще), в то же время сохраняя элемент внутри как numpy.NaN?

В частности, я конвертирую внутреннюю структуру данных в Pandas DataFrame. В нашей структуре у нас есть столбцы целочисленного типа, которые все еще имеют NaN (но d-тип столбца - int). Похоже, что все переделано как float, если мы сделаем это DataFrame, но нам бы очень хотелось int.

Мысли?

Вещи пытались:

Я попытался использовать from_records()функцию под pandas.DataFrame, с coerce_float=Falseи это не помогло. Я также пытался использовать маскированные массивы NumPy с NaN fill_value, что также не работало. Все это привело к тому, что тип данных столбца стал плавающим.

Ely
источник
Не могли бы вы использовать массив масок?
Мгилсон
Я попробую. Я также попробовал эту from_recordsфункцию в pandas.DataFrame, coerce_float=Falseно не повезло ... она все еще заставляет новые данные иметь тип float64.
Ely
1
Да, не повезло. Даже с замаскированным массивом он все равно конвертируется в float. Похоже, что Панды выглядят так: «Есть ли где-нибудь NaN? ... Тогда все поплавок». Надеюсь, есть способ обойти это.
Ely
1
Дополнительная поддержка Nullable Integer теперь официально добавлена ​​на pandas 0.24.0 - наконец-то :) - пожалуйста, найдите обновленный ответ ниже. Замечания к выпуску pandas 0.24.x
19

Ответы:

70

Эта возможность была добавлена ​​в 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 (строчные буквы).

techvslife
источник
1
На данный момент вы должны указать специальный dtype, 'Int64'чтобы он работал. Будет еще лучше, когда он будет включен по умолчанию.
Жан Поль
Это круто! Однако существует небольшая проблема, заключающаяся в том, что PyCharm не отображает фрейм данных в окне отладки, если используется таким образом. Вы можете увидеть мой ответ на другой вопрос о том, как принудительно отобразить его: stackoverflow.com/questions/38956660/… (исходная проблема там иная, но решение для отображения информационного кадра работает)
Alaa M.
Должен ли я использовать 'Int64'или есть что-то подобное 'Int8'? Он использует безумное количество памяти по сравнению с np.float.
Superdooperhero
'Int8'кажется, работает, но np.floatвсе еще, кажется, загружается намного быстрее. Кажется, проблема в том, что между ними не высвобождается память. Предположим, что сборщик мусора в конечном итоге запустится.
Superdooperhero
103

NaNне может быть сохранен в целочисленном массиве. Это известное ограничение панд на данный момент; Я ждал прогресса в достижении значений NA в NumPy (аналогично NA в R), но пройдет не менее 6 месяцев в году, пока NumPy получит эти функции, кажется:

http://pandas.pydata.org/pandas-docs/stable/gotchas.html#support-for-integer-na

(Эта функция была добавлена ​​начиная с версии 0.24 для панд, но учтите, что для нее требуется расширение dtype Int64 (с заглавной буквы), а не d64 int64 (строчная буква) по умолчанию: https://pandas.pydata.org/pandas- docs / version / 0.24 / whatsnew / v0.24.0.html # option-integer-na-support )

Уэс МакКинни
источник
7
Привет Уэс, есть ли обновление по этому поводу? Мы сталкиваемся с проблемами, заключающимися в том, что объединяемые столбцы преобразуются либо в целые, либо в числа с плавающей точкой, в зависимости от наличия значения NA в исходном списке. (Создание проблем позже при попытке объединить эти
кадры
1
Обновленная ссылка: pandas-docs.github.io/pandas-docs-travis/whatsnew/…
techvslife
8

Если производительность не является основной проблемой, вы можете хранить строки вместо этого.

df.col = df.col.dropna().apply(lambda x: str(int(x)) )

Тогда вы можете смешивать NaNстолько, сколько хотите. Если вы действительно хотите иметь целые числа, в зависимости от вашего приложения, вы можете использовать -1, или 0, или 1234567890, или какое-то другое выделенное значение для представления NaN.

Вы также можете временно дублировать столбцы: один, как у вас, с плавающей точкой; другой экспериментальный, со вставками или строками. Затем вставляет assertsв каждое разумное место, проверяя, что оба синхронизированы. После достаточного тестирования вы можете отпустить поплавки.

OSA
источник
5

Это решение не для всех случаев, но мое (геномные координаты) я использовал 0 в качестве NaN

a3['MapInfo'] = a3['MapInfo'].fillna(0).astype(int)

Это, по крайней мере, позволяет использовать надлежащий «родной» тип столбца, такие операции, как вычитание, сравнение и т. Д., Работают как положено

рыба фугу
источник
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) указать причину , почему Integer серии upcasted к 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
JPP
источник
1

Просто хочу добавить, что в случае, если вы пытаетесь преобразовать вектор с плавающей точкой (1.143) в целое число (1) с преобразованием NA в новый тип 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.

Pedro Moisés Camacho Ureña
источник
0

Если в текстовых данных есть пробелы, столбцы, которые обычно были бы целыми числами, будут преобразованы в числа с плавающей точкой как float64 dtype, потому что int64 dtype не может обрабатывать нули. Это может привести к несогласованности схемы, если вы загружаете несколько файлов, некоторые с пробелами (которые в конечном итоге получат float64, а другие, без которых получится int64).

Этот код будет пытаться преобразовать столбцы любого числового типа в Int64 (в отличие от int64), так как Int64 может обрабатывать нули

import pandas as pd
import numpy as np

#show datatypes before transformation
mydf.dtypes

for c in mydf.select_dtypes(np.number).columns:
    try:
        mydf[c] = mydf[c].astype('Int64')
        print('casted {} as Int64'.format(c))
    except:
        print('could not cast {} to Int64'.format(c))

#show datatypes after transformation
mydf.dtypes
Kynrek
источник