Перетворимо стовпчик Pandas, що містить NaNs, у тип `int`


175

Я читаю дані з .csv-файлу до фрейму даних Pandas, як показано нижче. Для одного з стовпців idя хочу вказати тип стовпця як int. Проблема полягає в тому, що в idсерії є відсутні / порожні значення.

Коли я намагаюся передати idстовпчик на ціле число під час читання .csv, я отримую:

df= pd.read_csv("data.csv", dtype={'id': int}) 
error: Integer column has NA values

Крім того, я спробував перетворити тип стовпця після читання, як показано нижче, але цього разу я отримав:

df= pd.read_csv("data.csv") 
df[['id']] = df[['id']].astype(int)
error: Cannot convert NA to integer

Як я можу вирішити це?


3
Я думаю, що цілі значення не можуть бути перетворені або збережені в серії / фреймі даних, якщо відсутні / значення NaN. Це, на мою думку, стосується сумісної сумісності (я здогадуюсь тут), якщо ви хочете пропустити сумісність значень, то я б зберігав значення як плаваючі
EdChum

1
дивіться тут: pandas.pydata.org/pandas-docs/dev/… ; у вас повинен бути поплавковий тип, коли у вас відсутні значення (або технічно об'єктний тип, але це неефективно); яка ваша мета використання типу int?
Джефф

6
Я вважаю, що це проблема NumPy, не характерна лише для Pandas. Прикро, оскільки існує так багато випадків, коли тип int, який дозволяє можливість нульових значень, набагато ефективніший, ніж великий стовпець плавців.
ely

1
У мене теж проблема з цим. У мене є кілька фреймів даних, які я хочу об'єднати на основі рядкового представлення кількох "цілих" стовпців. Однак, коли в одному з цих цілих стовпців є np.nan, кастинг рядків створює ".0", який скидає злиття. Просто робить речі дещо складнішими, було б добре, якби була проста робота.
дермен

1
@Rhubarb, Необов'язкова підтримка цілочисельних чисел тепер офіційно додана на пандах 0,24,0 - нарешті :) - знайдіть оновлену відповідь нижче. pandas 0.24.x нотатки до випуску
mork

Відповіді:


169

Відсутність репрезентації NaN у цілих цілих стовпцях - це панда "готча" .

Звичайний спосіб вирішення - просто використовувати поплавці.


13
Чи є ще якісь обхідні шляхи, окрім поводження з ними як з поплавками?
NumenorForLife

3
@ jsc123 ви можете використовувати тип об’єкта. Це додається з невеликим попередженням про здоров'я, але здебільшого працює добре.
Енді Хайден

1
Чи можете ви навести приклад того, як використовувати dtype об'єкта? Я переглядав документи pandas і googling, і читав, що це рекомендований метод. Але я не знайшов приклад, як використовувати тип об’єкта.
MikeyE

29
У версії v0.24 тепер ви можете це зробити df = df.astype(pd.Int32Dtype())(конвертувати всю фрейм даних або) df['col'] = df['col'].astype(pd.Int32Dtype()). Іншими прийнятими нульовими цілими типами є pd.Int16Dtypeі pd.Int64Dtype. Виберіть свою отруту.
cs95

1
Це значення NaN, але перевірка isnan взагалі не працює :(
Winston,

117

У версії 0.24. + Панди отримали можливість зберігати цілі dtypes з відсутніми значеннями.

Тип даних про незмінне ціле число .

Панди можуть представляти цілі дані з можливими відсутніми значеннями, використовуючи arrays.IntegerArray. Це типи розширень, реалізовані в межах панд. Не є типом за замовчуванням для цілих чисел, і він не буде зроблений; ви повинні явно передати dtype у array()або Series:

arr = pd.array([1, 2, np.nan], dtype=pd.Int64Dtype())
pd.Series(arr)

0      1
1      2
2    NaN
dtype: Int64

Для перетворення стовпця в нульові цілі числа використовуйте:

df['myCol'] = df['myCol'].astype('Int64')

4
Мені подобається ця відповідь.
cs95

8
Зауважте, що dtype повинен бути, "Int64"а не "int64"(спочатку "я" має бути з великої літери)
В'ячеслав Z

2
df.myCol = df.myCol.astype('Int64')абоdf['myCol'] = df['myCol'].astype('Int64')
LoMaPh

43

Мій випадок використання - це розміщення даних перед завантаженням у таблицю БД:

df[col] = df[col].fillna(-1)
df[col] = df[col].astype(int)
df[col] = df[col].astype(str)
df[col] = df[col].replace('-1', np.nan)

Видаліть NaN, перетворіть у int, перетворіть у str та повторно вставте NAN.

Це не дуже, але це робить роботу!


1
Я витягнув волосся, намагаючись завантажити серійні номери, де деякі є нульовими, а решта - плаваючими, це врятувало мене.
Кріс Декер

1
ОП хоче стовпчик цілих чисел. Перетворення його в рядок не відповідає умові.
Рішаб Гупта,

1
Працює лише в тому випадку, якщо у колу ще немає -1. В іншому випадку він
зіпсується

то як повернутися до int .. ??
abdoulsn

5

Тепер можна створити стовпчик панди, що містить NaNs як dtype int, оскільки він тепер офіційно доданий на пандах 0,24,0

Примітки до випуску pandas 0.24.x Цитата: " Pandas отримав можливість зберігати цілі цінні типи з відсутніми значеннями


4

Якщо ви абсолютно хочете об'єднати цілі числа та NaN в стовпці, ви можете використовувати тип даних 'object':

df['col'] = (
    df['col'].fillna(0)
    .astype(int)
    .astype(object)
    .where(df['col'].notnull())
)

Це замінить NaN на ціле число (не важливо, яке), перетворить на int, перетворить на об’єкт і, нарешті, знову вставить NaNs.


3

Якщо ви можете змінити збережені дані, використовуйте дозорне значення для відсутніх id. Загальний випадок використання, який випливає з імені стовпця, оскільки idце ціле число, строго більше нуля, ви можете використовувати 0як дозорне значення, щоб ви могли писати

if row['id']:
   regular_process(row)
else:
   special_process(row)

3

Ви можете використовувати, .dropna()якщо це нормально для опускання рядків зі значеннями NaN.

df = df.dropna(subset=['id'])

Крім того, використовуйте .fillna()та .astype()замінюйте NaN значеннями та перетворюйте їх в int.

Я зіткнувся з цією проблемою під час обробки файлу CSV з великими цілими числами, а деякі з них були відсутні (NaN). Використання float як типу не було варіантом, тому що я можу втратити точність.

Моє рішення полягало у використанні str як проміжного типу . Тоді ви можете перетворити рядок у int, як згодом, у коді. Я замінив NaN на 0, але ви можете вибрати будь-яке значення.

df = pd.read_csv(filename, dtype={'id':str})
df["id"] = df["id"].fillna("0").astype(int)

Для ілюстрації ось приклад того, як поплавці можуть втратити точність:

s = "12345678901234567890"
f = float(s)
i = int(f)
i2 = int(s)
print (f, i, i2)

А вихід:

1.2345678901234567e+19 12345678901234567168 12345678901234567890

2

Більшість рішень тут розповідає, як використовувати ціле число заповнювача для представлення нулів. Цей підхід не корисний, якщо ви не впевнені, що ціле число не відображатиметься у вихідних даних. Мій метод з буде форматувати плаває без їх десяткових значень і перетворювати нулі в None. Результат - це тип даних об'єкта, який буде виглядати як ціле поле з нульовими значеннями при завантаженні в CSV.

keep_df[col] = keep_df[col].apply(lambda x: None if pandas.isnull(x) else '{0:.0f}'.format(pandas.to_numeric(x)))

1

Я зіткнувся з цим питанням, працюючи з pyspark. Оскільки це frontend пітона для коду, що працює на jvm, він вимагає безпеки типу, а використання float замість int не є варіантом. Я вирішив проблему, загорнувши панди pd.read_csvу функцію, яка заповнить визначені користувачем стовпці із визначеними користувачем значеннями заповнення перед тим, як надати їх потрібному типу. Ось, що я закінчив:

def custom_read_csv(file_path, custom_dtype = None, fill_values = None, **kwargs):
    if custom_dtype is None:
        return pd.read_csv(file_path, **kwargs)
    else:
        assert 'dtype' not in kwargs.keys()
        df = pd.read_csv(file_path, dtype = {}, **kwargs)
        for col, typ in custom_dtype.items():
            if fill_values is None or col not in fill_values.keys():
                fill_val = -1
            else:
                fill_val = fill_values[col]
            df[col] = df[col].fillna(fill_val).astype(typ)
    return df

1
import pandas as pd

df= pd.read_csv("data.csv")
df['id'] = pd.to_numeric(df['id'])

4
Чи є причина, що ви віддаєте перевагу цій формулярі над запропонованою у прийнятій відповіді? Якщо це так, було б корисно відредагувати свою відповідь, щоб дати пояснення, і тим більше, що є десять додаткових відповідей, які змагаються за увагу.
Джеремі Кейні

Хоча цей код може вирішити проблему з ОП, найкраще включити пояснення, як / чому ваш код вирішує це. Таким чином майбутні відвідувачі можуть дізнатисясь із вашої публікації та застосувати її до власного коду. ТАК - це не програма кодування, а ресурс для знань. Крім того, швидше за все буде запрошено високу якість, повну відповідь. Ці функції, поряд з вимогою, що всі повідомлення є автономними, є деякою сильною стороною SO, оскільки платформа відрізняє її від форумів. Ви можете editдодати додаткову інформацію та / або доповнити свої пояснення джерельною документацією.
ШерілХоман

0

Спочатку видаліть рядки, які містять NaN. Потім виконайте перетворення цілого числа на решти рядків. Останнє знову вставити вилучені рядки. Сподіваюся, це спрацює


-1

Припустимо, що формат 3312018.0 у форматі DateColumn перетвориться на 31.03.2018 як рядок. І деякі записи відсутні або 0.

df['DateColumn'] = df['DateColumn'].astype(int)
df['DateColumn'] = df['DateColumn'].astype(str)
df['DateColumn'] = df['DateColumn'].apply(lambda x: x.zfill(8))
df.loc[df['DateColumn'] == '00000000','DateColumn'] = '01011980'
df['DateColumn'] = pd.to_datetime(df['DateColumn'], format="%m%d%Y")
df['DateColumn'] = df['DateColumn'].apply(lambda x: x.strftime('%m/%d/%Y'))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.