处理500MB文本文件时遇Pandas MemoryError及apply属性缺失问题
解决大文本文件处理的内存错误与分块读取问题
咱们先拆解下你遇到的两个核心问题,再一步步给出针对性的解决方案:
1. 初始代码的MemoryError原因
你一开始用file.readlines()直接把500MB的文件全部加载到内存里,生成了一个包含所有行的巨大列表,这直接超出了内存承载上限,所以抛出了MemoryError。
2. 分块读取后的AttributeError原因
pd.read_csv(..., chunksize=chunksize)返回的是TextFileReader迭代器对象,而不是常规的DataFrame/Series——它本身没有apply方法,你需要遍历这个迭代器,对每个分块(实际是小型DataFrame)单独处理。
关键隐藏bug:你的fixup函数无效
注意:字符串在Python中是不可变对象,x.replace(...)不会修改原变量x,必须把返回值重新赋值给x,否则所有替换操作都是无效的!我已经在下面的代码里修正了这个问题。
方案一:用Pandas分块处理(适合后续需用Pandas分析的场景)
这个方案保留Pandas的分块机制,逐块处理后写入输出文件,彻底避免一次性加载全部数据:
import re import pandas as pd import html # 修正后的fixup函数 def fixup(x): # 所有替换操作必须重新赋值给x,否则无效 x = x.replace('>', '').replace('<', '').replace('doc', '')\ .replace(':', '').replace('t_up', '').replace('fi.wikipedia.org', '')\ .replace('url="https', '').replace('\xa0', '') x = html.unescape(x) # 替换多个空格为单个空格,最后清理首尾空格 return re1.sub(' ', x).strip() # 正则表达式只编译一次,提升处理效率 re1 = re.compile(r' +') chunksize = 10000 # 可根据内存大小调整,比如20000或50000 input_file = f'{trn_path}text.00' output_file = f'{trn_path}train_processed.csv' # 先创建空输出文件,避免后续追加时重复写入表头 with open(output_file, 'w', encoding='utf-8') as f: pass # 遍历每个分块进行处理 for chunk in pd.read_csv(input_file, header=None, chunksize=chunksize): # 对分块的第0列(所有行存在这里,因为header=None)应用fixup chunk[0] = chunk[0].apply(fixup) # 追加写入输出文件 chunk.to_csv(output_file, mode='a', header=False, index=False) # 后续如需使用处理后的数据,可再次读取(同样支持分块) df_trn = pd.read_csv(output_file, header=None)
方案二:纯Python逐行处理(更省内存,适合仅需文本清洗的场景)
如果不需要用Pandas做后续分析,直接用Python原生文件操作逐行处理,内存占用会极低:
import re import html re1 = re.compile(r' +') input_file = f'{trn_path}text.00' output_file = f'{trn_path}train_processed.csv' with open(input_file, 'r', encoding='utf-8') as infile, open(output_file, 'w', encoding='utf-8') as outfile: for line in infile: # 逐行执行清洗操作 line = line.replace('>', '').replace('<', '').replace('doc', '')\ .replace(':', '').replace('t_up', '').replace('fi.wikipedia.org', '')\ .replace('url="https', '').replace('\xa0', '') line = html.unescape(line) line = re1.sub(' ', line).strip() # 可选:跳过空行,根据需求调整 if line: outfile.write(line + '\n')
这两个方案都能解决你的内存问题,同时避免分块读取后的属性错误,还修正了原函数中替换无效的隐藏bug。
内容的提问来源于stack exchange,提问作者Minsky
相关产品推荐
相关产品推荐

