2014-09-24 101 views
2

我有一个文件,我只需要将某些值读入数组。该文件按指定TIMESTEP值的行进行划分。我需要文件中最高TIMESTEP之后的部分数据。使用numpy.genfromtxt进行过滤

这些文件将包含超过200,000行,尽管我不知道哪一行是我需要的部分开始的任何给定的文件,我不知道最大的TIMESTEP值是多少。

我假设如果我能找到最大的TIMESTEP的行号,那么我可以从该行开始导入。所有这些TIMESTEP行都以空格字符开头。关于我如何进行的任何想法都会有所帮助。

示例文件

headerline 1 to skip 
headerline 2 to skip 
headerline 3 to skip 
TIMESTEP = 0.00000000  
0, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
1, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
2, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
2, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
TIMESTEP = 0.119999997  
0, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
1, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
2, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
3, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
TIMESTEP = 3.00000000  
0, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
1, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
1, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 
2, 1.0, 1.0, 1.0, 1.0,  1.0, 1.0 

Basic代码

import numpy as np 

with open('myfile.txt') as f_in: 
    data = np.genfromtxt(f_in, skip_header=3, comments=" ") 
+0

我会使用常规的Python文件读取找到正确的TIMESTEP块。 – hpaulj 2014-09-24 05:27:06

+0

你甚至可能不需要'genfromtxt'从所需的行提取数据。或者将它们加载到一个'StringIO'缓冲区中,然后运行'genfromtxt'。 – hpaulj 2014-09-24 07:18:52

+0

感谢提示@hpaulj。我会给你一个镜头。如果你想提供一个非常棒的基本例子。 :) – Carl 2014-09-24 08:35:58

回答

1

你可以做的是使用自定义iterator

这里是一个工作示例:

从numpy的进口genfromtxt

class Iter(object): 
    ' a custom iterator which returns a timestep and corresponding data ' 

    def __init__(self, fd): 
     self.__fd = fd 
     self.__timestep = None 
     self.__next_timestep = None 
     self.__finish = False 
     for _ in self.to_next_timestep(): pass # skip header 

    def to_next_timestep(self): 
     ' iterate until next timestep ' 
     for line in self.__fd: 
      if 'TIMESTEP' in line: 
       self.__timestep = self.__next_timestep 
       self.__next_timestep = float(line.split('=')[1]) 
       return 
      yield line 
     self.__timestep = self.__next_timestep 
     self.__finish = True 

    def __iter__(self): return self 

    def next(self): 
     if self.__finish: 
      raise StopIteration 
     data = genfromtxt(self.to_next_timestep(), delimiter=',') 
     return self.__timestep, data 

with open('myfile.txt') as fd: 
    iter = Iter(fd) 
    for timestep, data in iter: 
     print timestep, data # data can be selected upon highest timestep 
+0

我得到一个错误,它不会在最后一节中读取: UserWarning:genfromtxt:空输入文件:“<生成器对象to_next_timestep在0x107bdd050>” 警告。warn('genfromtxt:空输入文件:'%s''%fname) – Carl 2014-09-25 02:37:32

+0

这不是一个错误,它是一个警告:)最后一节应该读得很好。你可以很容易地看到警告,看到https://docs.python.org/2/library/warnings.html – 2014-09-25 09:07:57

+0

对不起,“警告”不是“错误”。如果我按照迭代的方式输出'timestep'值,它会返回第二个'timestep'值两次,虽然'data'是正确的。 0.0 0.119999997 0.119999997 – Carl 2014-09-25 09:16:37

2

您可以精确地使用filter()同时使用genfromtxt(),因为genfromtxt接受发电机。

with open('myfile.txt', 'rb') as f_in: 
    lines = filter(lambda x: not x.startswith(b' '), f_in) 
    data = genfromtxt(lines, delimiter=',') 

然后在你的情况下,你不需要skip_header

+0

谢谢!这样可以导入大量的数据,但我真正需要的是在TIMESTEP行之后的数据部分,其值最高。在这种情况下,TIMESTEP = 3.00000000之后的部分理想情况下不需要多次迭代整个文件。 – Carl 2014-09-24 10:10:43

+0

好的抱歉,我没有得到你的问题。我会发表另一个答案。 – 2014-09-24 12:31:03

0

下面是一个使用常规的Python文件读取,将genfromtxt到行列表的解决方案。为了便于说明,我正在解析每个数据块,但可以轻松修改它以跳过不符合时间步长标准的块。

我第一次写到StringIO,正如许多genfromtxt doc示例中使用的那样,但它只需要一个迭代器即可。所以一行的清单工作得很好。

import numpy as np 
filename = 'stack26008436.txt' 

def parse(tstep, block): 
    print tstep 
    print np.genfromtxt(block, delimiter=',') 

with open(filename) as f: 
    block = [] 
    for line in f: 
     if 'TIMESTEP' in line: 
      if block: 
       parse(tstep, block) 
      block = [] 
      tstep = float(line.strip().split('=')[1]) 
     else: 
      if 'header' not in line: 
       block.append(line) 
    parse(tstep, block) 

从样品生产:

0901:~/mypy$ python2.7 stack26008436.py 
0.0 
[[ 0. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1.] 
... 
[ 3. 1. 1. 1. 1. 1. 1.]] 
3.0 
[[ 0. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1.] 
[ 1. 1. 1. 1. 1. 1. 1.] 
[ 2. 1. 1. 1. 1. 1. 1.]]