使用NumPy读取大型格式化文本文件

Tim*_*Tim 6 numpy python-2.7

我自愿帮助某人将有限元网格从一种格式转换为另一种格式(i-deas*.unv到Alberta).我已经使用NumPy对网格进行了一些额外的修改,但是我在将原始文本文件数据读入NumPy数组时遇到了问题.到目前为止,我已经尝试过genfromtxt和loadtxt但没有成功.

一些细节:

1)所有组由它自己的行上的页眉和页脚标志"-1"分隔.

2)NODE组在其自己的行上有一个标题"2411".我只想从这个组中读取备用行,用4个整数跳过每一行,但是用3个Fortran双精度数读取该行.

3)ELEMENT连接组在其自己的行上有一个标题"2412".所有数据都是整数,只需要读取前4列.由于缺少2和3节点元素的值,NumPy阵列中将有一些空插槽.

4)"2477"节点组我认为我可以使用正则表达式处理自己,找到要读取的行.

5)真正的数据文件将有大约100万行文本,所以我非常希望它尽可能地被矢量化(或者NumPy快速读取的东西).

对不起,如果我提供了太多信息,谢谢.

以下行是*.unv文本文件格式的部分示例.

    -1
  2411
  146303         1         1        11
  6.9849462399269246D-001  8.0008842847097805D-002  6.6360238055630028D-001
  146304         1         1        11
  4.1854795755893875D-001  9.1256034628308313D-001  3.5725496189239300D-002
  146305         1         1        11
  7.5541258490349616D-001  3.7870257739063029D-001  2.0504544370783115D-001
  146306         1         1        11
  2.7637569971086767D-001  9.2829777518336010D-001  1.3757239038663285D-001
   -1
   -1
 2412
     9        21         1         0         7         2
     0         0         0
     1         9
    10        21         1         0         7         2
     0         0         0
     9        10
  1550        91         6         0         7         3
   761      3685      2027
  1551        91         6         0         7         3
   761      2380      2067
 39720       111         1         0         7         4
 71854     59536     40323     73014
 39721       111         1         0         7         4
 45520     48908    133818    145014
   -1
   -1
   2477
     1         0         0         0         0         0         0      3022
PERMANENT GROUP1
     7         2         0         0         7         3         0         0
     7         8         0         0         7         7         0         0
     7       147         0         0         7       148         0         0
     2         0         0         0         0         0         0      2915
PERMANENT GROUP2
     7         1         0         0         7         5         0         0
     7         4         0         0         7         6         0         0
     7         9         0         0         7        11         0         0
   -1
Run Code Online (Sandbox Code Playgroud)

Bál*_*adi 5

该numpy的方法genfromtxtloadtxt将是相当难以适用于整个文件,为您的数据具有相当特殊的结构(其中的变化取决于在哪一个节点你)。因此,我建议采用以下策略:

  • 逐行读取文件,尝试通过分析该行来确定您在哪个节点。

  • 如果您在一个只有少量数据的节点中(例如,您必须读取交替的行,因此无法连续读取),请逐行读取并处理这些行。

  • 当您到达包含大量数据的部分(例如包含“真实数据”的部分)时,使用 numpys fromfile 方法读取数据,如下所示:

    mydata = np.fromfile(fp, sep=" ", dtype=int, count=number_of_elements)
    mydata.shape = (100000, 3)    # Reshape it to the desired shape as fromfile
                                  # returns a 1D array.
    
    Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以将逐行处理的灵活性与快速读取和转换大量数据的能力结合起来。

更新:关键是,你打开文件,一行一行地读取它,当你到达一个有大量数据的地方时,你将文件描述符传递给 fromfile。

下面是一个简化的例子:

import numpy as np

fp = open("test.dat", "r")
line = fp.readline()
ndata = int(line.strip())
data = np.fromfile(fp, count=ndata, sep=" ", dtype=int)
fp.close()
Run Code Online (Sandbox Code Playgroud)

这将从test.dat内容如下的文件中读取数据:

10
1 2 3 4 5
6 7 8 9 10
Run Code Online (Sandbox Code Playgroud)

第一行被显式读取fp.read(),处理(确定要读取的整数数量),然后np.fromfile()读取适当的数据块并将其存储在 1D-array 中data

UPDATE2:或者,您可以将整个文本读入缓冲区,然后确定大块数据的开始和结束位置并通过np.fromstring直接转换:

fp = open("test.dat", "r")
txt = fp.read()
fp.close()
# Now determine starting and end positions (startpos, endpos)
# ..
# pass text that portion of the text to the fromstring function.
data = np.fromstring(txt[startpos:endpos], dtype=int, sep=" ")
Run Code Online (Sandbox Code Playgroud)

或者,如果很容易形成一个正则表达式,您可以fromregex()直接在文件上使用。