Условие
После pd.read_csv user_id стал float, цена — object, дата — строка, флаг подписки — int (0/1). Чем это плохо и как исправить?
Решение
Почему так получается
- int с NaN → float. Pandas-int не поддерживает NaN, поэтому при единственном пропуске вся колонка станет float64. Решение —
Int64(nullable, с большой буквы). - Цена object = в значениях есть нечисловые символы (
'1 200','1,200.50','—'). - Дата строкой =
parse_dates=['col']не указан. - Флаг 0/1 как int — нормально, но
boolэкономит память и читается лучше.
Реализация
df['user_id'] = df['user_id'].astype('Int64') # nullable integer
df['price'] = (
df['price']
.astype(str)
.str.replace(' ', '', regex=False)
.str.replace(',', '.', regex=False)
.replace({'—': None, '': None})
.astype('float64')
)
df['ts'] = pd.to_datetime(df['ts'], errors='coerce')
df['is_subscribed'] = df['is_subscribed'].astype(bool)
# Категории с низкой кардинальностью
df['country'] = df['country'].astype('category')Memory check
print(df.dtypes)
print(df.memory_usage(deep=True).sum() / 1e6, 'MB')Подводные камни
astype(int)упадёт на NaN — всегда сначалаInt64(nullable) илиfillna.pd.to_datetime(errors='raise')упадёт на первом мусоре.errors='coerce'ставит NaT — обычно лучше.- Конкатенация
category + categoryс разными категориями становится object. Используйтеunion_categoricals. - Сравнение
boolиintработает, ноdf['flag'] == Trueиногда возвращает не то, что ждёте.df['flag'].astype(bool). - JSON/CSV не различает int/float — данные нужно явно типизировать на этапе чтения через
dtype=.
Эталонный ответ
Nullable Int64 для целых с пропусками, category для низкой кардинальности, pd.to_datetime(errors='coerce') для дат. Типизировать на этапе read_csv(dtype=...), а не после.