2014-09-24 64 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.]]