我能想到两种方法可以提供你所需的一些功能:
分块读取/每次读取n行等方式读取文件:
你可以将一个生成器函数传递给numpy.genfromtxt和numpy.loadtxt。这样,你可以在保留这两个函数的所有方便的解析功能的同时,以内存高效的方式从文本文件中加载大型数据集。
只从符合正则表达式匹配条件的行中读取数据:
你可以使用numpy.fromregex来使用正则表达式精确地定义应该加载哪些输入文件行中的标记。不符合模式的行将被忽略。
为了说明这两种方法,我将使用我的研究背景下的一个例子。
我经常需要加载具有以下结构的文件:
6
generated by VMD
CM 5.420501 3.880814 6.988216
HM1 5.645992 2.839786 7.044024
HM2 5.707437 4.336298 7.926170
HM3 4.279596 4.059821 7.029471
OD1 3.587806 6.069084 8.018103
OD2 4.504519 4.977242 9.709150
6
generated by VMD
CM 5.421396 3.878586 6.989128
HM1 5.639769 2.841884 7.045364
HM2 5.707584 4.343513 7.928119
HM3 4.277448 4.057222 7.022429
OD1 3.588119 6.069086 8.017814
这些文件可能非常巨大(以GB计),我只对数值数据感兴趣。所有数据块的大小都相同--在此示例中为
6
--并且它们始终由两行分隔。因此,块的
stride
为
8
。
使用第一种方法:
首先,我将定义一个生成器,该生成器会过滤掉不需要的行:
def filter_lines(f, stride):
for i, line in enumerate(f):
if i%stride and (i-1)%stride:
yield line
然后我打开文件,创建一个名为filter_lines
的生成器(这里需要知道stride
),并将该生成器传递给genfromtxt
函数:
with open(fname) as f:
data = np.genfromtxt(filter_lines(f, 8),
dtype='f',
usecols=(1, 2, 3))
这个操作非常简单。请注意,我可以使用usecols
来删除数据的第一列。同样,您还可以使用genfromtxt
的其他功能——检测类型,列与列之间的变化类型,缺失值,转换器等。
在此示例中,data.shape
为(204000, 3)
,而原始文件由272000
行组成。
在这里,使用generator
筛选同质跨度的行,但人们也可以想象它基于(简单的)条件过滤出不均匀的行块。
使用第二种方法:
这是我要使用的regexp
:
regexp = r'\s+\w+' + r'\s+([-.0-9]+)' * 3 + r'\s*\n'
组 -- 即在 ()
中 -- 定义了从给定行中提取的令牌。
接下来,fromregex
执行此任务并忽略不符合模式的行:
data = np.fromregex(fname, regexp, dtype='f')
结果与第一种方法完全一样。
append
更快吗?无论如何,我最终需要筛选后的np.array()。 - Roman Shapovalov