我有一个大阵写在一个CSV文件编号,并需要加载仅阵列中分得一杯羹。 从概念上讲我想打电话给np.genfromtxt()
然后排片所产生的阵列,但
- 该文件是如此之大,可能不适合在RAM
- 有关行的数量可能很小,所以没有必要分析每一行。
MATLAB具有的功能textscan()
可以采取一个文件描述符和只读文件的块。 有没有像在NumPy的东西吗?
现在,我定义下面的函数,它读取只有满足给定的条件的行:
def genfromtxt_cond(fname, cond=(lambda str: True)):
res = []
with open(fname) as file:
for line in file:
if cond(line):
res.append([float(s) for s in line.split()])
return np.array(res, dtype=np.float64)
有几个问题与此解决方案:
- 不是一般的:仅支持浮动式,而
genfromtxt
检测类型,这可以从列到列有所不同; 也缺失值,变换器,跳绳等; - 效率不高:当条件是困难的,每行可以被解析两次,也使用的数据结构和读取bufferization可能是次优的;
- 需要编写代码。
有没有实现过滤的标准功能,或MATLAB的一些对口textscan
?
我能想到的,提供一些你所要求的功能的两种方法:
读取文件无论是在块/或在正线/等的进步:
你可以通过一个generator
来numpy.genfromtxt以及对numpy.loadtxt 。 这样就可以从一个文本的内存高效,同时保留所有的两个函数的解析便利功能,加载大量数据集。
只从匹配可表示为一个正则表达式的标准的所有行读出的数据:
您可以使用numpy.fromregex并使用regular expression
来精确定义令牌从输入文件中给定的行应该被加载。 行不匹配的格局将被忽略。
为了说明这两种方法,我将使用从我的研究范围内的例子。
我经常需要用下面的结构来加载文件:
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
这些文件可以是巨大的(GBS),我只是在数值数据感兴趣。 所有的数据块具有相同的大小- 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')
其结果是完全一样的第一种方法。
如果您传递的类型(格式条件)的列表,使用try块,并用收益率来使用genfromtxt作为发电机,我们应该能够复制textscan()
def genfromtext(fname, formatTypes):
with open(fname, 'r') as file:
for line in file:
try:
line = line.split(',') # Do you care about line anymore?
r = []
for type, cell in zip(formatTypes, line):
r.append(type(cell))
except:
pass # Fail silently on this line since we hit an error
yield r
编辑:我忘了,除了块。 现在运行没关系,你可以使用genfromtext像这样一台发电机(使用随机CSV日志我已经围坐):
>>> a = genfromtext('log.txt', [str, str, str, int])
>>> a.next()
['10.10.9.45', ' 2013/01/17 16:29:26', '00:00:36', 0]
>>> a.next()
['10.10.9.45', ' 2013/01/17 16:22:20', '00:08:14', 0]
>>> a.next()
['10.10.9.45', ' 2013/01/17 16:31:05', '00:00:11', 3]
我也许应该注意,我用zip
拉上一起逗号分割线和formatSpec(当列表中的一个用完的项目停止),这将tuplify两个列表,所以我们可以对他们进行迭代在一起,避免回路相关在len(line)
或者类似的东西。
想要证明注释OP。
def fread(name, cond):
with open(name) as file:
for line in file:
if cond(line):
yield line.split()
def a_genfromtxt_cond(fname, cond=(lambda str: True)):
"""Seems to work without need to convert to float."""
return np.array(list(fread(fname, cond)), dtype=np.float64)
def b_genfromtxt_cond(fname, cond=(lambda str: True)):
r = [[int(float(i)) for i in l] for l in fread(fname, cond)]
return np.array(r, dtype=np.integer)
a = a_genfromtxt_cond("tar.data")
print a
aa = b_genfromtxt_cond("tar.data")
print aa
产量
[[ 1. 2.3 4.5]
[ 4.7 9.2 6.7]
[ 4.7 1.8 4.3]]
[[1 2 4]
[4 9 6]
[4 1 4]]