我想在python中导入一些ascii文件(来自tecplot,用于cfd后期处理的软件)。 这些文件的规则(至少是我需要导入的文件):
每个部分都有两行标题:
VARIABLES = "x" "y" "z" "ro" "rovx" "rovy" "rovz" "roE" "M" "p" "Pi" "tsta" "tgen"
ZONE T="Window(s) : E_W_Block0002_ALL", I=29, J=17, K=25, F=BLOCK
以下是数据示例:
VARIABLES = "x" "y" "z" "ro" "rovx" "rovy" "rovz" "roE" "M" "p" "Pi" "tsta" "tgen"
ZONE T="Window(s) : E_W_Block0002_ALL", I=29, J=17, K=25, F=BLOCK
-3.9999999E+00 -3.3327306E+00 -2.7760824E+00 -2.3117116E+00 -1.9243209E+00 -1.6011492E+00
[...]
0.0000000E+00 #fin first variable
-4.3532482E-02 -4.3584235E-02 -4.3627592E-02 -4.3663762E-02 -4.3693815E-02 -4.3718831E-02 #second variable, 'y'
[...]
1.0738781E-01 #end of second variable
[...]
[...]
VARIABLES = "x" "y" "z" "ro" "rovx" "rovy" "rovz" "roE" "M" "p" "Pi" "tsta" "tgen" #next zone
ZONE T="Window(s) : E_W_Block0003_ALL", I=17, J=17, K=25, F=BLOCK
我是python的新手,我编写了一个代码将数据导入字典,将变量写为3D numpy.array
。那些文件可能非常大,(高达Gb)。如何让这段代码更快? (或者更一般地说,如何尽可能快地导入这些文件)?
import re
from numpy import zeros, array, prod
def vectorr(I, J, K):
"""function"""
vect = []
for k in range(0, K):
for j in range(0, J):
for i in range(0, I):
vect.append([i, j, k])
return vect
a = open('E:\u.dat')
filelist = a.readlines()
NumberCol = 6
count = 0
data = dict()
leng = len(filelist)
countzone = 0
while count < leng:
strVARIABLES = re.findall('VARIABLES', filelist[count])
variables = re.findall(r'"(.*?)"', filelist[count])
countzone = countzone+1
data[countzone] = {key:[] for key in variables}
count = count+1
strI = re.findall('I=....', filelist[count])
strI = re.findall('\d+', strI[0])
I = int(strI[0])
##
strJ = re.findall('J=....', filelist[count])
strJ = re.findall('\d+', strJ[0])
J = int(strJ[0])
##
strK = re.findall('K=....', filelist[count])
strK = re.findall('\d+', strK[0])
K = int(strK[0])
data[countzone]['indmax'] = array([I, J, K])
pr = prod(data[countzone]['indmax'])
lin = pr // NumberCol
if pr%NumberCol != 0:
lin = lin+1
vect = vectorr(I, J, K)
for key in variables:
init = zeros((I, J, K))
for ii in range(0, lin):
count = count+1
temp = map(float, filelist[count].split())
for iii in range(0, len(temp)):
init.itemset(tuple(vect[ii*6+iii]), temp[iii])
data[countzone][key] = init
count = count+1
聚苯乙烯。在python中,没有cython或其他语言
答案 0 :(得分:2)
将大量字符串转换为数字总是会有点慢,但假设三重嵌套for循环是这里的瓶颈,可能会将其更改为以下内容,为您提供足够的加速:
# add this line to your imports
from numpy import fromstring
# replace the nested for-loop with:
count += 1
for key in variables:
str_vector = ' '.join(filelist[count:count+lin])
ar = fromstring(str_vector, sep=' ')
ar = ar.reshape((I, J, K), order='F')
data[countzone][key] = ar
count += lin
不幸的是,目前我只能访问我的智能手机(没有电脑)所以我无法测试它的速度有多快,甚至它是否正常工作或者根本无法测试!
<强>更新强>
最后我开始做一些测试:
ndarray.itemset
上,可能会进行循环开销和浮点转换。不幸的是,cProfile没有详细说明这一点.. numpy.fromstring
中花费了大约70%的时间,在我看来,这表明这种方法对于使用Python / NumPy可以实现的速度来说相当快。 更新2
当然,更好的方法是迭代文件,而不是一次性加载所有内容。在这种情况下,这稍微快一些(我尝试过)并显着减少内存使用。您还可以尝试使用多个CPU内核来执行加载和转换到浮点数,但是很难将所有数据都放在一个变量下。最后一句警告:我使用的fromstring
方法与字符串的长度相比较差。例如。从某个字符串长度来看,使用像np.fromiter(itertools.imap(float, str_vector.split()), dtype=float)
这样的东西会更有效率。
答案 1 :(得分:0)
如果你在这里使用正则表达式,我会改变两件事:
编译更频繁使用的RE(我猜这适用于您示例中的所有RE)。对regex=re.compile("<pattern>")
执行match=regex.match()
,并将结果对象与regex.group(1)
一起使用,如the Python documentation中所述。
对于I,J,K RE,考虑通过搜索“I =(\ d +)”形式的模式,使用分组功能(也如上所述)将两个RE减少为1,并且使用string.find()
抓取括号内匹配的部分。更进一步,您可以定义单个正则表达式,一步捕获所有三个变量。
至少在开始这些部分时,RE看起来有点矫枉过正:你需要寻找的字符串没有变化,{{1}}就足够了,在这种情况下可能更快。
编辑:我刚看到你已经为变量使用分组......