Як оцінити, скільки пам'яті знадобиться DataFrame Pandas?


125

Мені було цікаво ... Якщо я читаю, скажімо, файл csv 400 Мб у кадр даних панди (використовуючи read_csv або read_table), чи є можливість підрахувати, скільки пам'яті знадобиться? Просто намагаюся краще відчути фрейми даних та пам'ять ...


Ви завжди можете ознайомитись з процесом і його використанням пам'яті для одного файлу. Якщо ви використовуєте Linux, спробуйте, topа потім Shift + Mвідсортуйте моє використання пам'яті.
JayQuerie.com

Я думаю, що я повинен рекламувати це відкрите питання про панди .
Енді Хейден

3
У мене великий кадр даних з 4 мільйонами рядків. Я виявив, що його порожній підмножина x=df.loc[[]]займає 0.1кілька секунд, щоб обчислити (витягнути нульові рядки) і, крім того, займає сотні мегабайт пам'яті, як і оригінальний кадр даних, ймовірно, через деяке копіювання під ним.
osa

нове посилання на стару посаду головного розробника панд
саладі

Відповіді:


97

df.memory_usage() поверне кількість кожного стовпця:

>>> df.memory_usage()

Row_ID            20906600
Household_ID      20906600
Vehicle           20906600
Calendar_Year     20906600
Model_Year        20906600
...

Щоб включити індекси, пройдіть index=True.

Отже, щоб отримати загальне споживання пам’яті:

>>> df.memory_usage(index=True).sum()
731731000

Крім того, проходження deep=Trueдозволить отримати більш точний звіт про використання пам'яті, який враховує повне використання об'єктів, що містяться.

Це пояснюється тим, що використання пам'яті не включає пам'ять, яку споживають елементи, які не є компонентами масиву, якщо deep=False(випадок за замовчуванням).


1
чи справді вплив на обсяг пам’яті всіх стовпців впливає на використання пам’яті? Я можу собі уявити, що там більше накладних.
firelynx

14
Ви також дуже хочетеdeep=True
smci

Сума df.memory_usage () не дорівнює sys.getsizeof (df)! Накладних витрат багато. Як згадувалося у smci, вам потрібноdeep=True
бродяга

11
FYI, memory_usage()повертає використання пам'яті в байтах (як ви очікували).
engelen

2
Чому така величезна різниця між / без глибокого = True?
Nguai al

83

Ось порівняння різних методів - sys.getsizeof(df)найпростіше.

Для цього прикладу, dfє фрейм даних з 814 рядками, 11 стовпцями (2 входи, 9 об’єктів) - зчитується з формату 427 кб

sys.getsizeof (df)

>>> імпортувати sys
>>> sys.getsizeof (df)
(дає результати в байтах)
462456

df.memory_usage ()

>>> df.memory_usage ()
...
(перераховує кожен стовпець у 8 байт / рядок)

>>> df.memory_usage (). sum ()
71712
(приблизно рядки * cols * 8 байт)

>>> df.memory_usage (глибокий = True)
(перераховано повне використання пам'яті кожного стовпця)

>>> df.memory_usage (глибокий = True) .sum ()
(дає результати в байтах)
462432

df.info ()

Друкує інформацію про рамки даних для stdout. Технічно це кібібайти (KiB), а не кілобайти - як говориться в документі, "використання пам'яті показано в читаних людиною одиницях (представлення базових 2)". Отже, отримання байтів помножиться на 1024, наприклад 451,6 KiB = 462,438 байт.

>>> df.info ()
...
використання пам'яті: 70,0+ Кб

>>> df.info (memory_usage = 'глибокий')
...
використання пам'яті: 451,6 Кб

На який об’єкт чи модуль g посилається код вище?
zozo

@zozo woops - був виправлений помилка
Брайан Бернс

2
Я використовую df.info(memory_usage="deep"), він повертає "392,6 Мб", тоді як sys.getsizeof(df)і df.memory_usage(index=True, deep=True).sum()обидва повертають приблизно "411718016" (~ 411 МБ). Чи можете ви пояснити, чому 3 результати не відповідають? Дякую
Catbuilts

2
@BrianBurns: df.memory_usage(deep=True).sum()повертає майже те саме, що і з df.memory_usage(index=True, deep=True).sum(). у моєму випадку, indexDont займає багато пам'яті. Досить цікаво, я виявив, що 411718016/1024/1024 = 392.6так df.info(memory_usage="deep")може використовуватися 2^10для перетворення байтів у MB , що робить мене плутаниною. Дякую за допомогу в будь-якому випадку: D.
Catbuilts

1
@Catbuilts Ага, це пояснює це! df.infoповертає мебібайти (2 ^ 10), а не мегабайти (10 ^ 6) - відповідь змінить.
Брайан Бернс

43

Я думав, що піднесу ще трохи даних до дискусії.

Я провів низку тестів з цього питання.

Використовуючи resourceпакет python, я отримав використання пам'яті свого процесу.

І записуючи csv у StringIOбуфер, я міг легко виміряти його розмір у байтах.

Я провів два експерименти, кожен з яких створив 20 кадрів даних із збільшенням розмірів між 10 000 рядками та 1 000 000 рядків. Обидва мають 10 стовпців.

У першому експерименті я використовував лише поплавці у своєму наборі даних.

Так збільшилася пам'ять порівняно з файлом csv як функція кількості рядків. (Розмір у мегабайти)

Пам'ять і розмір CSV в Мегабайти як функція від кількості рядків з плаваючими записами

У другому експерименті у мене був такий самий підхід, але дані в наборі даних складалися лише з коротких рядків.

Пам'ять та розмір CSV в Мегабайти як функція від кількості рядків із рядковими записами

Здається, що співвідношення розміру csv та розміру фрейму даних може відрізнятися досить сильно, але розмір у пам'яті завжди буде більшим на 2-3 рази (для розмірів кадру в цьому експерименті)

Я хотів би доповнити цю відповідь ще кількома експериментами, будь ласка, коментуйте, якщо ви хочете, щоб я спробував щось особливе.


Яка ваша вісь y?
Ілля Володимирович Шуров

1
розмір max_rss та csv на диску в мегабайтах
firelynx

31

Ви повинні робити це в зворотному порядку.

In [4]: DataFrame(randn(1000000,20)).to_csv('test.csv')

In [5]: !ls -ltr test.csv
-rw-rw-r-- 1 users 399508276 Aug  6 16:55 test.csv

Технічно пам'ять про це (що включає в себе індекси)

In [16]: df.values.nbytes + df.index.nbytes + df.columns.nbytes
Out[16]: 168000160

Отже 168 Мб пам'яті з файлом 400 МБ, 1М рядків з 20 поплавкових стовпців

DataFrame(randn(1000000,20)).to_hdf('test.h5','df')

!ls -ltr test.h5
-rw-rw-r-- 1 users 168073944 Aug  6 16:57 test.h5

Набагато компактніше, коли записується як двійковий файл HDF5

In [12]: DataFrame(randn(1000000,20)).to_hdf('test.h5','df',complevel=9,complib='blosc')

In [13]: !ls -ltr test.h5
-rw-rw-r-- 1 users 154727012 Aug  6 16:58 test.h5

Дані були випадковими, тому стиснення не дуже допомагає


Це дуже розумно! Будь-яка ідея, як виміряти пам'ять, яку вам потрібно прочитати, використовуючи файл read_csv?
Енді Хайден

Не маю ідеї, як виміряти, як ви читаєте; IIRC, це може бути до 2х кінцевої пам'яті, необхідної для зберігання даних (з статті Веса), але я думаю, що він звів це до постійної + остаточної пам'яті
Джефф

Ах, мені потрібно перечитати, я згадав, що 2х був зручним теоретичним мінімом для певного алгоритму, якщо це навіть менше, що це coool.
Енді Хайден

Ви можете використовувати iotopяк top/ htopдля перегляду (в режимі реального часу) IO продуктивності.
Phillip Cloud

1
nbytesбуде грубо недооціненою, якщо у вас є, наприклад, рядки в кадрі даних.
osa

10

Якщо ви знаєте dtypes свого масиву, то ви можете безпосередньо обчислити кількість байтів, які знадобляться для зберігання ваших даних + деякі для самих об’єктів Python. Корисний атрибут numpyмасивів - це nbytes. Ви можете отримати кількість байтів з масивів у пандах DataFrame, виконавши це

nbytes = sum(block.values.nbytes for block in df.blocks.values())

objectdtype масиви зберігають 8 байтів на об'єкт (об’єктний масив dtype зберігає вказівник на непрозорий PyObject), тому якщо у вас є рядки у своєму csv, вам потрібно врахувати, що read_csvперетворить їх у objectмасиви dtype і відповідно скоригуйте свої обчислення.

Редагувати:

Див. numpyСторінку скалярних типів для отримання більш детальної інформації на сторінці object dtype. Оскільки зберігається лише посилання, потрібно також враховувати розмір об'єкта в масиві. Як зазначено на цій сторінці, масиви об'єктів дещо схожі на listоб’єкти Python .


Спасибі Філліп! Просто для уточнення - для рядка нам знадобиться 8 байт для вказівника на рядковий об’єкт плюс власне об’єкт рядка?
Енн

1
Так, для будь-якого типу об’єкта вам знадобиться 8-байтний покажчик + розмір (об’єкт)
Віктор Керкез

1
Запропонувати df.blocks.values ​​() Схоже, df.blocks зараз
дикт

8

Так, є. Панди зберігатимуть ваші дані у двовимірних нумерованих ndarrayструктурах, групуючи їх за типами. ndarrayце в основному необроблений масив даних C з невеликим заголовком. Таким чином, ви можете оцінити його розмір, просто помноживши розмір вміщеного на dtypeнього розмірів масиву.

Наприклад: якщо у вас 1000 рядків з 2 np.int32та 5 np.float64стовпцями, ваш DataFrame матиме один np.int32масив 2x1000 та один np.float64масив 5x1000, який є:

4 байти * 2 * 1000 + 8 байт * 5 * 1000 = 48000 байт


@AndyHayden Що ти маєш на увазі вартість будівництва? Розмір екземпляра DataFrame?
Філліп Хмара

Дякую Віктору! @Andy - Будь-яка ідея, яка велика вартість будівництва?
Енн

Це не включає, але pandasмає дуже ефективну реалізацію read_tableв Cython (це набагато краще, ніж numtі loadtxt), тому я припускаю, що він аналізує і зберігає дані безпосередньо в ndarray.
Віктор Керкез

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

6

Це я вважаю, що це дає розмір в пам'яті будь-якого об’єкта в python. Внутрішню внутрішню частину потрібно перевірити щодо панди та нумеру

>>> import sys
#assuming the dataframe to be df 
>>> sys.getsizeof(df) 
59542497
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.