如何快速读取含START/END标签的顶点数据文件?
我有一个数据文件,部分内容如下:
START vertex 266.36 234.594 14.6145 vertex 268.582 234.968 15.6956 vertex 267.689 232.646 15.7283 END START vertex 166.36 23.594 4.6145 vertex 8.582 23.968 5.6956 vertex 67.689 32.646 1.7283 END # [...]
文件由多个包含三个vertex的块组成。我目前采用逐行读取的方式加载数据,但速度很慢,当前代码如下:
data = numpy.empty((n, 3)) flt = numpy.vectorize(float) for k in range(n): parts = f.readline().decode('utf-8').split() assert len(parts) == 4 assert parts[0] == 'vertex' data[k] = flt(parts[1:])
想请教下有什么可行的优化建议?
嘿,看到你用逐行读取加numpy.vectorize的方式处理数据速度慢,太能理解了——Python的循环和频繁IO本来就是性能瓶颈,这里给你几个实用的优化方向,都是实际项目里验证过的:
一次性读取整个文件,批量处理
IO操作是最大的拖油瓶,逐行读取会频繁调用系统IO接口,不如一次性把整个文件内容读进来,再集中做字符串处理。比如:import numpy as np # 一次性读取全部内容,减少IO次数 with open('your_file.txt', 'rb') as f: content = f.read().decode('utf-8') # 拆分所有字符串片段,筛选出vertex相关的数值 tokens = content.split() # 找到所有标记为'vertex'的位置 vertex_positions = [i for i, token in enumerate(tokens) if token == 'vertex'] # 收集每个vertex后面的三个数值 numeric_values = [] for pos in vertex_positions: numeric_values.extend(tokens[pos+1 : pos+4]) # 用numpy批量转换为浮点数组,比vectorize高效太多 data = np.array(numeric_values, dtype=np.float64).reshape(-1, 3)这里把IO次数降到1次,而且用numpy的原生数组转换替代了
vectorize——别被vectorize的名字骗了,它本质还是Python循环,根本不是真正的向量化操作,速度快不起来。用numpy内置的文本读取函数
numpy自带的np.loadtxt或np.genfromtxt专门优化了文本读取,比手动循环高效得多。你可以先读取所有数据,再筛选出vertex开头的行:import numpy as np # 读取所有非注释行,按空格分隔 all_rows = np.loadtxt('your_file.txt', dtype=str, comments='#') # 筛选第一列是'vertex'的行,再转换为浮点型 vertex_data = all_rows[all_rows[:, 0] == 'vertex'][:, 1:].astype(np.float64)如果文件超大,内存放不下,还可以配合生成器用
np.fromiter分批处理,但一般情况下,只要内存足够,这种方式比手动循环快好几倍。借助pandas处理大文件
如果你的数据量特别大,pandas的文本读取工具内部做了很多底层优化,处理效率更高,代码也更简洁:import pandas as pd # 按空格分隔读取所有行,忽略注释 df = pd.read_table('your_file.txt', sep='\s+', header=None, comment='#') # 筛选出第一列为'vertex'的行,提取后三列转为numpy数组 data = df[df[0] == 'vertex'].iloc[:, 1:4].to_numpy(dtype=np.float64)pandas在处理大文本时的性能优势很明显,尤其是数据量超过百万行的时候。
去掉不必要的断言
原代码里的两个assert在调试阶段很有用,但如果是生产环境且你已经确认数据格式完全合规,去掉它们能节省不少额外的性能开销。
内容的提问来源于stack exchange,提问作者Nico Schlömer

