Ответ 1
Сокращение использования памяти в Python затруднено, потому что Python фактически не выводит память обратно в операционную систему. Если вы удаляете объекты, тогда память доступна для новых объектов Python, но не free()
'd назад в систему (см. Этот вопрос).
Если вы придерживаетесь числовых массивов 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).
Уменьшение размера файлового блока
По возможности избегайте использования объектов dtypes.
>>> 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
Просмотр использования памяти
Вы можете просмотреть использование памяти (docs):
>>> 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')
, чтобы увидеть использование памяти, включая объекты.