2016-02-12 48 views
2

我有一個由'數據塊'組成的文件,其中頭文件指出文件中有多少個塊以及每個塊中有多少行。如何使用numpy讀取文件的不同部分或塊

# mydata.dat 
3 12343 2 
# comment 
12343 
1 2 3 4 5 6 7 8 
1 2 3 4 5 6 7 8 
12343 
1 2 3 4 5 6 7 8 
1 2 3 4 5 6 7 8 
12343 
1 2 3 4 5 6 7 8 
1 2 3 4 5 6 7 8 

我想單獨存儲每個塊。我所做的是通過分割行來生成每個塊的列表,然後將其轉換爲數組以存儲在字典中。

import numpy as np 

with open('mydata.dat', "r") as f: 
    lines = f. readlines() 
    blocks, _, n = map(int, lines[1].split()) 
    del lines[:3] 
data = {i: np.array(dtype=float, 
        object=[line.split() 
          for line in lines[i * n + 1: n * (i + 1)]]) 
     for i in xrange(blocks)} 

我覺得應該有一個更好的(更「有效」)的方式來直接解析文本塊中的數據,像np.loadtxt在那裏你可以跳過行的定期量(如切片),並不僅僅是從文件開始。

回答

1

loadtxt不會爲每個塊做什麼 - 讀取每一行,將其拆分,根據dtype將其轉換並附加到列表中,最後將其轉換爲數組。

在其他問題中已經指出,您可以傳遞打開的文件或任何可迭代到loadtxt。因此,您可以對文件進行預處理,將其分成塊,跳過線條等。但總體而言,它不會比您所做的更有效率。

所以這可能工作(我沒有測試過):

data = {i: np.loadtxt(lines[i * n + 1: n * (i + 1)], dtype=float) 
    for i in xrange(blocks)} 

這是更緊湊,但我懷疑它是速度更快。

我能想到的唯一的另一種方法是去掉所有的塊大小行,將剩餘的塊傳遞給loadtxt以獲得所有數據的數組,然後將其分割成塊,例如,與np.split(...)

隨着txt如從樣本的行列表:

In [396]: timeit np.array([line.split() for line in txt[4:6]],dtype=float) 
100000 loops, best of 3: 13 µs per loop 
In [397]: timeit np.loadtxt(txt[4:6],dtype=float) 
10000 loops, best of 3: 71.4 µs per loop 
+0

謝謝,已經嘗試過他們,他們的工作。儘管如此,手工分割和使用'np.array'似乎比'np.loadtxt'或'np.split'更快,你知道這是爲什麼嗎? – izxle

+0

較少的開銷?正如我試圖描述的那樣,'loadtxt'對編譯代碼沒有什麼特別之處。 'pandas'有一個更快的'csv'加載器。 – hpaulj

0

np.loadtxt可以採取任何可迭代作爲參數,和鋼帶的空格來獲得的數據陣列。

下面的代碼給出了np.loadtxt一個可產生完整塊的迭代,而不是行。

import numpy as np 
from itertools import islice 

def chunks(iterable, blocks_count, block_size): 
    for i in range(blocks_count): 
     yield "".join(islice(iterable, block_size)) 

with open(r'c:\tmp\tmp.txt', "r") as f: 
    file_iterator = iter(f) 
    next(file_iterator) # skip first comment line 
    blocks, _, n = map(int, next(file_iterator).split()) 
    next(file_iterator) # skip second comment line 
    blocks_iterator = chunks(file_iterator, blocks, n) 
    data = dict() 
    i = 0 
    for arr in np.loadtxt(dtype=float, fname=blocks_iterator): 
     data[i] = arr 
     i += 1 
+0

很整潔,不知道loadtxt可以讀取迭代。我認爲你忘了每個塊的'header',因爲你的代碼在np.loadtxt(dtype = float,fname = blocks_iterator)中返回arr的大於等於16的值:''... ValueError:錯誤的數值第2行的列' – izxle

+0

通過將其修改爲'yield「」.join(islice(iterable,block_size + 1))'來修復它。但它運行速度較慢,也是更多的代碼。 – izxle

1

np.loadtxt()可以採取迭代,所以你可以通過它的line 片數據的第一行是2行

with open('mydata.dat', "r") as f: 
    # load data, skipping comment lines 
    line = [s for s in f if not s.startswith('#')] 

    # parse first line to find out block size 
    _, _, blocksize = map(int, line[0].split()) 

    # use np.loadtxt() to convert slices of the input 
    data = [np.loadtxt(line[i:i+blocksize]) 
      for i in range(2, len(line), blocksize+1)] 

你可以跳過使用第一個文件加載到一個字符串itertools.islice

with open('mydata.dat', "r") as f: 
    # iterator over lines in f with comment lines removed 
    lines = (line for line in f if not line.startswith('#')) 

    # parse block structure 
    nblks, _, blksz = map(int, next(lines).split()) 

    # convert "islice"s of the input file to np.arrays 
    # start arg to islice is 1 to skip over block header line 
    data = [np.loadtxt(it.islice(lines, 1, blksz + 1)) for i in range(nblks)] 
相關問題