Ответ
При ошибке памяти при слиянии в Pandas я действую по следующему чек-листу, начиная с самых вероятных причин:
1. Анализ объема данных:
# Оцениваю реальный объем памяти, занимаемый DataFrame
print(f"df1: {df1.memory_usage(deep=True).sum() / 1024**2:.2f} MB")
print(f"df2: {df2.memory_usage(deep=True).sum() / 1024**2:.2f} MB")
# Смотрю размеры таблиц
print(f"df1 shape: {df1.shape}, df2 shape: {df2.shape}")
Если суммарный объем близок к доступной оперативной памяти — проблема очевидна.
2. Оптимизация типов данных:
Часто в сырых данных используются неоптимальные типы, например, int64 или object для категориальных признаков.
# Привожу типы к более эффективным
df['category_col'] = df['category_col'].astype('category')
df['int_col'] = pd.to_numeric(df['int_col'], downcast='integer')
df['float_col'] = pd.to_numeric(df['float_col'], downcast='float')
3. Выбор стратегии слияния:
innerjoin создает наименьшую результирующую таблицу.- Если нужен
outerjoin, иногда эффективнее сделать дваinnerзапроса и затем конкатенировать результаты.
4. Проверка ключей слияния: Дубликаты в ключах могут взрывным образом увеличивать размер результата (декартово произведение).
# Проверяю на дубликаты ключей
print(f"Дубликаты в df1['key']: {df1['key'].duplicated().sum()}")
print(f"Дубликаты в df2['key']: {df2['key'].duplicated().sum()}")
5. Альтернативные подходы:
- Итеративная обработка: Разбиваю одну из таблиц на чанки и делаю merge по частям.
- Использование Dask: Если данные не помещаются в память, перехожу на библиотеку Dask для работы с ними на диске или в распределенной памяти.
- Переход к СУБД: Для регулярных операций с большими объемами данных правильным решением является использование базы данных (например, PostgreSQL) и выполнение JOIN средствами SQL.
Ответ 18+ 🔞
Давай разберём эту ситуацию с памятью в Pandas, как настоящие инженеры, а не мартышлюшки с клавиатурой. Ты представляешь, сидишь такой, кодишь, всё летает, а потом — бац! — и твой скрипт накрылся медным тазом с криком MemoryError. Удивление пиздец, да? Сам от себя охуеваешь.
Вот мой чек-лист, по которому я иду, когда терпения ноль ебать, а скрипт бздит.
1. Сначала смотрю, сколько жрёт моё добро. Потому что доверия ебать ноль к этим данным. Может, у тебя два датафрейма, а по факту — овердохуища информации.
# Оцениваю реальный объем памяти, занимаемый DataFrame
print(f"df1: {df1.memory_usage(deep=True).sum() / 1024**2:.2f} MB")
print(f"df2: {df2.memory_usage(deep=True).sum() / 1024**2:.2f} MB")
# Смотрю размеры таблиц
print(f"df1 shape: {df1.shape}, df2 shape: {df2.shape}")
Если сумма этих мегабайт подбирается к потолку твоей оперативки — всё, приехали. Проблема на поверхности, как хуй с горы.
2. Оптимизация типов — это святое.
Часто в сырых данных лежит всякий хлам: int64 там, где хватит int8, или object для колонки с тремя значениями. Это пиздопроебибна по неэффективности.
# Привожу типы к более эффективным
df['category_col'] = df['category_col'].astype('category')
df['int_col'] = pd.to_numeric(df['int_col'], downcast='integer')
df['float_col'] = pd.to_numeric(df['float_col'], downcast='float')
После таких манипуляций таблица может сжаться в разы, я тебе серьёзно.
3. Выбор стратегии слияния — тут надо думать головой.
innerjoin — наш лучший друг, он создаёт самый компактный результат.- Если тебе позарез нужен
outer, подумай: а может, сделать дваinnerи потом аккуратно склеить? Иногда это выгоднее.
4. Ключи слияния — вот где собака зарыта. Тут главная хитрая жопа. Дубликаты в ключах — это гарантированный взрыв размера. Получается декартово произведение, и ты из двух таблиц по гигабайту получаешь одну на терабайт. Ёпта.
# Проверяю на дубликаты ключей
print(f"Дубликаты в df1['key']: {df1['key'].duplicated().sum()}")
print(f"Дубликаты в df2['key']: {df2['key'].duplicated().sum()}")
Если тут цифры больше нуля — волнение ебать, пора чистить.
5. Если ничего не помогло — идём в тяжёлую артиллерию.
- Итеративная обработка: Режем одну таблицу на куски (чанки) и мержим по частям. Медленно, но работает.
- Dask: Если данные вообще не лезут в память, это твой выбор. Библиотека для ленивых вычислений, работает почти как Pandas, но с большими данными.
- СУБД — царь-решение: Для постоянной работы с огромными данными все эти костыли — хуй в пальто. Правильный путь — засунуть всё в нормальную базу (PostgreSQL, например) и делать JOIN'ы на стороне СУБД. Быстро, надёжно, по-взрослому.
В общем, э бошка думай, прежде чем слепо тыкать pd.merge(). А то будет вам хиросима, а не слияние таблиц.