与上飞的过滤线NumPy的阅读文件(NumPy reading file with filterin

2019-07-19 03:43发布

我有一个大阵写在一个CSV文件编号,并需要加载仅阵列中分得一杯羹。 从概念上讲我想打电话给np.genfromtxt()然后排片所产生的阵列,但

  1. 该文件是如此之大,可能不适合在RAM
  2. 有关行的数量可能很小,所以没有必要分析每一行。

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

Answer 1:

我能想到的,提供一些你所要求的功能的两种方法:

  1. 读取文件无论是在块/或在正线/等的进步:
    你可以通过一个generator来numpy.genfromtxt以及对numpy.loadtxt 。 这样就可以从一个文本的内存高效,同时保留所有的两个函数的解析便利功能,加载大量数据集。

  2. 只从匹配可表示为一个正则表达式的标准的所有行读出的数据:
    您可以使用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')

其结果是完全一样的第一种方法。



Answer 2:

如果您传递的类型(格式条件)的列表,使用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)或者类似的东西。



Answer 3:

想要证明注释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]]


文章来源: NumPy reading file with filtering lines on the fly