在用python处理数据处理的时候有时候会碰到较大的数据集,可能会出现Memory Error 的问题,经过我的尝试,总结了如下几个方案。

1.回收一些暂时不用的内存

  首先扩展一下python查看内存的方法:

import psutil
import os
info = psutil.virtual_memory()
print('内存使用:',psutil.Process(os.getpid()).memory_info().rss)
print('总内存:',info.total)
print('内存占比:',info.percent)
print('CPU个数:',psutil.cpu_count())

输出:

内存使用: 1083351040
总内存: 17074249728
内存占比: 24.1
CPU个数: 4

  python的psutil包可以查看内存的使用情况,直接点任务管理器也可以查看电脑的内存使用占比,还可以kill掉一些不用的进程来释放内存。但是如果想要释放掉python占用的内存,比如一些使用过后续又不再需要的数据,可以导入gc包直接删除掉数据并回收内存。

import gc
del user_log
gc.collect()

输出:

19037

2. 修改数据类型的长度

  修改数据类型的长度,可以对数据进行内存压缩,从而减少内存的占用。

import time
# 对数据进行内存压缩
def reduce_mem_usage(df):
    starttime = time.time()
    numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
    start_mem = df.memory_usage().sum() / 1024**2
    
    for col in df.columns:
        col_type = df[col].dtypes
        if col_type in numerics:
            c_min = df[col].min()
            c_max = df[col].max()
            if pd.isnull(c_min) or pd.isnull(c_max):
                continue
            if str(col_type)[:3] == 'int':
                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
                    df[col] = df[col].astype(np.int8)
                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                    df[col] = df[col].astype(np.int16)
                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
                    df[col] = df[col].astype(np.int32)
                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
                    df[col] = df[col].astype(np.int64)
            else:
                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
                    df[col] = df[col].astype(np.float16)
                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
                    df[col] = df[col].astype(np.float32)
                else:
                    df[col] = df[col].astype(np.float64)
    end_mem = df.memory_usage().sum() / 1024**2
    print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
    print('Decreased by {:.1f}%'.format(100*(start_mem-end_mem)/start_mem))
        
    return df

3. 分而治之

  读文件的时候可以逐行读取或者分块读取,避免一次性把数据都读入到内存里,导致程序崩掉。

  • 逐行读取:
data = []
with open(path, 'r',encoding='gbk',errors='ignore') as f:
    for line in f:
        data.append(line.split(','))
  • 分块读取
      有时候即使可以一次性读取所有数据,但是对数据进行操作时(比如reduce_mem_usage),也可能跑不起来,这时候可以分块处理,再把结果拼接起来。
user_log_file = r'./file.csv'
read_chunks = pd.read_csv(user_log_file,iterator=True,chunksize=500000)
user_log = pd.DataFrame()
for chunk in read_chunks:
    chunk = reduce_mem_usage(chunk)
    user_log = user_log.append(chunk)

4. 修改磁盘虚拟内存

扩大磁盘虚拟内存:
1、打开 控制面板
2、找到 系统 这一项;
3、找到 高级系统设置 这一项;
4、点击 性能 模块的 设置 按钮;
5、选择 高级,在 虚拟内存 模块点击更改
6、选择一个你文件运行的磁盘,点击自定义大小
记得 不要 选中“自动管理所有驱动器的分页文件大小”,手动输入初始大小和最大值,当然,最好不要太大,更改之后能在查看盘的使用情况,不要丢掉太多空间。
7、都设置好之后,记得点击 “设置”, 然后再确定,否则无效,最后 重启电脑 就可以了。(一开始我没有重启电脑,还是跑不动,一度怀疑自己的硬件问题。)

  如果还有其他方法可以解决内存问题,欢迎留言交流~

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐