Преобразовать столбец Pandas, содержащий NaN, в dtype `int`

Я прочитал данные из 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

Как я могу это решить?

Ответ 1

Отсутствие числа NaN в целочисленных столбцах является пандой "гоча".

Обычный обходной путь - просто использовать поплавки.

Ответ 2

Мой сценарий использования - данные перед загрузкой в таблицу БД:

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.

Это не красиво, но это делает работу!

Ответ 3

В версии 0.24. + Pandas получила возможность хранить целочисленные dtypes с пропущенными значениями.

Обнуляемый целочисленный тип данных.

Панды могут представлять целочисленные данные с возможно отсутствующими значениями, используя arrays.IntegerArray. Это расширение типов, реализованное в пандах. Это не dtype по умолчанию для целых чисел, и не будет выведено; Вы должны явно передать dtype в array() или Series:

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

0      1
1      2
2    NaN
dtype: Int64

Ответ 4

Если вы можете изменить свои сохраненные данные, используйте недопустимое значение для id. Обычный пример использования, выведенный по имени столбца, состоит в том, что id является целым числом, строго большим нуля, вы можете использовать 0 как значение дозорного, чтобы вы могли писать

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

Ответ 5

Вы можете использовать .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

Ответ 6

Теперь можно создать столбец панд, содержащий NaNs, как dtype int, поскольку теперь он официально добавлен в панды 0.24.0.

Замечания к выпуску pandas 0.24.x Цитата: "У Pandas появилась возможность хранить целочисленные dtypes с пропущенными значениями

Ответ 7

Предполагая, что ваш DateColumn в формате 3312018.0 должен быть преобразован в 31.03.2008 в виде строки. И некоторые записи отсутствуют или 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'))

Ответ 8

Я столкнулся с этой проблемой, работая с pyspark. Так как это интерфейс Python для кода, работающего на jvm, он требует безопасности типов и использование float вместо int не вариант. Я pd.read_csv эту проблему, обернув pandas 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

Ответ 9

Сначала удалите строки, которые содержат NaN. Затем выполните целочисленное преобразование оставшихся строк. Наконец, вставьте удаленные строки снова. Надеюсь, это сработает

Ответ 10

Если вы абсолютно хотите объединить целые и NaN в столбце, вы можете использовать тип данных "объект":

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

Это заменит NaN на целое число (неважно, какое), преобразует в int, преобразует в объект и, наконец, вставляет NaN.

Ответ 11

Большинство решений здесь говорят вам, как использовать целое число заполнителя для представления значений NULL. Такой подход не поможет, если вы не уверены, что целое число не будет отображаться в ваших исходных данных. Мой метод с будет форматировать плавающие без их десятичных значений и преобразовывать нули в None's. Результатом является объектный тип данных, который при загрузке в CSV будет выглядеть как целочисленное поле с нулевыми значениями.

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

Ответ 12

Преобразовать в float (игнорируя ошибки), а затем преобразовать результат в int.

df['id'] = df['id'].astype(float, errors='ignore').astype(int) 

В качестве альтернативы:

df['id'] = df['id'].replace(np.nan,0) 

А затем используйте регулярное выражение:

df['id'] = df['id'].astype(int)

В случае чисел, первоначально отформатированных в виде строк (например, "35" вместо 35), помогает следующее:

df['id'] = df['id'].apply(lambda x: int(x))

Ответ 13

NaNs во фреймах данных панд по умолчанию np.NaN. Если в вашей серии есть astype(int,errors='ignore') не изменит серию на целые и останется как float. Вам нужно сначала преобразовать np.NaN в None:

df['id'] = df['id'].replace(np.NaN, None).astype(int,errors='ignore')

Ответ 14

В моем случае я отредактировал формат столбца csv i.e. изменил формат столбца от общего к числу. Затем я могу изменить тип в pandas.

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