减少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)。
减少数据框大小
尽可能避免使用对象dtype。
>>> 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
从熊猫0.17.1开始,您还df.info(memory_usage='deep')
可以查看包括对象在内的内存使用情况。
gc
gc.collect()