在Python中逐块读取、切片和重新构造数据文件
Fortran程序生成的文本文件包含需要重新格式化的“块”数据(Python脚本) 此文件中的每个“数据块”对应于块开头指定的“时间”。所有“块”都有固定的大小和结构 我需要从对应于每个“时间”的不同“深度”(0、-1和-2)的“头部”和“湿度”列中提取数据:” 注意:开头的标题不是重复数据“块”的一部分 示例输入文件:在Python中逐块读取、切片和重新构造数据文件,python,text,format,block,Python,Text,Format,Block,Fortran程序生成的文本文件包含需要重新格式化的“块”数据(Python脚本) 此文件中的每个“数据块”对应于块开头指定的“时间”。所有“块”都有固定的大小和结构 我需要从对应于每个“时间”的不同“深度”(0、-1和-2)的“头部”和“湿度”列中提取数据:” 注意:开头的标题不是重复数据“块”的一部分 示例输入文件: ******* Program Simulation ******* This is initial header information for Simulation
******* Program Simulation
*******
This is initial header information for Simulation
Date: 1. 6. Time: 15: 3:39
Units: L = cm , T = min , M = mmol
Time: 0.0000
Node Depth Head Moisture K
[L] [L] [-] [L/T]
1 0.0000 -37.743 0.0630 0.5090E-05
2 -1.0000 -36.123 0.0750 0.5090E-05
3 -2.0000 -33.002 0.0830 0.5090E-05
end
Time: 360.0000
Node Depth Head Moisture K
[L] [L] [-] [L/T]
1 0.0000 -0.1000E+07 0.0450 0.1941E-32
2 -1.0000 -253.971 0.0457 0.4376E-10
3 -2.0000 -64.510 0.0525 0.2264E-06
end
Time: 720.0000
Node Depth Head Moisture K
[L] [L] [-] [L/T]
1 0.0000 -0.1000E+07 0.0550 0.1941E-32
2 -1.0000 -282.591 0.0456 0.2613E-10
3 -2.0000 -71.829 0.0513 0.1229E-06
end
所需输出:
Time Head(Depth=0) Head(Depth=-1) Head(Depth=-2) Moisture(Depth=0) Moisture(Depth=-1) Moisture(Depth=-2)
0.0000 -37.743 -36.123 -33.002 0.0630 0.0750 0.0830
360.0000 -0.1000E+07 -253.971 -64.510 0.0450 0.0457 0.0525
720.0000 -0.1000E+07 -282.591 -71.829 0.0550 0.0456 0.0513
如何从每个“时间:”到“结束”关键字逐块读取输入文件,并将其重新格式化为所需的输出?如果文件不太大,可以执行以下操作:
f = open('somefile')
file = f.read()
blocks = file.split('Time:')[1:]
以下是解析部分:
import re
data = []
with open(xxxx) as f:
for line in f:
m = re.match(r'^\s+Time:\s+([\d.]+)', line)
if m:
data.append([float(m.group(1))])
elif re.match(r'^\s+\d+', line):
data[-1].append(map(float, line.strip().split()))
产生:
[[0.0,
[1.0, 0.0, -37.743, 0.063, 5.09e-06],
[2.0, -1.0, -36.123, 0.075, 5.09e-06],
[3.0, -2.0, -33.002, 0.083, 5.09e-06]],
[360.0,
[1.0, 0.0, -1000000.0, 0.045, 1.941e-33],
[2.0, -1.0, -253.971, 0.0457, 4.376e-11],
[3.0, -2.0, -64.51, 0.0525, 2.264e-07]],
[720.0,
[1.0, 0.0, -1000000.0, 0.055, 1.941e-33],
[2.0, -1.0, -282.591, 0.0456, 2.613e-11],
[3.0, -2.0, -71.829, 0.0513, 1.229e-07]]]
从这里打印所需的表格应该很容易。编辑:我做了一些更改,所以它实际上可以运行
输入文件的大小很大。如何将每个块重新构造为所需的输出格式。此输出(重新格式化的纯文本)是您真正想要/需要的,还是首选更结构化的文本(xml、JSON)或数据对象(numpy.array、列表列表、字典)?重新格式化的纯文本或CSV应该可以。我将把它加载到Excel中进行进一步分析。您应该注意Excel如何解释/重新格式化科学记数法中的数字,因为它有时可能无法正常工作。@heltonbiker谢谢您的提示。如果excel无法正确导入,我将在编写输出文件之前使用Python重新格式化科学记数法。@akashwani我认为在进行ETL样式的工作时,我们不需要复杂的结构,只要保持结构尽可能简单,然后加载它们(可能使用C)。我正在调试您的代码。行
time=float(块[1].split()[1])
给出了此错误索引器:字符串索引超出范围。有什么想法吗@休-bothwell@akashwani:是的,我的错误:我想用一个文件迭代器返回十行列表,而实际上我写的东西返回了一个十行列表,然后对每行进行操作。我已经做了一个快速修复,现在正在寻找一个更好的(更Pythonic的)版本。@akashwani:我创建了一个BlockReader类,它按照我最初的意图运行,返回输入文件的十行块。希望这有帮助!谢谢,我正在使用你的代码。它肯定更像是蟒蛇,结构也很好。再次感谢!
from itertools import chain
def get_lines(f, n=1):
return [f.next() for i in xrange(n)]
class BlockReader(object):
def __init__(self, f, n=1):
self.f = f
self.n = n
def __iter__(self):
return self
def next(self):
return [self.f.next() for i in xrange(self.n)]
fmt = "{:<12}" + "{:<16}"*6 + "\n"
cols = [
"Time",
"Head(Depth=0)",
"Head(Depth=-1)",
"Head(Depth=-2)",
"Moisture(Depth=0)",
"Moisture(Depth=-1)",
"Moisture(Depth=-2)"
]
def main():
with open("simulation.txt") as inf, open("result.txt","w") as outf:
# throw away input header
get_lines(inf, 5)
# write output header
outf.write(fmt.format(*cols))
# read input file in ten-line chunks
for block in BlockReader(inf, 10):
# grab time value
time = float(block[1].split()[1])
# grab head and moisture columns
data = (line.split()[2:4] for line in block[6:9])
values = (map(float,dat) for dat in data)
h,m = zip(*values)
# write data to output file
outf.write(fmt.format(*chain([time],h,m)))
if __name__=="__main__":
main()
Time Head(Depth=0) Head(Depth=-1) Head(Depth=-2) Moisture(Depth=0)Moisture(Depth=-1)Moisture(Depth=-2)
0.0 -37.743 -36.123 -33.002 0.063 0.075 0.083
360.0 -1000000.0 -253.971 -64.51 0.045 0.0457 0.0525
720.0 -1000000.0 -282.591 -71.829 0.055 0.0456 0.0513