Уменьшить использование памяти в Python сложно, потому что Python фактически не возвращает память операционной системе . Если вы удаляете объекты, память становится доступной для новых объектов Python, но не free()
возвращается в систему ( см. Этот вопрос ).
Если вы придерживаетесь числовых массивов numpy, они освобождаются, а упакованные объекты - нет.
>>> 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
, чтобы вы не создавали копии.
Еще одна распространенная проблема - сохранение копий ранее созданных фреймов данных в 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
Значения с объектом dtype помещены в рамку, что означает, что массив numpy просто содержит указатель, и у вас есть полный объект Python в куче для каждого значения в вашем фрейме данных. Сюда входят струны.
Хотя numpy поддерживает строки фиксированного размера в массивах, pandas - нет ( это вызвало путаницу у пользователей ). Это может иметь большое значение:
>>> 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
Начиная с pandas 0.17.1, вы также df.info(memory_usage='deep')
можете видеть использование памяти, включая объекты.
gc
модуль и вызвать,gc.collect()
но он может не восстановить память