Зменшити використання пам'яті в Python важко, оскільки Python насправді не повертає пам'ять до операційної системи . Якщо ви видаляєте об'єкти, пам'ять доступна для нових об’єктів Python, але не free()
повертається до системи ( див. Це питання ).
Якщо ви дотримуєтеся числових масивів, вони звільняються, але об'єкти в коробці - ні.
>>> import os, psutil, numpy as np
>>> def usage():
... process = psutil.Process(os.getpid())
... return process.get_memory_info()[0] / float(2 ** 20)
...
>>> usage() # initial memory usage
27.5
>>> arr = np.arange(10 ** 8) # create a large array without boxing
>>> usage()
790.46875
>>> del arr
>>> usage()
27.52734375 # numpy just free()'d the array
>>> arr = np.arange(10 ** 8, dtype='O') # create lots of objects
>>> usage()
3135.109375
>>> del arr
>>> usage()
2372.16796875 # numpy frees the array, but python keeps the heap big
Зменшення кількості фреймів даних
Python зберігає нашу пам'ять на високому водному знаку, але ми можемо зменшити загальну кількість створених нами фреймів. Під час зміни свого фрейму даних надайте перевагу inplace=True
, щоб ви не створювали копії.
Ще один розповсюджений gotcha - це копія раніше створених фреймів даних в ipython:
In [1]: import pandas as pd
In [2]: df = pd.DataFrame({'foo': [1,2,3,4]})
In [3]: df + 1
Out[3]:
foo
0 2
1 3
2 4
3 5
In [4]: df + 2
Out[4]:
foo
0 3
1 4
2 5
3 6
In [5]: Out # Still has all our temporary DataFrame objects!
Out[5]:
{3: foo
0 2
1 3
2 4
3 5, 4: foo
0 3
1 4
2 5
3 6}
Ви можете виправити це, ввівши, %reset Out
щоб очистити свою історію. Крім того, ви можете налаштувати кількість історії, яку зберігає ipython ipython --cache-size=5
(за замовчуванням - 1000).
Зменшення розміру фрейму даних
По можливості уникайте використання об'єктних типів.
>>> df.dtypes
foo float64 # 8 bytes per value
bar int64 # 8 bytes per value
baz object # at least 48 bytes per value, often more
Значення з типом об'єкта є в коробці, що означає, що нумерований масив просто містить вказівник, і ви маєте повний об’єкт Python на купі для кожного значення у вашому фреймі даних. Сюди входять рядки.
Хоча numpy підтримує рядки фіксованого розміру в масивах, панди не мають ( це викликає плутанину користувачів ). Це може суттєво змінитись:
>>> import numpy as np
>>> arr = np.array(['foo', 'bar', 'baz'])
>>> arr.dtype
dtype('S3')
>>> arr.nbytes
9
>>> import sys; import pandas as pd
>>> s = pd.Series(['foo', 'bar', 'baz'])
dtype('O')
>>> sum(sys.getsizeof(x) for x in s)
120
Можливо, ви хочете уникати використання рядкових стовпців або знайти спосіб подання рядкових даних у вигляді чисел.
Якщо у вас є фрейм даних, який містить багато повторених значень (NaN дуже поширений), ви можете використовувати розріджену структуру даних для зменшення використання пам'яті:
>>> df1.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 39681584 entries, 0 to 39681583
Data columns (total 1 columns):
foo float64
dtypes: float64(1)
memory usage: 605.5 MB
>>> df1.shape
(39681584, 1)
>>> df1.foo.isnull().sum() * 100. / len(df1)
20.628483479893344 # so 20% of values are NaN
>>> df1.to_sparse().info()
<class 'pandas.sparse.frame.SparseDataFrame'>
Int64Index: 39681584 entries, 0 to 39681583
Data columns (total 1 columns):
foo float64
dtypes: float64(1)
memory usage: 543.0 MB
Перегляд використання пам'яті
Ви можете переглянути використання пам'яті ( документи ):
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 39681584 entries, 0 to 39681583
Data columns (total 14 columns):
...
dtypes: datetime64[ns](1), float64(8), int64(1), object(4)
memory usage: 4.4+ GB
З панд 0.17.1 ви також df.info(memory_usage='deep')
можете бачити використання пам'яті, включаючи об'єкти.
gc
модуль і зателефонувати,gc.collect()
але він може не відновити пам'ять